|
@@ -4,7 +4,11 @@ import android.annotation.SuppressLint
|
|
|
import android.app.Service
|
|
|
import android.bluetooth.BluetoothAdapter
|
|
|
import android.bluetooth.BluetoothDevice
|
|
|
+import android.bluetooth.BluetoothGatt
|
|
|
+import android.bluetooth.BluetoothGattCallback
|
|
|
+import android.bluetooth.BluetoothGattCharacteristic
|
|
|
import android.bluetooth.BluetoothManager
|
|
|
+import android.bluetooth.BluetoothProfile
|
|
|
import android.bluetooth.le.ScanCallback
|
|
|
import android.bluetooth.le.ScanFilter
|
|
|
import android.bluetooth.le.ScanResult
|
|
@@ -19,7 +23,10 @@ import android.util.Log
|
|
|
import androidx.core.app.NotificationChannelCompat
|
|
|
import androidx.core.app.NotificationCompat
|
|
|
import androidx.core.app.NotificationManagerCompat
|
|
|
+import androidx.core.content.ContextCompat
|
|
|
+import com.luojigou.xiaodou.ble.XDBLEUtils
|
|
|
import com.luojigou.xiaodou.ble.XDScanBLEDevice
|
|
|
+import com.luojigou.xiaodou.wifi.XDScanWifiInfo
|
|
|
import java.util.UUID
|
|
|
import kotlin.concurrent.thread
|
|
|
|
|
@@ -29,10 +36,16 @@ class XDScanBLEService : Service() {
|
|
|
companion object {
|
|
|
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_RESTART_SCAN = "com.luojigou.xiaodou.ble.ACTION_RESTART_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_SELECT_BLE_DEVICE = "com.luojigou.xiaodou.ble.ACTION_SELECT_BLE_DEVICE"
|
|
|
+ const val ACTION_SELECT_BLE_DEVICE_DATA = "com.luojigou.xiaodou.ble.ACTION_SELECT_BLE_DEVICE_DATA"
|
|
|
+ const val ACTION_SELECT_WIFI_DEVICE = "com.luojigou.xiaodou.ble.ACTION_SELECT_WIFI_DEVICE"
|
|
|
+ const val ACTION_SELECT_WIFI_DEVICE_DATA = "com.luojigou.xiaodou.ble.ACTION_SELECT_WIFI_DEVICE_DATA"
|
|
|
+
|
|
|
const val ACTION_CONNECT_WIFI = "com.luojigou.xiaodou.ble.ACTION_CONNECT_WIFI"
|
|
|
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"
|
|
@@ -45,13 +58,71 @@ class XDScanBLEService : Service() {
|
|
|
private val bleChannelName = "BLE-CHANNEL"
|
|
|
}
|
|
|
|
|
|
- private val deviceMap: MutableMap<XDScanBLEDevice, BluetoothDevice> = HashMap()
|
|
|
+ private val bluetoothDevices: MutableMap<XDScanBLEDevice, BluetoothDevice> = HashMap()
|
|
|
|
|
|
private lateinit var bluetoothManager: BluetoothManager
|
|
|
|
|
|
private lateinit var bluetoothAdapter: BluetoothAdapter
|
|
|
|
|
|
- private lateinit var bluetoothReceiver: BroadcastReceiver
|
|
|
+ /// 选择要连接的蓝牙设备
|
|
|
+ private var selectBluetoothDevice: XDScanBLEDevice? = null
|
|
|
+
|
|
|
+ /// 选择要连接的wifi网络
|
|
|
+ private var selectWifiInfo: XDScanWifiInfo? = null
|
|
|
+
|
|
|
+ private var bluetoothReceiver: BroadcastReceiver = object : BroadcastReceiver() {
|
|
|
+ override fun onReceive(context: Context?, intent: Intent) {
|
|
|
+ when (intent.action) {
|
|
|
+ ACTION_RESTART_SCAN -> {
|
|
|
+ bluetoothDevices.clear()
|
|
|
+ startScan()
|
|
|
+ }
|
|
|
+
|
|
|
+ ACTION_CONNECT_WIFI -> {
|
|
|
+ val device = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
|
+ intent.getParcelableExtra("device", XDScanBLEDevice::class.java)
|
|
|
+ } else {
|
|
|
+ intent.getParcelableExtra<XDScanBLEDevice>("device")
|
|
|
+ }
|
|
|
+ val ssid = intent.getStringExtra("ssid")
|
|
|
+ val password = intent.getStringExtra("password")
|
|
|
+ connectWifi(device!!, ssid!!, password!!)
|
|
|
+ }
|
|
|
+
|
|
|
+ ACTION_SELECT_BLE_DEVICE -> {
|
|
|
+ val bleDevice = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
|
+ intent.getParcelableExtra(
|
|
|
+ ACTION_SELECT_BLE_DEVICE_DATA, XDScanBLEDevice::class.java
|
|
|
+ )
|
|
|
+ } else {
|
|
|
+ intent.getParcelableExtra<XDScanBLEDevice>(ACTION_SELECT_BLE_DEVICE)
|
|
|
+ }
|
|
|
+
|
|
|
+ if (bleDevice != null) {
|
|
|
+ selectBluetoothDevice = bleDevice
|
|
|
+ selectWifiInfo = null
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ACTION_SELECT_WIFI_DEVICE -> {
|
|
|
+ val wifiInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
|
+ intent.getParcelableExtra(
|
|
|
+ ACTION_SELECT_WIFI_DEVICE_DATA, XDScanWifiInfo::class.java
|
|
|
+ )
|
|
|
+ } else {
|
|
|
+ intent.getParcelableExtra<XDScanWifiInfo>(ACTION_SELECT_WIFI_DEVICE)
|
|
|
+ }
|
|
|
+
|
|
|
+ if (wifiInfo != null) {
|
|
|
+ selectWifiInfo = wifiInfo
|
|
|
+ if (selectBluetoothDevice != null) {
|
|
|
+ connectWifi(selectBluetoothDevice!!, wifiInfo.ssid, wifiInfo.password)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
@Volatile
|
|
|
private var bleScanning = false
|
|
@@ -65,9 +136,9 @@ class XDScanBLEService : Service() {
|
|
|
private val bleScanCallback = object : ScanCallback() {
|
|
|
override fun onScanResult(callbackType: Int, result: ScanResult) {
|
|
|
super.onScanResult(callbackType, result)
|
|
|
- val oldSize = deviceMap.size
|
|
|
+ val oldSize = bluetoothDevices.size
|
|
|
addDevice(result)
|
|
|
- val newSize = deviceMap.size
|
|
|
+ val newSize = bluetoothDevices.size
|
|
|
|
|
|
if (oldSize != newSize) {
|
|
|
sendResult()
|
|
@@ -76,9 +147,9 @@ class XDScanBLEService : Service() {
|
|
|
|
|
|
override fun onBatchScanResults(results: MutableList<ScanResult>) {
|
|
|
super.onBatchScanResults(results)
|
|
|
- val oldSize = deviceMap.size
|
|
|
+ val oldSize = bluetoothDevices.size
|
|
|
results.forEach { addDevice(it) }
|
|
|
- val newSize = deviceMap.size
|
|
|
+ val newSize = bluetoothDevices.size
|
|
|
|
|
|
if (oldSize != newSize) {
|
|
|
sendResult()
|
|
@@ -103,8 +174,8 @@ class XDScanBLEService : Service() {
|
|
|
addressType = device.type.toString(),
|
|
|
)
|
|
|
|
|
|
- if (!deviceMap.contains(device)) {
|
|
|
- deviceMap[device] = result.device
|
|
|
+ if (!bluetoothDevices.contains(device)) {
|
|
|
+ bluetoothDevices[device] = result.device
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -129,8 +200,8 @@ class XDScanBLEService : Service() {
|
|
|
}
|
|
|
|
|
|
val notification = NotificationCompat.Builder(this, bleChannelName)
|
|
|
- .setContentTitle("XiaoDou")
|
|
|
- .setContentText("XiaoDou is running")
|
|
|
+ .setContentTitle("小逗AI设备配网服务")
|
|
|
+ .setContentText("正在为小逗AI设备配网中")
|
|
|
.setSmallIcon(android.R.drawable.stat_sys_data_bluetooth)
|
|
|
.setChannelId(bleChannelName)
|
|
|
.build()
|
|
@@ -143,28 +214,14 @@ class XDScanBLEService : Service() {
|
|
|
bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
|
|
|
bluetoothAdapter = bluetoothManager.adapter
|
|
|
|
|
|
- bluetoothReceiver = object : BroadcastReceiver() {
|
|
|
- override fun onReceive(context: Context?, intent: Intent) {
|
|
|
- when (intent.action) {
|
|
|
- ACTION_START_SCAN -> {
|
|
|
- startScan()
|
|
|
- }
|
|
|
-
|
|
|
- ACTION_STOP_SCAN -> {
|
|
|
- stopScan()
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
val intentFilter = IntentFilter()
|
|
|
- intentFilter.addAction(ACTION_START_SCAN)
|
|
|
- intentFilter.addAction(ACTION_STOP_SCAN)
|
|
|
- if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
|
- registerReceiver(bluetoothReceiver, intentFilter, Context.RECEIVER_NOT_EXPORTED)
|
|
|
- }else{
|
|
|
- registerReceiver(bluetoothReceiver, intentFilter)
|
|
|
- }
|
|
|
+ intentFilter.addAction(ACTION_RESTART_SCAN)
|
|
|
+ intentFilter.addAction(ACTION_SELECT_BLE_DEVICE)
|
|
|
+ intentFilter.addAction(ACTION_SELECT_WIFI_DEVICE)
|
|
|
+ intentFilter.addAction(ACTION_CONNECT_WIFI)
|
|
|
+ ContextCompat.registerReceiver(
|
|
|
+ this, bluetoothReceiver, intentFilter, ContextCompat.RECEIVER_EXPORTED
|
|
|
+ )
|
|
|
|
|
|
startScan()
|
|
|
}
|
|
@@ -180,15 +237,18 @@ class XDScanBLEService : Service() {
|
|
|
bleScanFilters, bleScanSettings, bleScanCallback
|
|
|
)
|
|
|
}
|
|
|
- // delayClose()
|
|
|
+ delayClose()
|
|
|
}
|
|
|
|
|
|
private fun delayClose() {
|
|
|
thread {
|
|
|
+ sendBroadcast(Intent(ACTION_START_SCAN))
|
|
|
Thread.sleep(5000)
|
|
|
if (bleScanning) {
|
|
|
stopScan()
|
|
|
}
|
|
|
+ Thread.sleep(3000)
|
|
|
+ sendBroadcast(Intent(ACTION_STOP_SCAN))
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -202,11 +262,61 @@ class XDScanBLEService : Service() {
|
|
|
private fun sendResult() {
|
|
|
val intent = Intent(ACTION_SCAN_RESULT)
|
|
|
intent.putParcelableArrayListExtra(
|
|
|
- ACTION_SCAN_RESULT_DATA, ArrayList(deviceMap.keys)
|
|
|
+ ACTION_SCAN_RESULT_DATA, ArrayList(bluetoothDevices.keys)
|
|
|
)
|
|
|
sendBroadcast(intent)
|
|
|
}
|
|
|
|
|
|
+ private fun connectWifi(device: XDScanBLEDevice, ssid: String, password: String) {
|
|
|
+ val bleDevice = bluetoothDevices[device] ?: return
|
|
|
+
|
|
|
+ val gattCallback = object : BluetoothGattCallback() {
|
|
|
+ override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
|
|
|
+ super.onConnectionStateChange(gatt, status, newState)
|
|
|
+ Log.d("XDScanBLEGattCallback", "onConnectionStateChange: $status,$newState")
|
|
|
+ when (newState) {
|
|
|
+ BluetoothProfile.STATE_CONNECTED -> {
|
|
|
+ gatt.discoverServices()
|
|
|
+ }
|
|
|
+
|
|
|
+ BluetoothProfile.STATE_DISCONNECTED -> {
|
|
|
+ gatt.close()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
|
|
|
+ super.onServicesDiscovered(gatt, status)
|
|
|
+ Log.d("XDScanBLEGattCallback", "onServicesDiscovered: $status")
|
|
|
+
|
|
|
+ when (status) {
|
|
|
+ BluetoothGatt.GATT_SUCCESS -> {
|
|
|
+ val service = gatt.getService(wifiConnectServiceUUID)!!
|
|
|
+
|
|
|
+ val notifyCharacteristic = service.getCharacteristic(wifiConnectNotifyUUID)!!
|
|
|
+ val writeCharacteristic = service.getCharacteristic(wifiConnectWriteUUID)!!
|
|
|
+
|
|
|
+ gatt.setCharacteristicNotification(notifyCharacteristic, true)
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ override fun onCharacteristicChanged(
|
|
|
+ gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, value: ByteArray
|
|
|
+ ) {
|
|
|
+ super.onCharacteristicChanged(gatt, characteristic, value)
|
|
|
+ val result = XDBLEUtils.parseConnectResponse(value)
|
|
|
+ Log.d("XDScanBLEService", "onCharacteristicChanged: $result")
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ val connectGatt = bleDevice.connectGatt(
|
|
|
+ this, false, gattCallback, BluetoothDevice.TRANSPORT_LE
|
|
|
+ )
|
|
|
+ }
|
|
|
+
|
|
|
override fun onDestroy() {
|
|
|
unregisterReceiver(bluetoothReceiver)
|
|
|
stopScan()
|