209 lines
5.5 KiB
Kotlin
209 lines
5.5 KiB
Kotlin
package llc.arma.ble.data
|
|
|
|
import android.Manifest
|
|
import android.app.Application
|
|
import android.bluetooth.BluetoothGatt
|
|
import android.bluetooth.BluetoothGattCallback
|
|
import android.bluetooth.BluetoothGattCharacteristic
|
|
import android.bluetooth.BluetoothProfile
|
|
import android.content.pm.PackageManager
|
|
import android.os.Build
|
|
import android.util.Log
|
|
import androidx.core.app.ActivityCompat
|
|
import llc.arma.ble.domain.Result
|
|
import llc.arma.ble.domain.common.BleException
|
|
import llc.arma.ble.domain.model.Ble
|
|
import java.util.UUID
|
|
|
|
class WriteBeaconCallback(
|
|
private val app: Application,
|
|
private var request: Ble.Beacon.WriteRequest,
|
|
private val onResult: (Result<Unit, BleException>) -> Unit
|
|
) : BluetoothGattCallback() {
|
|
|
|
private var flashed = false
|
|
|
|
override fun onConnectionStateChange(
|
|
gatt: BluetoothGatt,
|
|
status: Int,
|
|
newState: Int
|
|
) {
|
|
super.onConnectionStateChange(gatt, status, newState)
|
|
|
|
if(checkPermission()) {
|
|
|
|
if(status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED) {
|
|
|
|
gatt.discoverServices()
|
|
|
|
} else {
|
|
|
|
onResult(Result.failure(BleException.UnexpectedResponse))
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
onResult(Result.failure(BleException.PermissionDenied))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
override fun onServicesDiscovered(
|
|
gatt: BluetoothGatt,
|
|
status: Int
|
|
) {
|
|
super.onServicesDiscovered(gatt, status)
|
|
onCycle(gatt, status)
|
|
|
|
}
|
|
|
|
private fun onCycle(
|
|
gatt: BluetoothGatt,
|
|
status: Int
|
|
){
|
|
|
|
if(request.tx != null) {
|
|
|
|
var uuid: Pair<UUID, ByteArray>? = null
|
|
|
|
uuid = request.tx?.let {
|
|
|
|
this.request = request.copy(
|
|
tx = null
|
|
)
|
|
|
|
Pair(
|
|
txWriteUUID,
|
|
byteArrayOf(
|
|
when (it) {
|
|
Ble.BleState.TX.MINUS_40 -> -40
|
|
Ble.BleState.TX.MINUS_20 -> -20
|
|
Ble.BleState.TX.MINUS_16 -> -16
|
|
Ble.BleState.TX.MINUS_12 -> -12
|
|
Ble.BleState.TX.MINUS_8 -> -8
|
|
Ble.BleState.TX.MINUS_4 -> -4
|
|
Ble.BleState.TX.ZERO -> 0
|
|
Ble.BleState.TX.PLUS_3 -> 3
|
|
Ble.BleState.TX.PLUS_4 -> 4
|
|
}
|
|
)
|
|
)
|
|
|
|
} ?: uuid
|
|
|
|
uuid?.let { uuid ->
|
|
|
|
gatt.services.firstOrNull { it.uuid == serviceUUID }?.characteristics?.firstOrNull {
|
|
it.uuid == uuid.first
|
|
}?.let {
|
|
|
|
gatt.writeCharacteristic(it, uuid.second)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
onResult(Result.failure(BleException.UnexpectedResponse))
|
|
|
|
} else {
|
|
|
|
if(flashed.not()){
|
|
|
|
flashed = true
|
|
|
|
gatt.services.firstOrNull { it.uuid == serviceUUID }?.characteristics?.firstOrNull {
|
|
it.uuid == flashWriteUUID
|
|
}?.let {
|
|
|
|
gatt.writeCharacteristic(it, byteArrayOf(9))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
onResult(Result.failure(BleException.UnexpectedResponse))
|
|
|
|
} else {
|
|
|
|
onResult(Result.success(Unit))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
override fun onCharacteristicWrite(
|
|
gatt: BluetoothGatt,
|
|
characteristic: BluetoothGattCharacteristic,
|
|
status: Int
|
|
) {
|
|
|
|
Log.d("beacon", "onCharacteristicWrite $status")
|
|
|
|
super.onCharacteristicWrite(gatt, characteristic, status)
|
|
|
|
if(checkPermission()) {
|
|
|
|
if(status == BluetoothGatt.GATT_SUCCESS || flashed) {
|
|
|
|
onCycle(gatt, status)
|
|
|
|
} else {
|
|
|
|
onResult(Result.failure(BleException.UnexpectedResponse))
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
onResult(Result.failure(BleException.PermissionDenied))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fun BluetoothGatt.writeCharacteristic(
|
|
characteristic: BluetoothGattCharacteristic,
|
|
data: ByteArray
|
|
): Result<Unit, BleException> {
|
|
|
|
return if(checkPermission()){
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
writeCharacteristic(characteristic, data, BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT)
|
|
}else{
|
|
|
|
characteristic.writeType
|
|
characteristic.value = data
|
|
writeCharacteristic(characteristic)
|
|
}
|
|
|
|
Result.success(Unit)
|
|
|
|
} else {
|
|
Result.failure(BleException.PermissionDenied)
|
|
}
|
|
|
|
}
|
|
|
|
fun checkPermission(): Boolean {
|
|
|
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
ActivityCompat.checkSelfPermission(app, Manifest.permission.BLUETOOTH_CONNECT) ==
|
|
PackageManager.PERMISSION_GRANTED &&
|
|
ActivityCompat.checkSelfPermission(app, Manifest.permission.BLUETOOTH_SCAN) ==
|
|
PackageManager.PERMISSION_GRANTED
|
|
} else {
|
|
return ActivityCompat.checkSelfPermission(app, Manifest.permission.ACCESS_FINE_LOCATION) ==
|
|
PackageManager.PERMISSION_GRANTED &&
|
|
ActivityCompat.checkSelfPermission(app, Manifest.permission.ACCESS_COARSE_LOCATION) ==
|
|
PackageManager.PERMISSION_GRANTED
|
|
}
|
|
}
|
|
|
|
} |