|
| 1 | +package com.juul.kable |
| 2 | + |
| 3 | +import android.bluetooth.BluetoothGatt |
| 4 | +import android.bluetooth.BluetoothStatusCodes.ERROR_GATT_WRITE_NOT_ALLOWED |
| 5 | +import android.bluetooth.BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY |
| 6 | +import android.bluetooth.BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION |
| 7 | +import android.bluetooth.BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND |
| 8 | +import android.bluetooth.BluetoothStatusCodes.SUCCESS |
| 9 | +import android.os.Build |
| 10 | +import com.juul.kable.AndroidPeripheral.WriteResult |
| 11 | + |
| 12 | +internal fun BluetoothGatt.discoverServicesOrThrow() { |
| 13 | + if (!discoverServices()) { |
| 14 | + throw GattRequestRejectedException() |
| 15 | + } |
| 16 | +} |
| 17 | + |
| 18 | +internal fun BluetoothGatt.setCharacteristicNotificationOrThrow( |
| 19 | + characteristic: PlatformCharacteristic, |
| 20 | + enable: Boolean, |
| 21 | +) { |
| 22 | + if (!setCharacteristicNotification(characteristic, enable)) { |
| 23 | + throw GattRequestRejectedException() |
| 24 | + } |
| 25 | +} |
| 26 | + |
| 27 | +internal fun BluetoothGatt.readCharacteristicOrThrow( |
| 28 | + characteristic: PlatformCharacteristic, |
| 29 | +) { |
| 30 | + if (!readCharacteristic(characteristic)) { |
| 31 | + throw GattRequestRejectedException() |
| 32 | + } |
| 33 | +} |
| 34 | + |
| 35 | +internal fun BluetoothGatt.readDescriptorOrThrow( |
| 36 | + descriptor: PlatformDescriptor, |
| 37 | +) { |
| 38 | + if (!readDescriptor(descriptor)) { |
| 39 | + throw GattRequestRejectedException() |
| 40 | + } |
| 41 | +} |
| 42 | + |
| 43 | +internal fun BluetoothGatt.readRemoteRssiOrThrow() { |
| 44 | + if (!readRemoteRssi()) { |
| 45 | + throw GattRequestRejectedException() |
| 46 | + } |
| 47 | +} |
| 48 | + |
| 49 | +@Suppress("DEPRECATION") |
| 50 | +internal fun BluetoothGatt.writeCharacteristicOrThrow( |
| 51 | + characteristic: PlatformCharacteristic, |
| 52 | + data: ByteArray, |
| 53 | + writeType: Int, |
| 54 | +) { |
| 55 | + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { |
| 56 | + val result = writeCharacteristic(characteristic, data, writeType) |
| 57 | + if (result != SUCCESS) { |
| 58 | + throw GattWriteException(writeResultFrom(result)) |
| 59 | + } |
| 60 | + } else { |
| 61 | + characteristic.value = data |
| 62 | + characteristic.writeType = writeType |
| 63 | + if (!writeCharacteristic(characteristic)) { |
| 64 | + throw GattWriteException(WriteResult.Unknown) |
| 65 | + } |
| 66 | + } |
| 67 | +} |
| 68 | + |
| 69 | +@Suppress("DEPRECATION") |
| 70 | +internal fun BluetoothGatt.writeDescriptorOrThrow( |
| 71 | + descriptor: PlatformDescriptor, |
| 72 | + data: ByteArray, |
| 73 | +) { |
| 74 | + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { |
| 75 | + val result = writeDescriptor(descriptor, data) |
| 76 | + if (result != SUCCESS) { |
| 77 | + throw GattWriteException(writeResultFrom(result)) |
| 78 | + } |
| 79 | + } else { |
| 80 | + descriptor.value = data |
| 81 | + if (!writeDescriptor(descriptor)) { |
| 82 | + throw GattRequestRejectedException() |
| 83 | + } |
| 84 | + } |
| 85 | +} |
| 86 | + |
| 87 | +/** |
| 88 | + * Possible return value of [BluetoothGatt.writeCharacteristic] or [BluetoothGatt.writeDescriptor], |
| 89 | + * yet marked as `@hide` in Android source: |
| 90 | + * https://cs.android.com/android/platform/superproject/main/+/b7a389a145ff443550e1a942bf713c60c2bd6a14:packages/modules/Bluetooth/framework/java/android/bluetooth/BluetoothStatusCodes.java;l=45-50 |
| 91 | + */ |
| 92 | +private const val ERROR_DEVICE_NOT_CONNECTED = 4 |
| 93 | + |
| 94 | +private fun writeResultFrom(value: Int): WriteResult = when (value) { |
| 95 | + ERROR_DEVICE_NOT_CONNECTED -> WriteResult.NotConnected |
| 96 | + ERROR_GATT_WRITE_NOT_ALLOWED -> WriteResult.WriteNotAllowed |
| 97 | + ERROR_GATT_WRITE_REQUEST_BUSY -> WriteResult.WriteRequestBusy |
| 98 | + ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION -> WriteResult.MissingBluetoothConnectPermission |
| 99 | + ERROR_PROFILE_SERVICE_NOT_BOUND -> WriteResult.ProfileServiceNotBound |
| 100 | + else -> WriteResult.Unknown |
| 101 | +} |
0 commit comments