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 ) : 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? = 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 { 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 } } }