BluetoothPeripheral { public boolean setNotify(@NotNull final BluetoothGattCharacteristic characteristic, final boolean enable) { Objects.requireNonNull(characteristic, "no valid characteristic provided"); if (bluetoothGatt == null) { Timber.e("gatt is 'null', ignoring set notify request"); return false; } final BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(CCC_DESCRIPTOR_UUID)); if (descriptor == null) { Timber.e("could not get CCC descriptor for characteristic %s", characteristic.getUuid()); return false; } byte[] value; int properties = characteristic.getProperties(); if ((properties & PROPERTY_NOTIFY) > 0) { value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE; } else if ((properties & PROPERTY_INDICATE) > 0) { value = BluetoothGattDescriptor.ENABLE_INDICATION_VALUE; } else { Timber.e("characteristic %s does not have notify or indicate property", characteristic.getUuid()); return false; } final byte[] finalValue = enable ? value : BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE; boolean result = commandQueue.add(new Runnable() { @Override public void run() { if (!isConnected()) { completedCommand(); return; } if (!bluetoothGatt.setCharacteristicNotification(characteristic, enable)) { Timber.e("setCharacteristicNotification failed for characteristic: %s", characteristic.getUuid()); } currentWriteBytes = finalValue; descriptor.setValue(finalValue); boolean result; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { result = bluetoothGatt.writeDescriptor(descriptor); } else { final BluetoothGattCharacteristic parentCharacteristic = descriptor.getCharacteristic(); final int originalWriteType = parentCharacteristic.getWriteType(); parentCharacteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT); result = bluetoothGatt.writeDescriptor(descriptor); parentCharacteristic.setWriteType(originalWriteType); } if (!result) { Timber.e("writeDescriptor failed for descriptor: %s", descriptor.getUuid()); completedCommand(); } else { nrTries++; } } }); if (result) { nextCommand(); } else { Timber.e("could not enqueue setNotify command"); } return result; } BluetoothPeripheral(@NotNull Context context, @NotNull BluetoothDevice device, @NotNull InternalCallback listener, BluetoothPeripheralCallback peripheralCallback, Handler callbackHandler); boolean createBond(); boolean requestConnectionPriority(final int priority); void cancelConnection(); @NotNull String getAddress(); int getType(); String getName(); int getBondState(); @SuppressWarnings("WeakerAccess") @NotNull List<BluetoothGattService> getServices(); @Nullable BluetoothGattService getService(@NotNull UUID serviceUUID); @Nullable BluetoothGattCharacteristic getCharacteristic(@NotNull UUID serviceUUID, @NotNull UUID characteristicUUID); int getState(); int getCurrentMtu(); boolean isNotifying(@NotNull BluetoothGattCharacteristic characteristic); boolean readCharacteristic(@NotNull final BluetoothGattCharacteristic characteristic); boolean writeCharacteristic(@NotNull final BluetoothGattCharacteristic characteristic, @NotNull final byte[] value, final int writeType); boolean readDescriptor(@NotNull final BluetoothGattDescriptor descriptor); boolean writeDescriptor(@NotNull final BluetoothGattDescriptor descriptor, @NotNull final byte[] value); boolean setNotify(@NotNull final BluetoothGattCharacteristic characteristic, final boolean enable); boolean clearServicesCache(); boolean readRemoteRssi(); boolean requestMtu(final int mtu); @SuppressWarnings("WeakerAccess")
    static final int GATT_SUCCESS; @SuppressWarnings("WeakerAccess")
    static final int GATT_CONN_L2C_FAILURE; @SuppressWarnings("WeakerAccess")
    static final int GATT_CONN_TIMEOUT; @SuppressWarnings("WeakerAccess")
    static final int GATT_READ_NOT_PERMITTED; @SuppressWarnings("WeakerAccess")
    static final int GATT_WRITE_NOT_PERMITTED; @SuppressWarnings("WeakerAccess")
    static final int GATT_INSUFFICIENT_AUTHENTICATION; @SuppressWarnings("WeakerAccess")
    static final int GATT_REQUEST_NOT_SUPPORTED; @SuppressWarnings("WeakerAccess")
    static final int GATT_INSUFFICIENT_ENCRYPTION; @SuppressWarnings("WeakerAccess")
    static final int GATT_CONN_TERMINATE_PEER_USER; @SuppressWarnings("WeakerAccess")
    static final int GATT_CONN_TERMINATE_LOCAL_HOST; @SuppressWarnings("WeakerAccess")
    static final int GATT_CONN_LMP_TIMEOUT; @SuppressWarnings("WeakerAccess")
    static final int BLE_HCI_CONN_TERMINATED_DUE_TO_MIC_FAILURE; @SuppressWarnings("WeakerAccess")
    static final int GATT_CONN_FAIL_ESTABLISH; @SuppressWarnings("WeakerAccess")
    static final int GATT_NO_RESOURCES; @SuppressWarnings("WeakerAccess")
    static final int GATT_INTERNAL_ERROR; @SuppressWarnings("WeakerAccess")
    static final int GATT_BUSY; @SuppressWarnings("WeakerAccess")
    static final int GATT_ERROR; @SuppressWarnings("WeakerAccess")
    static final int GATT_AUTH_FAIL; @SuppressWarnings("WeakerAccess")
    static final int GATT_CONN_CANCEL; @SuppressWarnings("WeakerAccess")
    static final int DEVICE_TYPE_UNKNOWN; @SuppressWarnings("WeakerAccess")
    static final int DEVICE_TYPE_CLASSIC; @SuppressWarnings("WeakerAccess")
    static final int DEVICE_TYPE_LE; @SuppressWarnings("WeakerAccess")
    static final int DEVICE_TYPE_DUAL; @SuppressWarnings("WeakerAccess")
    static final int BOND_NONE; @SuppressWarnings("WeakerAccess")
    static final int BOND_BONDING; @SuppressWarnings("WeakerAccess")
    static final int BOND_BONDED; @SuppressWarnings("WeakerAccess")
    static final int STATE_DISCONNECTED; @SuppressWarnings("WeakerAccess")
    static final int STATE_CONNECTING; @SuppressWarnings("WeakerAccess")
    static final int STATE_CONNECTED; @SuppressWarnings("WeakerAccess")
    static final int STATE_DISCONNECTING; }
@Test public void notifyTest() { BluetoothGattCallback callback = connectAndGetCallback(); BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(UUID.fromString("00002A1C-0000-1000-8000-00805f9b34fb"), PROPERTY_INDICATE,0); peripheral.setNotify(characteristic, true); byte[] originalByteArray = new byte[]{0x01}; characteristic.setValue(originalByteArray); callback.onCharacteristicChanged(gatt, characteristic); ArgumentCaptor<BluetoothPeripheral> captorPeripheral = ArgumentCaptor.forClass(BluetoothPeripheral.class); ArgumentCaptor<byte[]> captorValue = ArgumentCaptor.forClass(byte[].class); ArgumentCaptor<BluetoothGattCharacteristic> captorCharacteristic = ArgumentCaptor.forClass(BluetoothGattCharacteristic.class); ArgumentCaptor<Integer> captorStatus = ArgumentCaptor.forClass(Integer.class); verify(peripheralCallback).onCharacteristicUpdate(captorPeripheral.capture(), captorValue.capture(), captorCharacteristic.capture(), captorStatus.capture()); byte[] value = captorValue.getValue(); assertEquals(0x01, value[0]); assertNotEquals(value, originalByteArray); assertEquals(peripheral, captorPeripheral.getValue()); assertEquals(characteristic, captorCharacteristic.getValue()); assertEquals(GATT_SUCCESS, (int) captorStatus.getValue() ); }