|
@@ -0,0 +1,268 @@
|
|
|
+package com.luojigou.xiaodou
|
|
|
+
|
|
|
+import android.Manifest
|
|
|
+import android.annotation.SuppressLint
|
|
|
+import android.bluetooth.BluetoothAdapter
|
|
|
+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.Context
|
|
|
+import android.content.Intent
|
|
|
+import android.content.IntentFilter
|
|
|
+import android.content.pm.PackageManager
|
|
|
+import android.os.Build
|
|
|
+import android.os.Bundle
|
|
|
+import android.util.Log
|
|
|
+import android.view.View
|
|
|
+import android.widget.Button
|
|
|
+import android.widget.ListView
|
|
|
+import android.widget.ProgressBar
|
|
|
+import android.widget.TextView
|
|
|
+import androidx.activity.result.contract.ActivityResultContracts
|
|
|
+import androidx.appcompat.app.AppCompatActivity
|
|
|
+import androidx.core.app.ActivityCompat
|
|
|
+
|
|
|
+
|
|
|
+class XDScanBLEActivity : AppCompatActivity() {
|
|
|
+ companion object {
|
|
|
+ const val REQUEST_ENABLE_BT = 10086
|
|
|
+ }
|
|
|
+
|
|
|
+ private val permissions: Array<String> by lazy {
|
|
|
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
|
+ arrayOf(
|
|
|
+ Manifest.permission.BLUETOOTH_SCAN,
|
|
|
+ Manifest.permission.BLUETOOTH_ADVERTISE,
|
|
|
+ Manifest.permission.BLUETOOTH_CONNECT
|
|
|
+ )
|
|
|
+ } else {
|
|
|
+ arrayOf(
|
|
|
+ Manifest.permission.ACCESS_FINE_LOCATION
|
|
|
+ )
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private lateinit var txtMsg: TextView
|
|
|
+ private lateinit var btnScan: Button
|
|
|
+ private lateinit var listview: ListView
|
|
|
+ private lateinit var progress: ProgressBar
|
|
|
+
|
|
|
+ private val broadcastReceiver by lazy {
|
|
|
+ object : BroadcastReceiver() {
|
|
|
+ override fun onReceive(context: Context?, intent: Intent?) {
|
|
|
+ val lastState = intent?.getIntExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, -1)
|
|
|
+ val currentState = intent?.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1)
|
|
|
+
|
|
|
+ if (lastState == currentState) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ when (currentState) {
|
|
|
+ BluetoothAdapter.STATE_OFF -> { // 蓝牙已关闭
|
|
|
+ maybeSetupBluetooth()
|
|
|
+ Log.d("BLEStateBroadcastReceiver", "onReceive: Bluetooth is off")
|
|
|
+ }
|
|
|
+
|
|
|
+ BluetoothAdapter.STATE_ON -> { // 蓝牙已打开
|
|
|
+ maybeSetupBluetooth()
|
|
|
+ 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 bluetoothManager: BluetoothManager by lazy {
|
|
|
+ getSystemService(BLUETOOTH_SERVICE) as BluetoothManager
|
|
|
+ }
|
|
|
+
|
|
|
+ private var bluetoothAdapter: BluetoothAdapter? = null
|
|
|
+
|
|
|
+
|
|
|
+ private val requestMultiplePermissionLauncher = registerForActivityResult(
|
|
|
+ ActivityResultContracts.RequestMultiplePermissions()
|
|
|
+ ) { permissions: Map<String, Boolean> ->
|
|
|
+ val noGrantedPermissions = ArrayList<String>()
|
|
|
+ permissions.entries.forEach {
|
|
|
+ if (!it.value) {
|
|
|
+ noGrantedPermissions.add(it.key)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (noGrantedPermissions.isEmpty()) {
|
|
|
+ maybeSetupBluetooth()
|
|
|
+ } else {
|
|
|
+ setStatus(XDScanBLEStatus.Permission)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private val scanCallback = object : ScanCallback() {
|
|
|
+ override fun onScanResult(callbackType: Int, result: ScanResult) {
|
|
|
+ super.onScanResult(callbackType, result)
|
|
|
+ logScanResult(result)
|
|
|
+ }
|
|
|
+
|
|
|
+ override fun onBatchScanResults(results: MutableList<ScanResult>) {
|
|
|
+ super.onBatchScanResults(results) // 如果需要处理批量扫描结果,可以在此处进行
|
|
|
+
|
|
|
+ results.forEach { result -> logScanResult(result) }
|
|
|
+ }
|
|
|
+
|
|
|
+ @SuppressLint("MissingPermission")
|
|
|
+ private fun logScanResult(result: ScanResult) {
|
|
|
+ val device = result.device
|
|
|
+ val deviceName = device.name ?: "Unknown"
|
|
|
+ val deviceAddress = device.address
|
|
|
+ val rssi = result.rssi
|
|
|
+
|
|
|
+ Log.d(
|
|
|
+ "XDScanBLEService",
|
|
|
+ "发现BLE设备: 名称 - $deviceName, 地址 - $deviceAddress, 信号强度 - $rssi"
|
|
|
+ )
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ override fun onScanFailed(errorCode: Int) {
|
|
|
+ super.onScanFailed(errorCode)
|
|
|
+ Log.w("XDScanBLEService", "BLE扫描失败,错误代码: $errorCode") // 根据错误码处理扫描失败情况
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ override fun onCreate(savedInstanceState: Bundle?) {
|
|
|
+ super.onCreate(savedInstanceState)
|
|
|
+ setContentView(R.layout.activity_scanble)
|
|
|
+
|
|
|
+ txtMsg = findViewById(R.id.scan_message)
|
|
|
+ btnScan = findViewById(R.id.scan_button)
|
|
|
+ listview = findViewById(R.id.scan_list)
|
|
|
+ progress = findViewById(R.id.scan_progress)
|
|
|
+
|
|
|
+ btnScan.setOnClickListener {
|
|
|
+ setStatus(XDScanBLEStatus.Scanning)
|
|
|
+ startScanBle()
|
|
|
+ }
|
|
|
+
|
|
|
+ setStatus(XDScanBLEStatus.Idle)
|
|
|
+ checkBluetoothPermission()
|
|
|
+ registerReceiver(broadcastReceiver, IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED))
|
|
|
+ }
|
|
|
+
|
|
|
+ private fun checkBluetoothPermission() {
|
|
|
+ val bluetoothAvailable = packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)
|
|
|
+ val bluetoothLEAvailable =
|
|
|
+ packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)
|
|
|
+
|
|
|
+ if (!bluetoothAvailable || !bluetoothLEAvailable) {
|
|
|
+ setStatus(XDScanBLEStatus.NotSupported)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ val checkResult = permissions.find {
|
|
|
+ ActivityCompat.checkSelfPermission(
|
|
|
+ this, it
|
|
|
+ ) != PackageManager.PERMISSION_GRANTED
|
|
|
+ }
|
|
|
+
|
|
|
+ if (checkResult != null) {
|
|
|
+ requestMultiplePermissionLauncher.launch(permissions)
|
|
|
+ } else {
|
|
|
+ maybeSetupBluetooth()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @SuppressLint("MissingPermission")
|
|
|
+ private fun maybeSetupBluetooth() {
|
|
|
+ bluetoothAdapter = bluetoothManager.adapter
|
|
|
+
|
|
|
+ if (bluetoothAdapter == null || !bluetoothAdapter!!.isEnabled) {
|
|
|
+ setStatus(XDScanBLEStatus.Disabled)
|
|
|
+ val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
|
|
|
+ startActivity(enableBtIntent)
|
|
|
+ } else {
|
|
|
+ setStatus(XDScanBLEStatus.Waiting)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @SuppressLint("MissingPermission")
|
|
|
+ private fun startScanBle() {
|
|
|
+
|
|
|
+ val settings =
|
|
|
+ ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) // 或选择其他适合的扫描模式
|
|
|
+ .build()
|
|
|
+
|
|
|
+ val filters = mutableListOf<ScanFilter>() // 可以添加过滤条件,如特定的服务UUID等
|
|
|
+
|
|
|
+ try {
|
|
|
+ bluetoothAdapter?.bluetoothLeScanner?.startScan(filters, settings, scanCallback)
|
|
|
+ } catch (e: Exception) {
|
|
|
+ Log.e("XDScanBLEService", "startScanBle error: ${e.message}")
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ override fun onDestroy() {
|
|
|
+ unregisterReceiver(broadcastReceiver)
|
|
|
+ super.onDestroy()
|
|
|
+ }
|
|
|
+
|
|
|
+ private fun setStatus(status: XDScanBLEStatus) {
|
|
|
+ when (status) {
|
|
|
+ XDScanBLEStatus.Idle -> {
|
|
|
+ btnScan.visibility = View.GONE
|
|
|
+ listview.visibility = View.GONE
|
|
|
+ progress.visibility = View.GONE
|
|
|
+ txtMsg.visibility = View.GONE
|
|
|
+ }
|
|
|
+
|
|
|
+ XDScanBLEStatus.Permission -> {
|
|
|
+ btnScan.visibility = View.GONE
|
|
|
+ listview.visibility = View.GONE
|
|
|
+ progress.visibility = View.GONE
|
|
|
+ txtMsg.visibility = View.VISIBLE
|
|
|
+ txtMsg.text = "蓝牙权限申请失败,请手动设置权限"
|
|
|
+ }
|
|
|
+
|
|
|
+ XDScanBLEStatus.Disabled -> {
|
|
|
+ btnScan.visibility = View.GONE
|
|
|
+ listview.visibility = View.GONE
|
|
|
+ progress.visibility = View.GONE
|
|
|
+ txtMsg.visibility = View.VISIBLE
|
|
|
+ txtMsg.text = "蓝牙未开启,请开启蓝牙"
|
|
|
+ }
|
|
|
+
|
|
|
+ XDScanBLEStatus.NotSupported -> {
|
|
|
+ btnScan.visibility = View.GONE
|
|
|
+ listview.visibility = View.GONE
|
|
|
+ progress.visibility = View.GONE
|
|
|
+ txtMsg.visibility = View.VISIBLE
|
|
|
+ txtMsg.text = "当前设备不支持蓝牙配对"
|
|
|
+ }
|
|
|
+
|
|
|
+ XDScanBLEStatus.Waiting -> {
|
|
|
+ btnScan.visibility = View.VISIBLE
|
|
|
+ listview.visibility = View.GONE
|
|
|
+ progress.visibility = View.GONE
|
|
|
+ txtMsg.visibility = View.GONE
|
|
|
+ }
|
|
|
+
|
|
|
+ XDScanBLEStatus.Scanning -> {
|
|
|
+ btnScan.visibility = View.GONE
|
|
|
+ listview.visibility = View.VISIBLE
|
|
|
+ progress.visibility = View.VISIBLE
|
|
|
+ txtMsg.visibility = View.GONE
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|