Browse Source

ble service will

zhaoyadi 8 months ago
parent
commit
9e8397764b

+ 4 - 2
.idea/codeStyles/Project.xml

@@ -1,6 +1,7 @@
 <component name="ProjectCodeStyleConfiguration">
   <code_scheme name="Project" version="173">
     <JetCodeStyleSettings>
+      <option name="WRAP_EXPRESSION_BODY_FUNCTIONS" value="2" />
       <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
     </JetCodeStyleSettings>
     <codeStyleSettings language="Dart">
@@ -138,11 +139,12 @@
     </codeStyleSettings>
     <codeStyleSettings language="kotlin">
       <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
-      <option name="RIGHT_MARGIN" value="160" />
-      <option name="KEEP_LINE_BREAKS" value="false" />
+      <option name="RIGHT_MARGIN" value="100" />
       <option name="KEEP_FIRST_COLUMN_COMMENT" value="false" />
       <option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
       <option name="ALIGN_MULTILINE_PARAMETERS_IN_CALLS" value="true" />
+      <option name="METHOD_CALL_CHAIN_WRAP" value="5" />
+      <option name="ASSIGNMENT_WRAP" value="0" />
     </codeStyleSettings>
   </code_scheme>
 </component>

+ 0 - 2
xiaodou/build.gradle

@@ -54,9 +54,7 @@ dependencies {
     implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
 
     implementation 'androidx.appcompat:appcompat:1.5.1'
-    implementation "androidx.bluetooth:bluetooth:1.0.0-alpha02"
     implementation 'com.google.android.material:material:1.10.0'
     implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
-    implementation 'com.guolindev.permissionx:permissionx:1.8.0'
     implementation 'commons-codec:commons-codec:1.17.1'
 }

+ 3 - 0
xiaodou/src/main/AndroidManifest.xml

@@ -23,6 +23,8 @@
     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
 
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
+    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE" />
+    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
 
     <uses-feature
         android:name="android.hardware.bluetooth"
@@ -42,6 +44,7 @@
 
         <service
             android:name=".XDScanBLEService"
+            android:exported="false"
             android:foregroundServiceType="connectedDevice" />
     </application>
 

+ 5 - 42
xiaodou/src/main/java/com/luojigou/xiaodou/XDScanBLEActivity.kt

@@ -4,19 +4,13 @@ import android.Manifest
 import android.bluetooth.BluetoothAdapter
 import android.bluetooth.BluetoothManager
 import android.content.BroadcastReceiver
-import android.content.ComponentName
 import android.content.Context
 import android.content.Intent
 import android.content.IntentFilter
-import android.content.ServiceConnection
 import android.content.pm.PackageManager
 import android.os.Build
 import android.os.Bundle
-import android.os.IBinder
-import android.util.Log
 import androidx.appcompat.app.AppCompatActivity
-import androidx.bluetooth.BluetoothDevice
-import androidx.bluetooth.BluetoothLe
 import androidx.core.app.ActivityCompat
 import androidx.fragment.app.Fragment
 import com.luojigou.xiaodou.ble.XDScanBLEDisableFragment
@@ -51,8 +45,6 @@ class XDScanBLEActivity : AppCompatActivity(), XDScanBLEStatus.Host {
         getSystemService(BLUETOOTH_SERVICE) as BluetoothManager
     }
 
-    private var bluetoothBinder: XDScanBLEService.XDScanBLEBinder? = null
-
     private val broadcastReceiver by lazy {
         object : BroadcastReceiver() {
             override fun onReceive(context: Context?, intent: Intent?) {
@@ -64,55 +56,27 @@ class XDScanBLEActivity : AppCompatActivity(), XDScanBLEStatus.Host {
                 }
 
                 when (currentState) {
-                    BluetoothAdapter.STATE_OFF -> { // 蓝牙已关闭
+                    BluetoothAdapter.STATE_OFF -> {
                         checkBluetoothPermissionAndEnable()
-                        Log.d("BLEStateBroadcastReceiver", "onReceive: Bluetooth is off")
                     }
 
-                    BluetoothAdapter.STATE_ON -> { // 蓝牙已打开
+                    BluetoothAdapter.STATE_ON -> {
                         checkBluetoothPermissionAndEnable()
-                        Log.d("BLEStateBroadcastReceiver", "onReceive: Bluetooth is on")
-                    }
-
-                    BluetoothAdapter.STATE_TURNING_OFF -> { // 蓝牙正在关闭
-                        Log.d("BLEStateBroadcastReceiver", "onReceive: Bluetooth is turning off")
-                    }
-
-                    BluetoothAdapter.STATE_TURNING_ON -> { // 蓝牙正在打开
-                        Log.d("BLEStateBroadcastReceiver", "onReceive: Bluetooth is turning on")
                     }
                 }
             }
         }
     }
 
-    private val bleConnection = object : ServiceConnection {
-        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
-            bluetoothBinder = service as XDScanBLEService.XDScanBLEBinder?
-            checkBluetoothPermissionAndEnable()
-        }
-
-        override fun onServiceDisconnected(name: ComponentName?) {
-            bluetoothBinder = null
-        }
-
-    }
-
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         setContentView(R.layout.activity_scanble)
-
-        val intent = Intent(this, XDScanBLEService::class.java)
-        startService(intent)
-        bindService(intent, bleConnection, 0)
     }
 
     override fun onResume() {
         super.onResume()
         registerReceiver(broadcastReceiver, IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED))
-        if(bluetoothBinder != null){
-            checkBluetoothPermissionAndEnable()
-        }
+        checkBluetoothPermissionAndEnable()
     }
 
     override fun onPause() {
@@ -158,7 +122,6 @@ class XDScanBLEActivity : AppCompatActivity(), XDScanBLEStatus.Host {
         beginTransaction.commit()
     }
 
-    override fun onStatusChanged(status: XDScanBLEStatus) = checkBluetoothPermissionAndEnable()
-
-    override fun getManager(): XDScanBLEStatus.Manager  = bluetoothBinder ?: throw IllegalStateException("蓝牙不存在")
+    override fun onStatusChanged(status: XDScanBLEStatus) =
+        checkBluetoothPermissionAndEnable()
 }

+ 167 - 62
xiaodou/src/main/java/com/luojigou/xiaodou/XDScanBLEService.kt

@@ -2,31 +2,26 @@ package com.luojigou.xiaodou
 
 import android.annotation.SuppressLint
 import android.app.Service
+import android.bluetooth.BluetoothAdapter
+import android.bluetooth.BluetoothDevice
+import android.bluetooth.BluetoothManager
+import android.bluetooth.le.ScanCallback
+import android.bluetooth.le.ScanFilter
+import android.bluetooth.le.ScanResult
+import android.bluetooth.le.ScanSettings
+import android.content.BroadcastReceiver
+import android.content.ComponentName
+import android.content.Context
 import android.content.Intent
-import android.os.Binder
+import android.content.IntentFilter
 import android.os.IBinder
-import android.util.ArraySet
 import android.util.Log
-import androidx.bluetooth.BluetoothDevice
-import androidx.bluetooth.BluetoothLe
-import androidx.bluetooth.ScanFilter
-import androidx.bluetooth.ScanResult
-import com.luojigou.xiaodou.ble.XDBLEConnectStatus
-import com.luojigou.xiaodou.ble.XDBLEUtils
+import androidx.core.app.NotificationChannelCompat
+import androidx.core.app.NotificationCompat
+import androidx.core.app.NotificationManagerCompat
 import com.luojigou.xiaodou.ble.XDScanBLEDevice
-import com.luojigou.xiaodou.ble.XDScanBLEStatus
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.SupervisorJob
-import kotlinx.coroutines.currentCoroutineContext
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.onCompletion
-import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.flow.onStart
-import kotlinx.coroutines.withContext
 import java.util.UUID
+import kotlin.concurrent.thread
 
 
 @SuppressLint("MissingPermission")
@@ -35,9 +30,10 @@ class XDScanBLEService : Service() {
         const val ACTION_START_SCAN = "com.luojigou.xiaodou.ble.ACTION_START_SCAN"
         const val ACTION_STOP_SCAN = "com.luojigou.xiaodou.ble.ACTION_STOP_SCAN"
 
+        const val ACTION_SCAN_RESULT = "com.luojigou.xiaodou.ble.ACTION_SCAN_RESULT"
+        const val ACTION_SCAN_RESULT_DATA = "com.luojigou.xiaodou.ble.ACTION_SCAN_RESULT_DATA"
+
         const val ACTION_CONNECT_WIFI = "com.luojigou.xiaodou.ble.ACTION_CONNECT_WIFI"
-        const val ACTION_CONNECT_WIFI_RESULT = "com.luojigou.xiaodou.ble.ACTION_CONNECT_WIFI_RESULT"
-        const val ACTION_CONNECT_WIFI_RESULT_DATA = "com.luojigou.xiaodou.ble.ACTION_CONNECT_WIFI_RESULT_DATA"
         const val ACTION_CONNECT_WIFI_RESULT_ERROR = "com.luojigou.xiaodou.ble.ACTION_CONNECT_WIFI_RESULT_ERROR"
         const val ACTION_CONNECT_WIFI_RESULT_SUCCESS = "com.luojigou.xiaodou.ble.ACTION_CONNECT_WIFI_RESULT_SUCCESS"
         const val ACTION_CONNECT_WIFI_RESULT_FAILED = "com.luojigou.xiaodou.ble.ACTION_CONNECT_WIFI_RESULT_FAILED"
@@ -45,63 +41,172 @@ class XDScanBLEService : Service() {
         private val wifiConnectServiceUUID = UUID.fromString("0000ae80-0000-1000-8000-00805f9b34fb")
         private val wifiConnectWriteUUID = UUID.fromString("0000ae81-0000-1000-8000-00805f9b34fb")
         private val wifiConnectNotifyUUID = UUID.fromString("0000ae82-0000-1000-8000-00805f9b34fb")
-        private val filter: List<ScanFilter> = listOf(ScanFilter())
+
+        private val bleChannelName = "BLE-CHANNEL"
     }
 
-    private val bluetoothLe: BluetoothLe by lazy { BluetoothLe(this) }
+    private val deviceMap: MutableMap<XDScanBLEDevice, BluetoothDevice> = HashMap()
+
+    private lateinit var bluetoothManager: BluetoothManager
+
+    private lateinit var bluetoothAdapter: BluetoothAdapter
+
+    private lateinit var bluetoothReceiver: BroadcastReceiver
+
+    @Volatile
+    private var bleScanning = false
+
+    private val bleScanSettings = ScanSettings.Builder()
+        .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
+        .build()
 
-    private val deviceSet: MutableSet<XDScanBLEDevice> = ArraySet()
+    private val bleScanFilters = mutableListOf<ScanFilter>()
 
-    private val deviceListFlow = MutableStateFlow<List<XDScanBLEDevice>>(listOf())
+    private val bleScanCallback = object : ScanCallback() {
+        override fun onScanResult(callbackType: Int, result: ScanResult) {
+            super.onScanResult(callbackType, result)
+            val oldSize = deviceMap.size
+            addDevice(result)
+            val newSize = deviceMap.size
+
+            if (oldSize != newSize) {
+                sendResult()
+            }
+        }
+
+        override fun onBatchScanResults(results: MutableList<ScanResult>) {
+            super.onBatchScanResults(results)
+            val oldSize = deviceMap.size
+            results.forEach { addDevice(it) }
+            val newSize = deviceMap.size
+
+            if (oldSize != newSize) {
+                sendResult()
+            }
+
+        }
+
+        override fun onScanFailed(errorCode: Int) {
+            super.onScanFailed(errorCode)
+            Log.d("XDScanBLEService", "onScanFailed: $errorCode")
+        }
+
+        private fun addDevice(result: ScanResult) {
+            result.apply {
+                if (device.name == null) return
+
+                val device = XDScanBLEDevice(
+                    name = device.name ?: "unknown",
+                    bondState = device.bondState.toString(),
+                    rssi = rssi.toString(),
+                    address = device.address,
+                    addressType = device.type.toString(),
+                )
+
+                if (!deviceMap.contains(device)) {
+                    deviceMap[device] = result.device
+                }
+            }
+
+        }
+    }
 
-    private val connectStatus = MutableStateFlow<XDBLEConnectStatus>(XDBLEConnectStatus.Waiting)
     override fun onCreate() {
         super.onCreate()
+        goForeground()
+        initBluetooth()
     }
 
-    override fun onBind(intent: Intent?): IBinder {
-        return XDScanBLEBinder(this)
-    }
+    private fun goForeground() {
+        val manager = NotificationManagerCompat.from(this)
+        val notificationChannel = NotificationChannelCompat.Builder(
+            bleChannelName, NotificationManagerCompat.IMPORTANCE_LOW
+        ).setName("蓝牙扫描通知").setDescription("用于蓝牙扫描硬件设备并配网处理").build()
+
+        if (manager.areNotificationsEnabled()) {
+            if (manager.getNotificationChannel(bleChannelName) == null) {
+                manager.createNotificationChannel(notificationChannel)
+            }
 
-    class XDScanBLEBinder(private val service: XDScanBLEService) : Binder(), XDScanBLEStatus.Manager {
-        override suspend fun scanBle(): Flow<ScanResult> {
-            return service.bluetoothLe.scan(filter)
+            val notification = NotificationCompat.Builder(this, bleChannelName)
+                .setContentTitle("XiaoDou")
+                .setContentText("XiaoDou is running")
+                .setSmallIcon(android.R.drawable.stat_sys_data_bluetooth)
+                .setChannelId(bleChannelName)
+                .build()
+
+            startForeground(1, notification)
         }
+    }
+
+    private fun initBluetooth() {
+        bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
+        bluetoothAdapter = bluetoothManager.adapter
 
-        override suspend fun connectWifi(device: BluetoothDevice, ssid: String, password: String): Unit = withContext(Dispatchers.IO) {
-            service.connectStatus.emit(XDBLEConnectStatus.Connecting(device))
-            service.bluetoothLe.connectGatt(device) {
-                val connection = this
-
-                val bleService = this.getService(wifiConnectServiceUUID)
-                if (bleService != null) {
-                    service.connectStatus.emit(XDBLEConnectStatus.Connected(device))
-
-                    val write = bleService.getCharacteristic(wifiConnectWriteUUID)
-                    val notify = bleService.getCharacteristic(wifiConnectNotifyUUID)
-
-                    if (notify != null) {
-                        connection
-                            .subscribeToCharacteristic(notify)
-                            .onStart { Log.d("XDScanBLEBinder", "subscribeToCharacteristic: ") }
-                            .onEach { XDBLEUtils.parseConnectResponse(it) }
-                            .onCompletion { Log.d("XDScanBLEBinder", "onCompletion: ") }
-                            .launchIn(CoroutineScope(currentCoroutineContext()))
+        bluetoothReceiver = object : BroadcastReceiver() {
+            override fun onReceive(context: Context?, intent: Intent) {
+                when (intent.action) {
+                    ACTION_START_SCAN -> {
+                        startScan()
                     }
 
-                    if (write != null) {
-                        val request = XDBLEUtils.convertToConnectRequest(ssid, password)
-                        val result = connection.writeCharacteristic(write, request)
-                        if (result.isSuccess) {
-                            Log.d("XDScanBLEBinder", "connectWifi: success")
-                        } else {
-                            Log.d("XDScanBLEBinder", "connectWifi: failed")
-                        }
+                    ACTION_STOP_SCAN -> {
+                        stopScan()
                     }
-                } else {
-                    service.connectStatus.emit(XDBLEConnectStatus.Failed(device, "蓝牙无服务"))
                 }
             }
         }
+
+        val intentFilter = IntentFilter()
+        intentFilter.addAction(ACTION_START_SCAN)
+        intentFilter.addAction(ACTION_STOP_SCAN)
+        registerReceiver(bluetoothReceiver, intentFilter, Context.RECEIVER_NOT_EXPORTED)
+
+        startScan()
+    }
+
+    override fun onBind(intent: Intent?): IBinder? {
+        return null
+    }
+
+    private fun startScan() {
+        if (!bleScanning) {
+            bleScanning = true
+            bluetoothAdapter.bluetoothLeScanner.startScan(
+                bleScanFilters, bleScanSettings, bleScanCallback
+            )
+        }
+        //        delayClose()
+    }
+
+    private fun delayClose() {
+        thread {
+            Thread.sleep(5000)
+            if (bleScanning) {
+                stopScan()
+            }
+        }
+    }
+
+    private fun stopScan() {
+        if (bleScanning) {
+            bleScanning = false
+            bluetoothAdapter.bluetoothLeScanner.stopScan(bleScanCallback)
+        }
+    }
+
+    private fun sendResult() {
+        val intent = Intent(ACTION_SCAN_RESULT)
+        intent.putParcelableArrayListExtra(
+            ACTION_SCAN_RESULT_DATA, ArrayList(deviceMap.keys)
+        )
+        sendBroadcast(intent)
+    }
+
+    override fun onDestroy() {
+        unregisterReceiver(bluetoothReceiver)
+        stopScan()
+        super.onDestroy()
+        Log.d("XDScanBLEService", "onDestroy: service destroyed")
     }
 }

+ 5 - 7
xiaodou/src/main/java/com/luojigou/xiaodou/ble/XDBLEConnectStatus.kt

@@ -1,12 +1,10 @@
 package com.luojigou.xiaodou.ble
 
-import androidx.bluetooth.BluetoothDevice
-
 sealed class XDBLEConnectStatus() {
     object Waiting : XDBLEConnectStatus()
-    data class Connecting(val device: BluetoothDevice) : XDBLEConnectStatus()
-    data class Connected(val device: BluetoothDevice) : XDBLEConnectStatus()
-    data class Disconnected(val device: BluetoothDevice) : XDBLEConnectStatus()
-    data class Unknown(val device: BluetoothDevice) : XDBLEConnectStatus()
-    data class Failed(val device: BluetoothDevice, val reason: String) : XDBLEConnectStatus()
+    object Connecting : XDBLEConnectStatus()
+    object Connected : XDBLEConnectStatus()
+    object Disconnected : XDBLEConnectStatus()
+    object Unknown : XDBLEConnectStatus()
+    object Failure : XDBLEConnectStatus()
 }

+ 0 - 1
xiaodou/src/main/java/com/luojigou/xiaodou/ble/XDScanBLEAdapter.kt

@@ -29,7 +29,6 @@ class XDScanBLEAdapter(
         val item = list.elementAt(position)
 
         holder.apply {
-            id.text = item.id
             name.text = item.name
             bondState.text = item.bondState
             rssi.text = item.rssi

+ 43 - 7
xiaodou/src/main/java/com/luojigou/xiaodou/ble/XDScanBLEDevice.kt

@@ -1,23 +1,59 @@
 package com.luojigou.xiaodou.ble
 
-import androidx.bluetooth.BluetoothDevice
+import android.os.Parcel
+import android.os.Parcelable
+import java.util.Objects
 
 data class XDScanBLEDevice(
-    val id: String,
     val name: String,
-    val bondState: String,
     val rssi: String,
+    val bondState: String,
     val address: String,
     val addressType: String,
-    val device: BluetoothDevice,
-) {
+) : Parcelable {
+
+    // Parcelable Creator
+    companion object {
+        @JvmField
+        val CREATOR: Parcelable.Creator<XDScanBLEDevice> = object :
+            Parcelable.Creator<XDScanBLEDevice> {
+            override fun createFromParcel(source: Parcel): XDScanBLEDevice {
+                return XDScanBLEDevice(
+                    source.readString()!!,
+                    source.readString()!!,
+                    source.readString()!!,
+                    source.readString()!!,
+                    source.readString()!!
+                )
+            }
+
+            override fun newArray(size: Int): Array<XDScanBLEDevice?> {
+                return arrayOfNulls(size)
+            }
+        }
+    }
+
+    // 实现 writeToParcel 方法
+    override fun writeToParcel(dest: Parcel, flags: Int) {
+        dest.writeString(name)
+        dest.writeString(rssi)
+        dest.writeString(bondState)
+        dest.writeString(address)
+        dest.writeString(addressType)
+    }
+
+    // 实现 describeContents 方法(通常返回0)
+    override fun describeContents(): Int {
+        return 0
+    }
+
     override fun hashCode(): Int {
-        return address.hashCode()
+        return Objects.hash(address, addressType)
     }
 
     override fun equals(other: Any?): Boolean {
         return if (other is XDScanBLEDevice) {
-            address == other.address
+            address == other.address && addressType == other.addressType
         } else {
             false
         }

+ 62 - 48
xiaodou/src/main/java/com/luojigou/xiaodou/ble/XDScanBLENormalFragment.kt

@@ -1,8 +1,11 @@
 package com.luojigou.xiaodou.ble
 
 import android.annotation.SuppressLint
+import android.content.BroadcastReceiver
+import android.content.ComponentName
 import android.content.Context
 import android.content.Intent
+import android.content.IntentFilter
 import android.os.Bundle
 import android.view.LayoutInflater
 import android.view.View
@@ -10,30 +13,29 @@ import android.view.ViewGroup
 import android.widget.Button
 import androidx.activity.result.ActivityResultLauncher
 import androidx.activity.result.contract.ActivityResultContracts
-import androidx.bluetooth.ScanFilter
 import androidx.fragment.app.Fragment
 import androidx.recyclerview.widget.GridLayoutManager
 import androidx.recyclerview.widget.RecyclerView
 import com.luojigou.xiaodou.R
+import com.luojigou.xiaodou.XDScanBLEActivity
+import com.luojigou.xiaodou.XDScanBLEService
+import com.luojigou.xiaodou.XDScanBLEService.Companion.ACTION_SCAN_RESULT
+import com.luojigou.xiaodou.XDScanBLEService.Companion.ACTION_SCAN_RESULT_DATA
 import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.MainScope
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
 
 @SuppressLint("MissingPermission")
-class XDScanBLENormalFragment(private val host: XDScanBLEStatus.Host) : Fragment(), CoroutineScope by MainScope() {
+class XDScanBLENormalFragment(private val host: XDScanBLEStatus.Host) : Fragment(),
+    CoroutineScope by MainScope() {
     private val adapter = XDScanBLEAdapter {
-        launch {
-            host.getManager().connectWifi(it.device, "zdzh", "zdzh00000")
-        }
+        //        launch {
+        //            host.getManager().connectWifi(it.device, "zdzh", "zdzh00000")
+        //        }
     }
 
-    private val scanFilter = listOf<ScanFilter>(
-    )
-
     private lateinit var selectWifi: ActivityResultLauncher<Intent>
 
+    private lateinit var bluetoothReceiver: BroadcastReceiver
     override fun onCreateView(
         inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
     ): View? {
@@ -48,7 +50,7 @@ class XDScanBLENormalFragment(private val host: XDScanBLEStatus.Host) : Fragment
         }
 
         val button = view.findViewById<Button>(R.id.scan_again)
-        button.setOnClickListener { scanBle() }
+        button.setOnClickListener { restartScan() }
 
         val recyclerView = view.findViewById<RecyclerView>(R.id.scan_list)
         val layoutManager = GridLayoutManager(requireContext(), 2, RecyclerView.VERTICAL, false)
@@ -59,52 +61,64 @@ class XDScanBLENormalFragment(private val host: XDScanBLEStatus.Host) : Fragment
 
     override fun onAttach(context: Context) {
         super.onAttach(context)
-        scanBle()
+        startService()
     }
 
-    private fun scanBle() {
-        adapter.setValues(mutableListOf())
-
-        launch {
-            host.getManager().scanBle().collect {
-                val device = it.device
-                val rssi = it.rssi
-                val serviceUuids = it.serviceUuids
-                val deviceAddress = it.deviceAddress
-                val periodicAdvertisingInterval = it.periodicAdvertisingInterval
-                val timestampNanos = it.timestampNanos
-                val serviceData = it.serviceData
-
-                val id = device.id
-                val bondState = device.bondState
-                val name = device.name
-
-                val address = deviceAddress.address
-                val addressType = deviceAddress.addressType
-
-                //                Log.d("XDScanBLENormalFragment", "onAttach: ")
-
-                if (name != null) {
-                    withContext(Dispatchers.Main) {
-                        adapter.addValue(
-                            XDScanBLEDevice(
-                                id = id.toString(),
-                                name = name.toString(),
-                                bondState = bondState.toString(),
-                                rssi = rssi.toString(),
-                                address = address,
-                                addressType = addressType.toString(),
-                                device = device,
-                            )
+    private fun startService() {
+        bluetoothReceiver = object : BroadcastReceiver() {
+            override fun onReceive(context: Context?, intent: Intent) {
+                when (intent.action) {
+                    ACTION_SCAN_RESULT -> {
+                        val list = intent.getParcelableArrayListExtra(
+                            ACTION_SCAN_RESULT_DATA, XDScanBLEDevice::class.java
                         )
+
+                        if (list != null) {
+                            setAdapterValue(list)
+                        }
                     }
                 }
             }
         }
+
+        val intentFilter = IntentFilter()
+        intentFilter.addAction(ACTION_SCAN_RESULT)
+        requireContext().registerReceiver(
+            bluetoothReceiver,
+            intentFilter,
+            Context.RECEIVER_NOT_EXPORTED
+        )
+
+        requireContext().startForegroundService(
+            Intent(
+                requireContext(), XDScanBLEService::class.java
+            )
+        )
+    }
+
+    private fun stopService() {
+        requireContext().stopService(
+            Intent(
+                requireContext(), XDScanBLEService::class.java
+            )
+        )
+    }
+
+    private fun restartScan() {
+        setAdapterValue(listOf())
+        requireActivity().sendBroadcast(
+            Intent(
+                XDScanBLEService.ACTION_START_SCAN
+            )
+        )
+    }
+
+    private fun setAdapterValue(list: List<XDScanBLEDevice>) {
+        adapter.setValues(list)
     }
 
     override fun onDetach() {
-        adapter.setValues(mutableListOf())
+        stopService()
         super.onDetach()
     }
 }

+ 0 - 11
xiaodou/src/main/java/com/luojigou/xiaodou/ble/XDScanBLEStatus.kt

@@ -1,9 +1,5 @@
 package com.luojigou.xiaodou.ble
 
-import androidx.bluetooth.BluetoothDevice
-import androidx.bluetooth.ScanResult
-import kotlinx.coroutines.flow.Flow
-
 sealed class XDScanBLEStatus {
     object Disabled : XDScanBLEStatus()
     object Permission : XDScanBLEStatus()
@@ -12,12 +8,5 @@ sealed class XDScanBLEStatus {
 
     interface Host {
         fun onStatusChanged(status: XDScanBLEStatus)
-
-        fun getManager(): Manager
-    }
-
-    interface Manager {
-        suspend fun scanBle(): Flow<ScanResult>
-        suspend fun connectWifi(device: BluetoothDevice, ssid: String, password: String)
     }
 }