Browse Source

wifi service

zhaoyadi 10 months ago
parent
commit
f9939e958e

+ 4 - 0
xiaodou/src/main/java/com/luojigou/xiaodou/XDConnectActivity.kt

@@ -0,0 +1,4 @@
+package com.luojigou.xiaodou
+
+class XDConnectActivity {
+}

+ 130 - 67
xiaodou/src/main/java/com/luojigou/xiaodou/XDScanBLEService.kt

@@ -7,6 +7,7 @@ import android.bluetooth.BluetoothDevice
 import android.bluetooth.BluetoothGatt
 import android.bluetooth.BluetoothGattCallback
 import android.bluetooth.BluetoothGattCharacteristic
+import android.bluetooth.BluetoothGattDescriptor
 import android.bluetooth.BluetoothManager
 import android.bluetooth.BluetoothProfile
 import android.bluetooth.le.ScanCallback
@@ -46,14 +47,18 @@ class XDScanBLEService : Service() {
         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_BLE = "com.luojigou.xiaodou.ble.ACTION_CONNECT_BLE"
+        const val ACTION_CONNECT_BLE_RESULT_ERROR = "com.luojigou.xiaodou.ble.ACTION_CONNECT_BLE_RESULT_ERROR"
+        const val ACTION_CONNECT_BLE_RESULT_SUCCESS = "com.luojigou.xiaodou.ble.ACTION_CONNECT_BLE_RESULT_SUCCESS"
+
         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"
-        const val ACTION_CONNECT_WIFI_RESULT_FAILED = "com.luojigou.xiaodou.ble.ACTION_CONNECT_WIFI_RESULT_FAILED"
 
         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 wifiConnectNotifyDescUUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")
 
         private val bleChannelName = "BLE-CHANNEL"
     }
@@ -64,11 +69,9 @@ class XDScanBLEService : Service() {
 
     private lateinit var bluetoothAdapter: BluetoothAdapter
 
-    /// 选择要连接的蓝牙设备
-    private var selectBluetoothDevice: XDScanBLEDevice? = null
+    private var bluetoothGatt: BluetoothGatt? = null
 
-    /// 选择要连接的wifi网络
-    private var selectWifiInfo: XDScanWifiInfo? = null
+    private var writeCharacteristic: BluetoothGattCharacteristic? = null
 
     private var bluetoothReceiver: BroadcastReceiver = object : BroadcastReceiver() {
         override fun onReceive(context: Context?, intent: Intent) {
@@ -78,17 +81,6 @@ class XDScanBLEService : Service() {
                     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(
@@ -98,10 +90,7 @@ class XDScanBLEService : Service() {
                         intent.getParcelableExtra<XDScanBLEDevice>(ACTION_SELECT_BLE_DEVICE)
                     }
 
-                    if (bleDevice != null) {
-                        selectBluetoothDevice = bleDevice
-                        selectWifiInfo = null
-                    }
+                    bleDevice?.let { connectBLE(it) }
                 }
 
                 ACTION_SELECT_WIFI_DEVICE -> {
@@ -113,12 +102,7 @@ class XDScanBLEService : Service() {
                         intent.getParcelableExtra<XDScanWifiInfo>(ACTION_SELECT_WIFI_DEVICE)
                     }
 
-                    if (wifiInfo != null) {
-                        selectWifiInfo = wifiInfo
-                        if (selectBluetoothDevice != null) {
-                            connectWifi(selectBluetoothDevice!!, wifiInfo.ssid, wifiInfo.password)
-                        }
-                    }
+                    wifiInfo?.let { connectWifi(wifiInfo) }
                 }
             }
         }
@@ -231,6 +215,11 @@ class XDScanBLEService : Service() {
     }
 
     private fun startScan() {
+        bluetoothGatt?.disconnect()
+        bluetoothGatt?.close()
+
+        writeCharacteristic = null
+
         if (!bleScanning) {
             bleScanning = true
             bluetoothAdapter.bluetoothLeScanner.startScan(
@@ -242,13 +231,13 @@ class XDScanBLEService : Service() {
 
     private fun delayClose() {
         thread {
-            sendBroadcast(Intent(ACTION_START_SCAN))
-            Thread.sleep(5000)
+            broadcastUpdate(ACTION_START_SCAN)
+            Thread.sleep(3000)
             if (bleScanning) {
                 stopScan()
             }
-            Thread.sleep(3000)
-            sendBroadcast(Intent(ACTION_STOP_SCAN))
+            Thread.sleep(1000)
+            broadcastUpdate(ACTION_STOP_SCAN)
         }
     }
 
@@ -267,60 +256,134 @@ class XDScanBLEService : Service() {
         sendBroadcast(intent)
     }
 
-    private fun connectWifi(device: XDScanBLEDevice, ssid: String, password: String) {
+    private fun connectBLE(device: XDScanBLEDevice) {
+        broadcastUpdate(ACTION_CONNECT_BLE)
         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()
-                    }
+        bluetoothGatt = bleDevice.connectGatt(
+            this,
+            false,
+            bluetoothGattCallback,
+            BluetoothDevice.TRANSPORT_LE,
+        )
+    }
 
-                    BluetoothProfile.STATE_DISCONNECTED -> {
-                        gatt.close()
-                    }
+    private fun connectWifi(device: XDScanWifiInfo) {
+        if (bluetoothGatt == null || writeCharacteristic == null) return
+
+        bluetoothGatt!!.writeCharacteristic(
+            writeCharacteristic!!,
+            XDBLEUtils.convertToConnectRequest(device.ssid, device.password),
+            BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE,
+        )
+    }
+
+    override fun onDestroy() {
+        bluetoothGatt?.disconnect()
+        bluetoothGatt?.close()
+
+        unregisterReceiver(bluetoothReceiver)
+        stopScan()
+        super.onDestroy()
+        Log.d("XDScanBLEService", "onDestroy: service destroyed")
+    }
+
+    private fun broadcastUpdate(action: String) {
+        val intent = Intent(action)
+        sendBroadcast(intent)
+    }
+
+    private val bluetoothGattCallback = 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()
+                    bluetoothGatt = null
                 }
             }
+        }
 
-            override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
-                super.onServicesDiscovered(gatt, status)
-                Log.d("XDScanBLEGattCallback", "onServicesDiscovered: $status")
+        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)!!
+            when (status) {
+                BluetoothGatt.GATT_SUCCESS -> {
+                    val service = gatt.getService(wifiConnectServiceUUID)!!
 
-                        val notifyCharacteristic = service.getCharacteristic(wifiConnectNotifyUUID)!!
-                        val writeCharacteristic = service.getCharacteristic(wifiConnectWriteUUID)!!
+                    val notifyCharacteristic = service.getCharacteristic(wifiConnectNotifyUUID)
+                    writeCharacteristic = service.getCharacteristic(wifiConnectWriteUUID)
 
-                        gatt.setCharacteristicNotification(notifyCharacteristic, true)
+                    if (notifyCharacteristic == null || writeCharacteristic == null) {
+                        broadcastUpdate(ACTION_CONNECT_BLE_RESULT_ERROR)
+                        return
+                    }
+
+                    gatt.setCharacteristicNotification(notifyCharacteristic, true)
 
+                    val notifyDescriptor = notifyCharacteristic.getDescriptor(
+                        wifiConnectNotifyDescUUID
+                    )
 
+                    if (notifyDescriptor != null) {
+                        notifyDescriptor.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
+                        gatt.writeDescriptor(notifyDescriptor)
                     }
+
+                    broadcastUpdate(ACTION_CONNECT_BLE_RESULT_SUCCESS)
                 }
             }
+        }
 
-            override fun onCharacteristicChanged(
-                gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, value: ByteArray
-            ) {
-                super.onCharacteristicChanged(gatt, characteristic, value)
-                val result = XDBLEUtils.parseConnectResponse(value)
-                Log.d("XDScanBLEService", "onCharacteristicChanged: $result")
-            }
+        override fun onCharacteristicChanged(
+            gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic
+        ) {
+            super.onCharacteristicChanged(gatt, characteristic)
+            gatt.readCharacteristic(characteristic)
+            Log.d("XDScanBLEService", "onCharacteristicChanged1:")
         }
 
-        val connectGatt = bleDevice.connectGatt(
-            this, false, gattCallback, BluetoothDevice.TRANSPORT_LE
-        )
-    }
+        override fun onCharacteristicChanged(
+            gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, value: ByteArray
+        ) {
+            super.onCharacteristicChanged(gatt, characteristic, value)
+            val result = XDBLEUtils.parseConnectResponse(value)
+            Log.d("XDScanBLEService", "onCharacteristicChanged2: $result")
+        }
 
-    override fun onDestroy() {
-        unregisterReceiver(bluetoothReceiver)
-        stopScan()
-        super.onDestroy()
-        Log.d("XDScanBLEService", "onDestroy: service destroyed")
+        override fun onCharacteristicRead(
+            gatt: BluetoothGatt,
+            characteristic: BluetoothGattCharacteristic,
+            value: ByteArray,
+            status: Int
+        ) {
+            super.onCharacteristicRead(gatt, characteristic, value, status)
+            val result = XDBLEUtils.parseConnectResponse(value)
+            Log.d("XDScanBLEService", "onCharacteristicRead: $result")
+        }
+
+        override fun onCharacteristicWrite(
+            gatt: BluetoothGatt?, characteristic: BluetoothGattCharacteristic?, status: Int
+        ) {
+            super.onCharacteristicWrite(gatt, characteristic, status)
+            Log.d("XDScanBLEService", "onCharacteristicWrite: $status")
+            if (status == BluetoothGatt.GATT_SUCCESS) {
+                Log.d("XDScanBLEService", "onCharacteristicWrite: success")
+            }
+        }
+
+        override fun onDescriptorRead(
+            gatt: BluetoothGatt, descriptor: BluetoothGattDescriptor, status: Int, value: ByteArray
+        ) {
+            super.onDescriptorRead(gatt, descriptor, status, value)
+            val result = XDBLEUtils.parseConnectResponse(value)
+            Log.d("XDScanBLEService", "onDescriptorRead: $result")
+        }
     }
 }

+ 7 - 0
xiaodou/src/main/java/com/luojigou/xiaodou/ble/XDBLEController.kt

@@ -0,0 +1,7 @@
+package com.luojigou.xiaodou.ble
+
+import android.content.Context
+
+class XDBLEController(private val context: Context) {
+
+}

+ 29 - 2
xiaodou/src/main/java/com/luojigou/xiaodou/ble/XDBLEUtils.kt

@@ -3,11 +3,38 @@ package com.luojigou.xiaodou.ble
 import android.util.Log
 
 object XDBLEUtils {
-    fun parseConnectResponse(data: ByteArray) {
+    const val CONNECT_SUCCESS = 0
+    const val CONNECTING = 1
+    const val CONNECT_FAIL = 2
+    const val CONNECT_NOT_FOUND = 3
+    const val CONNECT_PWD_ERROR = 4
+
+    const val END_BYTE: Byte = 255.toByte()
+    fun parseConnectResponse(data: ByteArray): Int {
         Log.d("XDBLEUtils", "parseConnectResponse: ${data.decodeToString()}")
+        return data[16] - '0'.code
     }
 
     fun convertToConnectRequest(ssid: String, password: String): ByteArray {
+        val stringBuffer = StringBuffer()
+        stringBuffer.append(Char(0x7E))
+        stringBuffer.append(Char(0x01))
+        stringBuffer.append(Char(ssid.length))
+        ssid.toCharArray().forEach {
+            stringBuffer.append(it)
+        }
+        stringBuffer.append(Char(password.length))
+        password.toCharArray().forEach {
+            stringBuffer.append(it)
+        }
+        val byteArray = stringBuffer.toString().toByteArray()
+        return byteArrayOf(*byteArray, END_BYTE)
+    }
+
+    fun convert(): ByteArray {
+        val ssid = "abcd"
+        val password = "12345678"
+
         val stringBuffer = StringBuffer()
 
         stringBuffer.append(Char(0x7E))
@@ -20,7 +47,7 @@ object XDBLEUtils {
         password.toCharArray().forEach {
             stringBuffer.append(it)
         }
-        stringBuffer.append(Char(0xFF))
+        stringBuffer.append(0xFF)
         val byteArray = stringBuffer.toString().toByteArray()
         return byteArray
     }

+ 4 - 0
xiaodou/src/main/java/com/luojigou/xiaodou/wifi/XDScanWifiAdapter.kt

@@ -32,6 +32,10 @@ class XDScanWifiAdapter(
         } else {
             holder.name.text = item.BSSID
         }
+
+        holder.itemView.setOnClickListener {
+            itemClickListener.invoke(item)
+        }
     }
 
     fun addValue(result: ScanResult) {

+ 17 - 3
xiaodou/src/main/java/com/luojigou/xiaodou/wifi/XDScanWifiNormalFragment.kt

@@ -6,6 +6,7 @@ import android.content.Context
 import android.content.Intent
 import android.content.IntentFilter
 import android.net.wifi.WifiManager
+import android.os.Build
 import android.os.Bundle
 import android.view.LayoutInflater
 import android.view.View
@@ -16,13 +17,27 @@ import androidx.fragment.app.Fragment
 import androidx.recyclerview.widget.LinearLayoutManager
 import androidx.recyclerview.widget.RecyclerView
 import com.luojigou.xiaodou.R
+import com.luojigou.xiaodou.XDScanBLEService
 
 @SuppressLint("MissingPermission")
 class XDScanWifiNormalFragment(private val host: XDScanWifiStatus.Host) : Fragment() {
     private lateinit var wifiScanReceiver: BroadcastReceiver
 
-    private val adapter = XDScanWifiAdapter {
-
+    private val adapter = XDScanWifiAdapter { wifi ->
+        XDScanWifiPasswordFragment {
+            val intent = Intent(XDScanBLEService.ACTION_SELECT_WIFI_DEVICE)
+            intent.putExtra(
+                XDScanBLEService.ACTION_SELECT_WIFI_DEVICE_DATA, XDScanWifiInfo(
+                    ssid = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+                        val s = wifi.wifiSsid.toString()
+                        s.substring(1, s.length - 1)
+                    } else {
+                        wifi.BSSID
+                    }, password = it
+                )
+            )
+            requireActivity().sendBroadcast(intent)
+        }.show(requireActivity().supportFragmentManager, "password")
     }
 
     override fun onCreateView(
@@ -34,7 +49,6 @@ class XDScanWifiNormalFragment(private val host: XDScanWifiStatus.Host) : Fragme
     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         super.onViewCreated(view, savedInstanceState)
 
-
         val restartScanButton = view.findViewById<Button>(R.id.scan_again) //        restartScanButton.setOnClickListener { restartScan() }
 
         val recyclerView = view.findViewById<RecyclerView>(R.id.scan_list)

+ 34 - 0
xiaodou/src/main/java/com/luojigou/xiaodou/wifi/XDScanWifiPasswordFragment.kt

@@ -0,0 +1,34 @@
+package com.luojigou.xiaodou.wifi
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Button
+import android.widget.EditText
+import com.google.android.material.bottomsheet.BottomSheetDialogFragment
+import com.luojigou.xiaodou.R
+
+class XDScanWifiPasswordFragment(private val onPasswordEdit: (password: String) -> Unit) :
+    BottomSheetDialogFragment() {
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View {
+        return inflater.inflate(R.layout.fragment_scanwifi_password, container, false)
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+
+        val editText = view.findViewById<EditText>(R.id.et_pwd)
+        val button = view.findViewById<Button>(R.id.btn_pwd)
+
+        button.setOnClickListener {
+            val text = editText.getText()
+            onPasswordEdit.invoke(text.toString())
+            dismiss()
+        }
+    }
+}

+ 19 - 0
xiaodou/src/main/res/layout/fragment_scanwifi_password.xml

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:padding="16dp">
+
+    <EditText
+        android:id="@+id/et_pwd"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:hint="请在此输入wifi密码" />
+
+    <Button
+        android:id="@+id/btn_pwd"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="这是一个底部滑出对话框" />
+</LinearLayout>