/*package*/ NativeGattCharacteristic( @NonNull BluetoothGattCharacteristic characteristic, @NonNull NativeGattService service, @NonNull NativeGattPeripheral peripheral) { this.wrappedCharacteristic = characteristic; this.service = service; this.peripheral = peripheral; this.logger = peripheral.getStack().getLogger(); this.gattDispatcher = peripheral.gattDispatcher; }
@Override @NonNull public Observable<byte[]> read(@NonNull final OperationTimeout timeout) { return peripheral.createObservable( new ConnectedOnSubscribe<byte[]>(peripheral) { @Override public void onSubscribe( @NonNull BluetoothGatt gatt, @NonNull final Subscriber<? super byte[]> subscriber) { logger.info(GattPeripheral.LOG_TAG, "Reading characteristic " + getUuid()); final Runnable onDisconnect = peripheral.addTimeoutDisconnectListener(subscriber, timeout); peripheral.setupTimeout(Operation.READ, timeout, subscriber, onDisconnect); gattDispatcher.characteristicRead = new CharacteristicReadListener() { @Override public void onCharacteristicRead( @NonNull BluetoothGatt gatt, @NonNull BluetoothGattCharacteristic characteristic, int status) { timeout.unschedule(); if (status == BluetoothGatt.GATT_SUCCESS) { final byte[] value = characteristic.getValue(); subscriber.onNext(value); subscriber.onCompleted(); } else { logger.error( GattPeripheral.LOG_TAG, "Could not read characteristic. " + GattException.statusToString(status), null); subscriber.onError(new GattException(status, Operation.READ)); } gattDispatcher.characteristicRead = null; peripheral.removeDisconnectListener(onDisconnect); } }; if (gatt.readCharacteristic(wrappedCharacteristic)) { timeout.schedule(); } else { gattDispatcher.characteristicRead = null; peripheral.removeDisconnectListener(onDisconnect); subscriber.onError(new GattException(BluetoothGatt.GATT_FAILURE, Operation.READ)); } } }); }
@NonNull @Override public Observable<Void> write( @NonNull final GattPeripheral.WriteType writeType, @NonNull final byte[] payload, @NonNull final OperationTimeout timeout) { if (payload.length > PACKET_LENGTH) { return Observable.error( new IllegalArgumentException( "Payload length " + payload.length + " greater than " + PACKET_LENGTH)); } return peripheral.createObservable( new Observable.OnSubscribe<Void>() { @Override public void call(final Subscriber<? super Void> subscriber) { if (peripheral.getConnectionStatus() != GattPeripheral.STATUS_CONNECTED || peripheral.gatt == null) { subscriber.onError(new ConnectionStateException()); return; } final Runnable onDisconnect = peripheral.addTimeoutDisconnectListener(subscriber, timeout); peripheral.setupTimeout( Operation.ENABLE_NOTIFICATION, timeout, subscriber, onDisconnect); gattDispatcher.characteristicWrite = new CharacteristicWriteListener() { @Override public void onCharacteristicWrite( @NonNull BluetoothGatt gatt, @NonNull BluetoothGattCharacteristic characteristic, int status) { timeout.unschedule(); if (status != BluetoothGatt.GATT_SUCCESS) { logger.error( GattPeripheral.LOG_TAG, "Could not write command " + getUuid() + ", " + GattException.statusToString(status), null); subscriber.onError(new GattException(status, Operation.WRITE_COMMAND)); } else { subscriber.onNext(null); subscriber.onCompleted(); } peripheral.removeDisconnectListener(onDisconnect); gattDispatcher.characteristicWrite = null; } }; final BluetoothGattCharacteristic characteristic = service.wrappedService.getCharacteristic(getUuid()); // Looks like write type might need to be specified for some phones. See // <http://stackoverflow.com/questions/25888817/android-bluetooth-status-133-in-oncharacteristicwrite> characteristic.setWriteType(writeType.value); characteristic.setValue(payload); if (peripheral.gatt.writeCharacteristic(characteristic)) { timeout.schedule(); } else { peripheral.removeDisconnectListener(onDisconnect); gattDispatcher.characteristicWrite = null; subscriber.onError( new GattException( BluetoothGatt.GATT_WRITE_NOT_PERMITTED, Operation.WRITE_COMMAND)); } } }); }
@NonNull @Override public Observable<UUID> disableNotification( @NonNull final UUID descriptor, @NonNull final OperationTimeout timeout) { return peripheral.createObservable( new ConnectedOnSubscribe<UUID>(peripheral) { @Override public void onSubscribe( @NonNull BluetoothGatt gatt, @NonNull final Subscriber<? super UUID> subscriber) { logger.info(GattPeripheral.LOG_TAG, "Unsubscribing from " + getUuid()); final Runnable onDisconnect = peripheral.addTimeoutDisconnectListener(subscriber, timeout); peripheral.setupTimeout( Operation.ENABLE_NOTIFICATION, timeout, subscriber, onDisconnect); gattDispatcher.descriptorWrite = new DescriptorWriteListener() { @Override public void onDescriptorWrite( @NonNull BluetoothGatt gatt, @NonNull BluetoothGattDescriptor descriptor, int status) { if (!Arrays.equals( descriptor.getValue(), BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE)) { return; } timeout.unschedule(); if (status == BluetoothGatt.GATT_SUCCESS) { if (gatt.setCharacteristicNotification(wrappedCharacteristic, false)) { subscriber.onNext(getUuid()); subscriber.onCompleted(); } else { logger.error( GattPeripheral.LOG_TAG, "Could not unsubscribe from characteristic. " + GattException.statusToString(status), null); subscriber.onError( new GattException( BluetoothGatt.GATT_FAILURE, Operation.DISABLE_NOTIFICATION)); } } else { subscriber.onError(new GattException(status, Operation.DISABLE_NOTIFICATION)); } peripheral.removeDisconnectListener(onDisconnect); gattDispatcher.descriptorWrite = null; } }; final BluetoothGattDescriptor descriptorToWrite = wrappedCharacteristic.getDescriptor(descriptor); descriptorToWrite.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE); if (gatt.writeDescriptor(descriptorToWrite)) { timeout.schedule(); } else { peripheral.removeDisconnectListener(onDisconnect); gattDispatcher.descriptorWrite = null; subscriber.onError( new GattException( BluetoothGatt.GATT_WRITE_NOT_PERMITTED, Operation.DISABLE_NOTIFICATION)); } } }); }