diff --git a/android/app/build.gradle b/android/app/build.gradle index 965934fd..05a2f8df 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -42,7 +42,7 @@ configurations.all { android { compileSdkVersion 33 - + buildToolsVersion "31.0.0" sourceSets { main.java.srcDirs += 'src/main/kotlin' } @@ -75,7 +75,7 @@ android { buildTypes { debug { debuggable true - signingConfig signingConfigs.release + signingConfig signingConfigs.debug } release { debuggable false @@ -102,6 +102,11 @@ android { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } + repositories { + flatDir { + dirs 'libs' + } + } } flutter { @@ -139,5 +144,12 @@ dependencies { implementation 'androidx.core:core-ktx:1.6.0' implementation 'androidx.appcompat:appcompat:1.3.1' androidTestImplementation "androidx.test:core:1.4.0" + + // Lepu Libraries + implementation 'no.nordicsemi.android:ble:2.2.4' + implementation(name: 'lepu-blepro-1.0.1', ext: 'aar') + implementation 'io.github.jeremyliao:live-event-bus-x:1.8.0' + implementation 'com.guolindev.permissionx:permissionx:1.7.1' + } diff --git a/android/app/libs/lepu-blepro-1.0.1.aar b/android/app/libs/lepu-blepro-1.0.1.aar new file mode 100644 index 00000000..1dcefd22 Binary files /dev/null and b/android/app/libs/lepu-blepro-1.0.1.aar differ diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/MainActivity.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/MainActivity.kt index 8aa1ef85..cd59f014 100644 --- a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/MainActivity.kt +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/MainActivity.kt @@ -1,4 +1,5 @@ package com.ejada.hmg + import android.app.NotificationChannel import android.app.NotificationManager import android.content.ContentResolver @@ -10,20 +11,23 @@ import android.os.Build import android.view.WindowManager import androidx.annotation.NonNull; import com.ejada.hmg.utils.* +import com.ejada.hmg.* import io.flutter.embedding.android.FlutterFragmentActivity import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodChannel import io.flutter.plugins.GeneratedPluginRegistrant +import com.lepu.blepro.observer.BleChangeObserver -class MainActivity: FlutterFragmentActivity() { +class MainActivity : FlutterFragmentActivity(), BleChangeObserver { override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { GeneratedPluginRegistrant.registerWith(flutterEngine); + + // Create Flutter Platform Bridge this.window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON or WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) - PlatformBridge(flutterEngine, this).create() OpenTokPlatformBridge(flutterEngine, this).create() - + BleBridge(flutterEngine, this).create() // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // val mChannel = NotificationChannel("video_call_noti", "video call", NotificationManager.IMPORTANCE_HIGH) // val soundUri = Uri.parse("android.resource://" + getApplicationContext() @@ -45,6 +49,13 @@ class MainActivity: FlutterFragmentActivity() { } + + override fun onBleStateChanged(model: Int, state: Int) { + //println( "model $model, state: $state") +// _bleState.value = state == Ble.State.CONNECTED +// Log.d(TAG, "bleState $bleState") + } + override fun onResume() { super.onResume() } diff --git a/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/ble/BleBridge.kt b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/ble/BleBridge.kt new file mode 100644 index 00000000..7d8e3aad --- /dev/null +++ b/android/app/src/main/kotlin/com/cloud/diplomaticquarterapp/ble/BleBridge.kt @@ -0,0 +1,182 @@ +package com.ejada.hmg.utils + +import android.content.Context +import android.content.Intent +import android.content.Intent.getIntent +import android.net.Uri +import android.os.Build +import android.os.Bundle +import android.provider.Settings +import android.widget.Toast +import androidx.core.app.ActivityCompat.startActivityForResult +import com.ejada.hmg.MainActivity +import io.flutter.embedding.engine.FlutterEngine +import io.flutter.plugin.common.MethodCall +import io.flutter.plugin.common.MethodChannel +import io.flutter.plugin.common.EventChannel +import android.util.SparseArray + + +//Ble +import com.jeremyliao.liveeventbus.LiveEventBus +import com.lepu.blepro.constants.Ble +import com.lepu.blepro.event.EventMsgConst +import com.lepu.blepro.event.EventMsgConst.Ble.* +import com.lepu.blepro.event.InterfaceEvent +import com.lepu.blepro.ext.BleServiceHelper +import com.lepu.blepro.ext.pc60fw.RtParam +import com.lepu.blepro.objs.Bluetooth +import com.lepu.blepro.objs.BluetoothController +import com.lepu.blepro.observer.BleChangeObserver +import io.flutter.plugin.common.EventChannel.EventSink +import no.nordicsemi.android.ble.observer.ConnectionObserver + +class BleBridge( + private var flutterEngine: FlutterEngine, private var mainActivity: MainActivity +) { + + private lateinit var channel: MethodChannel + private lateinit var Echannel: EventChannel + private var eventSink: EventChannel.EventSink? = null + + companion object { + private const val CHANNEL = "BLE-Platform-Bridge" + private const val EVENTCHANNEL = "BLE-Platform-Bridge-Event" + private const val SCAN_DEVICE = "scan" + } + + + private val models = intArrayOf( + Bluetooth.MODEL_PC60FW, Bluetooth.MODEL_PC_60NW, Bluetooth.MODEL_PC_60NW_1, + Bluetooth.MODEL_PC66B, Bluetooth.MODEL_PF_10, Bluetooth.MODEL_PF_20, + Bluetooth.MODEL_OXYSMART, Bluetooth.MODEL_POD2B, + Bluetooth.MODEL_POD_1W, Bluetooth.MODEL_S5W, + Bluetooth.MODEL_PF_10AW, Bluetooth.MODEL_PF_10AW1, + Bluetooth.MODEL_PF_10BW, Bluetooth.MODEL_PF_10BW1, + Bluetooth.MODEL_PF_20AW, Bluetooth.MODEL_PF_20B, + Bluetooth.MODEL_S7W, Bluetooth.MODEL_S7BW, + Bluetooth.MODEL_S6W, Bluetooth.MODEL_S6W1, + Bluetooth.MODEL_PC60NW_BLE, Bluetooth.MODEL_PC60NW_WPS, + Bluetooth.MODEL_PC_60NW_NO_SN, // Pc60fwActivity + Bluetooth.MODEL_O2RING, Bluetooth.MODEL_O2M, + Bluetooth.MODEL_BABYO2, Bluetooth.MODEL_BABYO2N, + Bluetooth.MODEL_CHECKO2, Bluetooth.MODEL_SLEEPO2, + Bluetooth.MODEL_SNOREO2, Bluetooth.MODEL_WEARO2, + Bluetooth.MODEL_SLEEPU, Bluetooth.MODEL_OXYLINK, + Bluetooth.MODEL_KIDSO2, Bluetooth.MODEL_OXYFIT, + Bluetooth.MODEL_OXYRING, Bluetooth.MODEL_BBSM_S1, + Bluetooth.MODEL_BBSM_S2, Bluetooth.MODEL_OXYU, + Bluetooth.MODEL_AI_S100, Bluetooth.MODEL_O2M_WPS, + Bluetooth.MODEL_CMRING, Bluetooth.MODEL_OXYFIT_WPS, + Bluetooth.MODEL_KIDSO2_WPS, Bluetooth.MODEL_SI_PO6, // OxyActivity + Bluetooth.MODEL_PC80B, Bluetooth.MODEL_PC80B_BLE, + Bluetooth.MODEL_PC80B_BLE2, // Pc80bActivity + Bluetooth.MODEL_PC100, // Pc102Activity + Bluetooth.MODEL_AP20, Bluetooth.MODEL_AP20_WPS, // Ap20Activity + Bluetooth.MODEL_PC_68B, // Pc68bActivity + Bluetooth.MODEL_PULSEBITEX, Bluetooth.MODEL_HHM4, // PulsebitExActivity + Bluetooth.MODEL_CHECKME_LE, // CheckmeLeActivity + Bluetooth.MODEL_PC300, Bluetooth.MODEL_PC300_BLE, + Bluetooth.MODEL_GM_300SNT, Bluetooth.MODEL_CMI_PC303, // Pc303Activity + Bluetooth.MODEL_CHECK_POD, Bluetooth.MODEL_CHECKME_POD_WPS, // CheckmePodActivity + Bluetooth.MODEL_AOJ20A, // Aoj20aActivity + Bluetooth.MODEL_SP20, Bluetooth.MODEL_SP20_BLE, Bluetooth.MODEL_SP20_WPS, // Sp20Activity + Bluetooth.MODEL_VETCORDER, Bluetooth.MODEL_CHECK_ADV, // CheckmeMonitorActivity + Bluetooth.MODEL_TV221U, // Vtm20fActivity + Bluetooth.MODEL_BPM, // BpmActivity + Bluetooth.MODEL_BIOLAND_BGM, // BiolandBgmActivity + Bluetooth.MODEL_POCTOR_M3102, // PoctorM3102Activity + Bluetooth.MODEL_LPM311, // Lpm311Activity + Bluetooth.MODEL_LEM, // LemActivity + Bluetooth.MODEL_ER1, Bluetooth.MODEL_ER1_N, Bluetooth.MODEL_HHM1, // Er1Activity + Bluetooth.MODEL_ER2, Bluetooth.MODEL_LP_ER2, Bluetooth.MODEL_DUOEK, + Bluetooth.MODEL_HHM2, Bluetooth.MODEL_HHM3, // Er2Activity + Bluetooth.MODEL_BP2, Bluetooth.MODEL_BP2A, Bluetooth.MODEL_BP2T, // Bp2Activity + Bluetooth.MODEL_BP2W, // Bp2wActivity + Bluetooth.MODEL_LP_BP2W, // LpBp2wActivity + Bluetooth.MODEL_ER3, // Er3Activity + Bluetooth.MODEL_LEPOD, // LepodActivity + Bluetooth.MODEL_ECN, // EcnActivity + Bluetooth.MODEL_R20, Bluetooth.MODEL_R21, + Bluetooth.MODEL_R10, Bluetooth.MODEL_R11, + Bluetooth.MODEL_LERES, // VentilatorActivity + Bluetooth.MODEL_FHR, // FhrActivity + Bluetooth.MODEL_VTM_AD5, Bluetooth.MODEL_FETAL, // Ad5Activity + Bluetooth.MODEL_VCOMIN, // VcominActivity + ) + + private var list = arrayListOf() + + fun create() { + channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL) + Echannel = EventChannel(flutterEngine.dartExecutor.binaryMessenger, EVENTCHANNEL) + channel.setMethodCallHandler { methodCall: MethodCall, result: MethodChannel.Result -> + + if (methodCall.method == SCAN_DEVICE) { + scanDevice(methodCall, result) + } else { + result.notImplemented() + } + } + Echannel.setStreamHandler(object : EventChannel.StreamHandler { + override fun onListen(arguments: Any?, eventSink: EventChannel.EventSink?) { + this@BleBridge.eventSink = eventSink + } + + override fun onCancel(arguments: Any?) { + } + }) + + + } + + fun scanDevice(methodCall: MethodCall, result: MethodChannel.Result) { + + println("This is Test of Scanning") + LiveEventBus.get(EventMsgConst.Ble.EventServiceConnectedAndInterfaceInit) + .observe(this.mainActivity) { + // BleService init success + println("EventServiceConnectedAndInterfaceInit---------") + BleServiceHelper.BleServiceHelper.startScan(models) + println("EventServiceConnectedAndInterfaceInit") + } + LiveEventBus.get(EventMsgConst.Discovery.EventDeviceFound) + .observe(this.mainActivity) { + var deviceName: String = "" + for (b in BluetoothController.getDevices()) { + // println(b.name) + if (b.name.contains("POD-1_SN8187", true)) { + deviceName = b.name + BleServiceHelper.BleServiceHelper.setInterfaces(b.model) + BleServiceHelper.BleServiceHelper.stopScan() + BleServiceHelper.BleServiceHelper.connect( + this.mainActivity.applicationContext, + b.model, + b.device + ) + } + } + + println("EventDeviceFound") + println(deviceName) + + LiveEventBus.get(InterfaceEvent.PC60Fw.EventPC60FwRtParam) + .observe(this.mainActivity) { + val data = it.data as RtParam + println("OXY DATA: $data") + eventSink?.success(data.toString()) + } + + + } + val rawFolders = SparseArray() + try { + BleServiceHelper.BleServiceHelper.initRawFolder(rawFolders) + .initService(this.mainActivity.application) + + } catch (e: Exception) { + println(e) + } + } + +} \ No newline at end of file diff --git a/android/build.gradle b/android/build.gradle index e723adba..4ee80e4c 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.7.20' + ext.kotlin_version = '1.8.20' repositories { google() jcenter() diff --git a/lib/pages/ble_screen.dart b/lib/pages/ble_screen.dart new file mode 100644 index 00000000..c0dc0fc4 --- /dev/null +++ b/lib/pages/ble_screen.dart @@ -0,0 +1,58 @@ +import 'package:diplomaticquarterapp/viatom_ble/ble_connect.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:photo_view/photo_view.dart'; + +class BLEScreen extends StatefulWidget { + @override + State createState() => _BLEScreenState(); +} + +class _BLEScreenState extends State { + String abc = ""; + EventChannel eventChannel = EventChannel('BLE-Platform-Bridge-Event'); + String recivedData = ''; + + @override + void initState() { + // TODO: implement initState + super.initState(); + eventChannel.receiveBroadcastStream().listen((event) { + // Handle the received event here. + print('Received event---: $event'); + + setState(() { + recivedData = event; + }); + // You can update your UI or perform any other actions based on the event. + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: SafeArea( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Center( + child: GestureDetector( + onTap: () async { + abc = await BleChannel.getScanningResult(); + }, + child: Container( + width: 50, + height: 50, + color: Colors.blueAccent, + ), + ), + ), + Center(child: Text(recivedData)) + ], + ), + ), + ); + } +} diff --git a/lib/routes.dart b/lib/routes.dart index 7df15030..a9e6555a 100644 --- a/lib/routes.dart +++ b/lib/routes.dart @@ -5,6 +5,7 @@ import 'package:diplomaticquarterapp/pages/DrawerPages/family/add-family_type.da import 'package:diplomaticquarterapp/pages/DrawerPages/family/my-family.dart'; import 'package:diplomaticquarterapp/pages/TestPage.dart'; import 'package:diplomaticquarterapp/pages/appUpdatePage/app_update_page.dart'; +import 'package:diplomaticquarterapp/pages/ble_screen.dart'; import 'package:diplomaticquarterapp/pages/landing/landing_page.dart'; import 'package:diplomaticquarterapp/pages/livecare/incoming_call.dart'; import 'package:diplomaticquarterapp/pages/livecare/livecare_home.dart'; @@ -54,6 +55,7 @@ const String OPENTOK_CALL_PAGE = 'OPENTOK_CALL_PAGE'; const String CART_ORDER_PAGE = 'cart-order-page'; const String CALL_PAGE = 'CALL_PAGE'; const String INCOMING_CALL_PAGE = 'INCOMING_CALL_PAGE'; +const String BLE_Page = 'BLE_PAGE'; const String HEALTH_WEATHER = 'health-weather'; const APP_UPDATE = 'app-update'; @@ -84,6 +86,7 @@ var routes = { CART_ORDER_PAGE: (_) => CartOrderPage(), // CALL_PAGE: (_) => CallPage(), INCOMING_CALL_PAGE: (_) => IncomingCall(), + BLE_Page: (_) => BLEScreen(), OPENTOK_CALL_PAGE: (_) => OpenTokConnectCallPage( apiKey: OPENTOK_API_KEY, sessionId: '1_MX40NjIwOTk2Mn5-MTY0NzE3MzcwNjA0MH55RUJoZnd0ZGh2U3BPc01ENVZBelQvT1Z-fg', diff --git a/lib/viatom_ble/ble_connect.dart b/lib/viatom_ble/ble_connect.dart new file mode 100644 index 00000000..f9fa96e3 --- /dev/null +++ b/lib/viatom_ble/ble_connect.dart @@ -0,0 +1,19 @@ +import 'package:flutter/services.dart'; + +class BleChannel { + static const platform = MethodChannel('BLE-Platform-Bridge'); + + +//BLE-Platform-Bridge + static Future getScanningResult() async { + try { + print("----------Flutter Init -------"); + final String result = await platform.invokeMethod('scan'); + print("----------Flutter Result -------"); + print(result); + return result; + } catch (e) { + return "Error: $e"; + } + } +}