Browse Source

device connect

zzf 1 năm trước cách đây
mục cha
commit
6bdd953262

+ 0 - 2
.gitignore

@@ -12,5 +12,3 @@
 # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
 hs_err_pid*
 
-/megablelibopen/build/
-/.gradle/

BIN
.gradle/5.6.4/fileContent/fileContent.lock


BIN
.gradle/5.6.4/fileHashes/resourceHashesCache.bin


BIN
.gradle/5.6.4/javaCompile/jarAnalysis.bin


BIN
.gradle/5.6.4/javaCompile/taskHistory.bin


BIN
.gradle/buildOutputCleanup/outputFiles.bin


+ 1 - 0
sample/build.gradle

@@ -43,4 +43,5 @@ dependencies {
     implementation 'javax.validation:validation-api:2.0.1.Final'
     // https://mvnrepository.com/artifact/org.java-websocket/Java-WebSocket
     implementation 'org.java-websocket:Java-WebSocket:1.5.3'
+    implementation 'com.github.hijesse:android-logger:2.5.0'
 }

+ 2 - 0
sample/src/main/AndroidManifest.xml

@@ -21,6 +21,8 @@
     <uses-permission android:name="android.permission.INTERNET"/>
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
 
     <application
         android:name=".App"

+ 43 - 3
sample/src/main/java/com/yanzhenjie/andserver/sample/MainActivity.java

@@ -15,10 +15,15 @@
  */
 package com.yanzhenjie.andserver.sample;
 
+import android.Manifest;
+import android.app.PendingIntent;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothManager;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.location.Location;
+import android.location.LocationManager;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
@@ -30,9 +35,12 @@ import android.widget.TextView;
 import androidx.annotation.RequiresApi;
 import androidx.appcompat.app.AppCompatActivity;
 import androidx.appcompat.widget.Toolbar;
+import androidx.core.app.ActivityCompat;
+import androidx.core.content.ContextCompat;
 
 import com.yanzhenjie.andserver.sample.util.Constant;
 import com.yanzhenjie.andserver.sample.util.HostUtil;
+import com.yanzhenjie.andserver.sample.util.UtilsSharedPreference;
 import com.yanzhenjie.andserver.sample.websocket.SocketServer;
 import com.yanzhenjie.loading.dialog.LoadingDialog;
 
@@ -40,6 +48,8 @@ import java.net.InetSocketAddress;
 import java.util.LinkedList;
 import java.util.List;
 
+import javax.validation.ConstraintDeclarationException;
+
 /**
  * Created by Zhenjie Yan on 2018/6/9.
  */
@@ -55,7 +65,11 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
     private LoadingDialog mDialog;
     private String mRootUrl;
     public static BluetoothAdapter mBluetoothAdapter;
-    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
+    SocketServer socketServer;
+
+    public static Context context;
+
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -71,26 +85,52 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
         mBtnStart.setOnClickListener(this);
         mBtnStop.setOnClickListener(this);
         mBtnBrowser.setOnClickListener(this);
-
+        //open gps
+        openGPS(this);
         // AndServer run in the service.
         mServerManager = new ServerManager(this);
         mServerManager.register();
         BluetoothManager bluetoothManager = (BluetoothManager) this.getSystemService(Context.BLUETOOTH_SERVICE);
         mBluetoothAdapter = bluetoothManager.getAdapter();
+        context = this.getApplicationContext();
         new Thread(() -> {
             String address = HostUtil.getHostIp();
             InetSocketAddress inetSocketAddress = new InetSocketAddress(address, Constant.WEB_SOCKET_PORT);
-            SocketServer socketServer = new SocketServer(inetSocketAddress);
+            socketServer = new SocketServer(inetSocketAddress);
             socketServer.run();
         }).start();
         // startServer;
         mBtnStart.performClick();
     }
 
+    /**
+     * 强制帮用户打开GPS
+     * @param context
+     */
+    public static final void openGPS(Context context) {
+        Intent GPSIntent = new Intent();
+        GPSIntent.setClassName("com.android.settings",
+                "com.android.settings.widget.SettingsAppWidgetProvider");
+        GPSIntent.addCategory("android.intent.category.ALTERNATIVE");
+        GPSIntent.setData(Uri.parse("custom:3"));
+        try {
+            PendingIntent.getBroadcast(context, 0, GPSIntent, 0).send();
+        } catch (PendingIntent.CanceledException e) {
+            e.printStackTrace();
+        }
+    }
+
     @Override
     protected void onDestroy() {
         super.onDestroy();
         mServerManager.unRegister();
+        if(socketServer != null ) {
+            try {
+                socketServer.stop();
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+        }
     }
 
     @Override

+ 200 - 31
sample/src/main/java/com/yanzhenjie/andserver/sample/controller/CommonController.java

@@ -1,5 +1,6 @@
 package com.yanzhenjie.andserver.sample.controller;
 
+import android.annotation.SuppressLint;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.le.BluetoothLeScanner;
 import android.os.Build;
@@ -16,10 +17,13 @@ import com.yanzhenjie.andserver.annotation.RestController;
 import com.yanzhenjie.andserver.sample.MainActivity;
 import com.yanzhenjie.andserver.sample.model.ScannedDevice;
 import com.yanzhenjie.andserver.sample.util.Constant;
+import com.yanzhenjie.andserver.sample.util.FileUtils;
 import com.yanzhenjie.andserver.sample.util.Result;
+import com.yanzhenjie.andserver.sample.util.UtilsSharedPreference;
 import com.yanzhenjie.andserver.util.MediaType;
 
 import org.apache.commons.lang3.StringUtils;
+import org.slf4j.helpers.NOPLogger;
 
 import java.util.Collection;
 import java.util.HashMap;
@@ -28,30 +32,40 @@ import java.util.concurrent.atomic.AtomicBoolean;
 
 import javax.validation.Valid;
 
+import cn.jesse.nativelogger.NLogger;
 import io.mega.megablelib.MegaAdvParse;
 import io.mega.megablelib.MegaBleBuilder;
 import io.mega.megablelib.MegaBleCallback;
 import io.mega.megablelib.MegaBleClient;
+import io.mega.megablelib.MegaBleConst;
+import io.mega.megablelib.enums.MegaBleBattery;
 import io.mega.megablelib.model.MegaBleDevice;
 import io.mega.megablelib.model.bean.MegaAdvOnly;
 import io.mega.megablelib.model.bean.MegaAdvertisingParsedEntity;
+import io.mega.megablelib.model.bean.MegaBleHeartBeat;
+import io.mega.megablelib.model.bean.MegaV2LiveSpoLive;
+import io.mega.megablelib.model.bean.MegaV2LiveSpoMonitor;
+import io.mega.megablelib.model.bean.MegaV2Mode;
 import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
 
 // Created by Develoven on 2023/4/23.
 // Copyright (c) 2023 redflow. All rights reserved.
 //
-@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
 @RestController
 @RequestMapping("/common")
 public class CommonController extends BaseController{
 
     private static final String TAG = "CommonController";
-    private final Long  SCAN_PERIOD = 5L;
+    private final Long  SCAN_PERIOD = 10L;
 
     private static BluetoothAdapter mBluetoothAdapter;
     private static BluetoothLeScanner mScanner = null;
     //    private static BluetoothAdapter.LeScanCallback mLeScanCallback ;
-    private static HashMap<String,ScannedDevice> scannedDeviceList = new HashMap<>();
+    private static HashMap<String,Object> scannedDeviceList = new HashMap<>();
+
+    private String fileName;
+    MegaBleClient megaBleClient ;
     static {
 //        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
         mBluetoothAdapter = MainActivity.mBluetoothAdapter;
@@ -71,7 +85,7 @@ public class CommonController extends BaseController{
      */
     @GetMapping(value = "/open/bluetooth",produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
     public Result openBluetooth(){
-
+        Log.d(TAG, fileName == null?"fileName == null":fileName);
         //1.open bluetooth
         if (mBluetoothAdapter == null) {
             Log.e(TAG, "--------------- current device not support bluetooth ");
@@ -87,6 +101,7 @@ public class CommonController extends BaseController{
             Log.e(TAG, "--------------- bluetooth open success");
             return fail(null,"bluetooth open success");
         }
+
         return success(null,"bluetooth open success");
 
     }
@@ -133,44 +148,73 @@ public class CommonController extends BaseController{
      * model = PULSE|ECG
      * @return
      */
-    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
+    @SuppressLint("CheckResult")
     @GetMapping(value = "/scan/device/{model}",produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
-    public Result<Collection<ScannedDevice>> scanDevice(@PathVariable("model") String model) throws InterruptedException {
+    public Result scanDevice(@PathVariable("model") String model) throws InterruptedException {
+        Log.d(TAG, fileName == null?"fileName == null":fileName);
         AtomicBoolean scanStatus = new AtomicBoolean(true);
         BluetoothAdapter.LeScanCallback mLeScanCallback = (device, rssi, scanRecord) -> {
             try{
+
                 Log.d(TAG+"LeScan","device:{"+device.getName()+"  "+rssi+"   "+scanRecord);
                 if(StringUtils.isEmpty(device.getName())) {
                     return;
                 }
-                if (!device.getName().toLowerCase().contains("ring")) return;
-                if(scanRecord.length < 62) return;
-                // parse 3rd ring
-                MegaAdvOnly advOnly = MegaAdvParse.parse(scanRecord);
-                //parse 2nd ring
-                if(advOnly == null){
-                    MegaAdvertisingParsedEntity advEntity = MegaBleClient.parseScanRecord(device, scanRecord);
-                    if(advEntity != null){
-                        Log.d(TAG,advEntity.toString());
+                if(model.equals(Constant.MODEL_PULSE)){
+                    if (!device.getName().toLowerCase().contains("ring")) return;
+                    if(scanRecord.length < 62) return;
+                    // parse 3rd ring
+                    MegaAdvOnly advOnly = MegaAdvParse.parse(scanRecord);
+                    //parse 2nd ring
+                    if(advOnly == null){
+                        MegaAdvertisingParsedEntity advEntity = MegaBleClient.parseScanRecord(device, scanRecord);
+                        if(advEntity != null){
+                            Log.d(TAG,advEntity.toString());
+                        }
+                    }else {
+                        Log.d(TAG,advOnly.toString());
                     }
-                }else {
-                    Log.d(TAG,advOnly.toString());
-                }
-                ScannedDevice scannedDevice = new ScannedDevice(device.getName(), device.getAddress(), rssi);
-                Log.d(TAG, "device: "+scannedDevice);
+                    ScannedDevice scannedDevice = new ScannedDevice(device.getName(), device.getAddress(), rssi);
+                    Log.d(TAG, "device: "+scannedDevice);
                 /*int index = scannedDeviceList.indexOf(scannedDevice);
                 if(index == -1){
                     scannedDeviceList.add(scannedDevice);
                 }else {
                     scannedDeviceList.add(index,scannedDevice);
                 }*/
-                scannedDeviceList.put(scannedDevice.getAddress(),scannedDevice);
+                    scannedDeviceList.put(scannedDevice.getAddress(),scannedDevice);
+                }else if(model.equals(Constant.MODEL_ECG)){
+                    if (!device.getName().toLowerCase().contains("bw-ecg")) return;
+                    scannedDeviceList.put(device.getAddress(),device.getAddress());
+                }
+
             }catch (Exception e ){
                 Log.d(TAG,e.getMessage());
                 e.printStackTrace();
             }
         };
-        switch (model){
+        Log.d(TAG,"model="+model);
+        //scan PULSE device
+        Log.d(TAG,"size---"+scannedDeviceList.size());
+        if(scannedDeviceList.size()>0){
+            scannedDeviceList.clear();
+        }
+        Log.d(TAG,"size---"+scannedDeviceList.size());
+        //scan ecg device
+        Observable.timer(SCAN_PERIOD,TimeUnit.SECONDS).subscribe( aLong -> {
+            mBluetoothAdapter.stopLeScan(mLeScanCallback);
+            scanStatus.set(false);
+            Log.d(TAG,"scannedDeviceList.size---"+scannedDeviceList.size());
+        });
+        Log.d(TAG,"mLeScanCallback---"+mLeScanCallback);
+        Log.d(TAG,"mBluetoothAdapter---"+mBluetoothAdapter);
+        Log.i(TAG,"开始扫描");
+        mBluetoothAdapter.startLeScan(mLeScanCallback);
+        Observable.interval(1,TimeUnit.SECONDS).take(SCAN_PERIOD).observeOn(AndroidSchedulers.mainThread()).subscribe(aLong ->{
+            Log.d(TAG,aLong.toString()+"scanning...");
+
+        });
+        /*switch (model){
 
             case Constant.MODEL_ECG:
 
@@ -193,16 +237,18 @@ public class CommonController extends BaseController{
                 Log.d(TAG,"mBluetoothAdapter---"+mBluetoothAdapter);
                 Log.i(TAG,"开始扫描");
                 mBluetoothAdapter.startLeScan(mLeScanCallback);
-/*                Observable.interval(1,TimeUnit.SECONDS).take(SCAN_PERIOD).observeOn(AndroidSchedulers.mainThread()).subscribe(aLong ->{
+                Observable.interval(1,TimeUnit.SECONDS).take(SCAN_PERIOD).observeOn(AndroidSchedulers.mainThread()).subscribe(aLong ->{
                     Log.d(TAG,aLong.toString()+"scanning...");
 
-                });*/
+                });
                 break;
-        }
+        }*/
         while (scanStatus.get()){
             Thread.sleep(1000);
+            Log.d(TAG, scanStatus+"---"+System.currentTimeMillis()+"----");
             Log.i(TAG,"等待");
         }
+
         return success(scannedDeviceList.values());
     }
 
@@ -210,29 +256,152 @@ public class CommonController extends BaseController{
      * connect bluetooth
      * @return
      */
-    @PostMapping(value = "/connect/bluetooth",produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+    @PostMapping(value = "/connect/bluetooth/{model}",produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
     public Result connectBluetooth(@Valid @RequestParam(name = "mac") String mac,@Valid @RequestParam(name = "name") String name){
         Log.i(TAG,mac);
+        fileName = "测试文件名称";
         MegaBleCallback megaBleCallback = new MegaBleCallback() {
             @Override
             public void onConnectionStateChange(boolean connected, MegaBleDevice device) {
                 super.onConnectionStateChange(connected, device);
                 //状态变更 :通知前台服务
                 if(connected){
+                    Log.d(TAG, "已连接:"+device);
+                }else {
+                    Log.d(TAG, "断开连接");
+                }
+            }
+            @Override
+            public void onError(int code) {
+                NLogger.e(TAG,"error code :{}",code);
+            }
+
+            @Override
+            public void onStart() {
+                String userId = "5837288dc59e0d00577c5f9a";
+                String token = UtilsSharedPreference.get(MainActivity.context,UtilsSharedPreference.KEY_TOKEN);
+                if(StringUtils.isEmpty(token)){
+                    megaBleClient.startWithToken(userId, "0,0,0,0,0,0");
+                }else {
+                    megaBleClient.startWithToken(userId, token);
+                }
+            }
+
+            @Override
+            public void onDeviceInfoReceived(MegaBleDevice device) {
+                megaBleClient.getV2Batt();
+                megaBleClient.getV2Mode();
+                megaBleClient.enableV2ModeSpoMonitor(true);
+            }
+            @Override
+            public void onSetUserInfo() {
+                megaBleClient.setUserInfo((byte) 25, (byte) 1, (byte) 170, (byte) 60, (byte) 0);
+            }
+
+            @Override
+            public void onIdle() {
+                // 设备闲时,可开启实时、开启长时监控、收监控数据。
+                // 长时监控数据会被记录到戒指内部,实时数据不会。
+                // 长时监控开启后,可断开蓝牙连接,戒指将自动保存心率血氧数据,以便后续手机连上收取。默认每次连上会同步过来。
+                // 绑定token有变动时,用户信息,监测数据将被清空。
+                // 建议默认开启全局实时通道,无需关闭,重复开启无影响
+                // suggested setting, repeated call is ok.
+                Log.d(TAG, "Important: the remote device is idle.");
+                megaBleClient.toggleLive(true);
+            }
+
+            @Override
+            public void onV2LiveSpoLive(MegaV2LiveSpoLive live) {
 
+            }
+
+            @Override
+            public void onV2LiveSpoMonitor(MegaV2LiveSpoMonitor live) {
+               /* switch (live.getStatus()){
+                    case MegaBleConst.STATUS_LIVE_VALID:
+                        updateV2Live(live);
+                        break;
+                    case MegaBleConst.STATUS_LIVE_PREPARING
+                        updateV2Live(live);
+                    break;
+                    case MegaBleConst.STATUS_LIVE_INVALID
+                            updateV2Live(live);
+                    break;
+
+                }*/
+            }
+
+            //notice user to shaking ,in order to bind the ring
+            @Override
+            public void onKnockDevice() {
+
+            }
+
+            @Override
+            public void onTokenReceived(String token) {
+                UtilsSharedPreference.put(MainActivity.context, UtilsSharedPreference.KEY_TOKEN, token);
+            }
+
+            //notice UI modify rssi
+            @Override
+            public void onRssiReceived(int rssi) {
+
+            }
+
+            /**
+             * notify front to change battery value & battery status
+             *
+             * @param value 电池电量
+             * @param status 电池状态  normal(0, "normal"), charging(1, "charging"),full(2, "full"),lowPower(3, "lowPower");error(4, "error");shutdown(5, "shutdown");
+             */
+            @Override
+            public void onBatteryChanged(int value, int status) {
+//                MegaBleBattery.getDescription(status);
+            }
+
+            /**
+             * notify front active mode
+             * @param mode
+             */
+            @Override
+            public void onV2ModeReceived(MegaV2Mode mode) {
+
+            }
+
+            /**
+             * 心跳检测,检测到心跳就开启脉搏
+             * @param heartBeat
+             */
+            @Override
+            public void onHeartBeatReceived(MegaBleHeartBeat heartBeat) {
+
+            }
+
+            @Override
+            public void onRawdataParsed(int[][] a) {
+                if(a != null && a.length > 0){
+                    for (int[] ints : a) {
+                        FileUtils.addFile(MainActivity.context.getFilesDir().getPath() + "/脉诊'", String.valueOf(ints[0]));
+                    }
                 }
             }
         };
         // mock id, key,use yours
         MegaBleBuilder builder = new MegaBleBuilder();
-        MegaBleClient megaBleClient = builder
-                .withSecretId("D4CE5DD515F81247")
-                .withSecretKey("uedQ2MgVEFlsGIWSgofHYHNdZSyHmmJ5")
-                .withCallback(megaBleCallback)
-                .build();
+        try{
+            megaBleClient = builder
+                    .withSecretId("D4CE5DD515F81247")
+                    .withSecretKey("uedQ2MgVEFlsGIWSgofHYHNdZSyHmmJ5")
+                    .withContext(MainActivity.context)
+                    .withCallback(megaBleCallback)
+                    .build();
+        }catch (Exception e ){
+            e.printStackTrace();
+        }
         // 开发测试时,可以开启debug
         megaBleClient.setDebugEnable(true);
         megaBleClient.connect(mac, name);
+
         return success();
     }
 

+ 46 - 1
sample/src/main/java/com/yanzhenjie/andserver/sample/util/FileUtils.java

@@ -23,13 +23,15 @@ import com.yanzhenjie.andserver.http.multipart.MultipartFile;
 import com.yanzhenjie.andserver.sample.App;
 
 import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
 import java.util.UUID;
 
 /**
  * Created by Zhenjie Yan on 2018/6/9.
  */
 public class FileUtils {
-
+    static String storageState = null;
     /**
      * Create a random file based on mimeType.
      *
@@ -45,4 +47,47 @@ public class FileUtils {
         String uuid = UUID.randomUUID().toString();
         return new File(App.getInstance().getRootDir(), uuid + "." + extension);
     }
+
+    public static void addFile(String filePath, String requestUrlStr){
+        File file = null;
+        try {
+            // getExternalStorageState 方法频繁调用会影响性能
+            // 修改为只调用一次后解决卡顿问题,但无法及时获取状态变化,最好能做到对存储设备的状态变化的实时监听
+            if (storageState == null) {
+                storageState = Environment.getExternalStorageState();
+            }
+            if(storageState.equals(Environment.MEDIA_MOUNTED)){
+                file=new File(filePath);
+                if (!file.exists()){
+                    file.getParentFile().mkdirs();
+                    if (file.createNewFile()){
+                        writeAppend(filePath,requestUrlStr);
+                    }
+                }else {
+                    writeAppend(filePath,","+requestUrlStr);
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    public static void writeAppend(String fileName, String requestUrlStr){
+
+        FileWriter writer = null;
+        try {
+            writer = new FileWriter(fileName, true);
+            writer.write(requestUrlStr);
+        }catch (IOException e){
+            e.printStackTrace();
+        }finally {
+            try {
+                if(writer != null){
+                    writer.close();
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
 }