feat: add BleRelayManager scan logic with permissions
This commit is contained in:
parent
82852e086e
commit
92585455c8
1 changed files with 102 additions and 6 deletions
|
|
@ -11,6 +11,16 @@ import java.nio.ByteBuffer
|
|||
import java.nio.ByteOrder
|
||||
import javax.crypto.Mac
|
||||
import javax.crypto.spec.SecretKeySpec
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.bluetooth.BluetoothAdapter
|
||||
import android.bluetooth.le.ScanCallback
|
||||
import android.bluetooth.le.ScanFilter
|
||||
import android.bluetooth.le.ScanResult
|
||||
import android.bluetooth.le.ScanSettings
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.ParcelUuid
|
||||
import androidx.core.app.ActivityCompat
|
||||
|
||||
class BleRelayManager(
|
||||
private val context: Context,
|
||||
|
|
@ -38,9 +48,92 @@ class BleRelayManager(
|
|||
private var hmacKey: ByteArray? = null
|
||||
private var deviceUuid: ByteArray? = null
|
||||
private var triedAddresses = mutableSetOf<String>()
|
||||
private val scanRunnable = Runnable { startScan() }
|
||||
private var scanTimeoutRunnable: Runnable? = null
|
||||
|
||||
private val scanCallback = object : ScanCallback() {
|
||||
override fun onScanResult(callbackType: Int, result: ScanResult) {
|
||||
val device = result.device ?: return
|
||||
val address = device.address ?: return
|
||||
if (triedAddresses.contains(address)) return
|
||||
stopScan()
|
||||
connectToDevice(device)
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
fun startScan() {
|
||||
if (isScanning) return
|
||||
if (!hasPermissions()) {
|
||||
callbacks.onStatusChanged(BleStatus.PermissionsDenied)
|
||||
return
|
||||
}
|
||||
val adapter = BluetoothAdapter.getDefaultAdapter()
|
||||
if (adapter == null || !adapter.isEnabled) {
|
||||
callbacks.onStatusChanged(BleStatus.BluetoothDisabled)
|
||||
return
|
||||
}
|
||||
loadState()
|
||||
if (hmacKey == null || deviceUuid == null) {
|
||||
callbacks.onStatusChanged(BleStatus.NoKey)
|
||||
return
|
||||
}
|
||||
isScanning = true
|
||||
scanTimedOut = false
|
||||
scanTimeoutRetries = 0
|
||||
callbacks.onStatusChanged(BleStatus.Scanning)
|
||||
val filter = ScanFilter.Builder().setServiceUuid(ParcelUuid(SERVICE_UUID)).build()
|
||||
val settings = ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build()
|
||||
adapter.bluetoothLeScanner.startScan(listOf(filter), settings, scanCallback)
|
||||
scanTimeoutRunnable?.let { handler.removeCallbacks(it) }
|
||||
scanTimeoutRunnable = Runnable {
|
||||
if (isScanning) {
|
||||
scanTimedOut = true
|
||||
stopScan()
|
||||
}
|
||||
}
|
||||
handler.postDelayed(scanTimeoutRunnable!!, SCAN_TIMEOUT_MS)
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
fun stopScan() {
|
||||
if (!isScanning) return
|
||||
isScanning = false
|
||||
scanTimeoutRunnable?.let { handler.removeCallbacks(it) }
|
||||
val adapter = BluetoothAdapter.getDefaultAdapter()
|
||||
adapter?.bluetoothLeScanner?.stopScan(scanCallback)
|
||||
if (scanTimedOut) {
|
||||
if (scanTimeoutRetries < MAX_SCAN_RETRIES) {
|
||||
scanTimeoutRetries++
|
||||
handler.postDelayed(scanRunnable, 2000L)
|
||||
return
|
||||
}
|
||||
callbacks.onStatusChanged(BleStatus.DeviceNotFound)
|
||||
}
|
||||
}
|
||||
|
||||
fun hasPermissions(): Boolean {
|
||||
return getRequiredPermissions().all {
|
||||
ActivityCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
}
|
||||
|
||||
fun getRequiredPermissions(): Array<String> {
|
||||
return if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
|
||||
arrayOf(
|
||||
Manifest.permission.BLUETOOTH_SCAN,
|
||||
Manifest.permission.BLUETOOTH_CONNECT,
|
||||
Manifest.permission.ACCESS_FINE_LOCATION
|
||||
)
|
||||
} else {
|
||||
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION)
|
||||
}
|
||||
}
|
||||
|
||||
fun destroy() {
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
}
|
||||
|
||||
fun startScan() {}
|
||||
fun stopScan() {}
|
||||
fun sendRelayCommand(cmd: Byte) {}
|
||||
fun disconnect() {}
|
||||
fun updateKeys() {
|
||||
|
|
@ -51,11 +144,14 @@ class BleRelayManager(
|
|||
triedAddresses.clear()
|
||||
}
|
||||
|
||||
fun hasPermissions(): Boolean = false
|
||||
fun getRequiredPermissions(): Array<String> = emptyArray()
|
||||
@SuppressLint("MissingPermission")
|
||||
private fun connectToDevice(device: android.bluetooth.BluetoothDevice) {
|
||||
callbacks.onStatusChanged(BleStatus.Connecting)
|
||||
bluetoothGatt = device.connectGatt(context, false, gattCallback)
|
||||
}
|
||||
|
||||
fun destroy() {
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
private val gattCallback = object : android.bluetooth.BluetoothGattCallback() {
|
||||
// implemented in next task
|
||||
}
|
||||
|
||||
private fun loadState() {
|
||||
|
|
|
|||
Loading…
Reference in a new issue