* Services will be discovered. */ public synchronized void withConnection(BtPromise promise) { if (callback != null) { throw new RuntimeException("The current callback is not done."); } Log.i(TAG, "withConnection(), address=" + bluetoothDevice.getAddress() + ", connected: " + (gatt != null)); BtPromise newPromise; if (gatt == null) { newPromise = new BtPromise(). ignoreFailureForNext(). onConnectionStateChange((gatt, status, newState) -> { Log.i(TAG, "defaultConnectCallback: status=" + status + ", newState=" + newState); btService.sendBroadcast(btService.createDeviceConnection(address)); if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothGatt.STATE_CONNECTED) { Log.i(TAG, "Connected to " + address + ", discovering services"); return gatt.discoverServices() ? waitForNextEvent() : fail(); } else { Log.i(TAG, "Could not connect to " + address + ", trying again"); return detour(new BtPromise().onConnectionStateChange((gatt2, status2, newState2) -> { if (status2 == BluetoothGatt.GATT_SUCCESS && newState2 == BluetoothGatt.STATE_CONNECTED) { Log.i(TAG, "Connected to " + address + ", discovering services"); return gatt.discoverServices() ? waitForNextEvent() : fail(); } Log.i(TAG, "Could still not connect to " + address + ", failing."); return fail(); })); } }). onServicesDiscovered(gatt -> { Log.i(TAG, "Services discovered, has " + gatt.getServices().size() + " services"); return detour(promise); }); } else { newPromise = promise; } callback = newPromise. onFinally(() -> { Log.i(TAG, "Promise done, device is available again: address=" + address); callback = null; }). asCallback(bluetoothDevice.getAddress()); if (gatt == null) { gatt = bluetoothDevice.connectGatt(btService, false, wrappingCallback); } else { callback.onEvent(BtPromise.EventType.onDirect, "", gatt, null, null, BluetoothGatt.GATT_SUCCESS, BluetoothGatt.STATE_CONNECTED); } } public boolean connected() { return connected; } @Override public String toString() { return "BtDevice{address=" + bluetoothDevice.getAddress() + '}'; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } BtDevice other = (BtDevice) o; return getAddress().equals(other.getAddress()); } @Override public int hashCode() { return getAddress().hashCode(); } private class WrappingBluetoothGattCallback extends BluetoothGattCallback { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { Log.i(TAG, "Wrapping: onConnectionStateChange: " + "address=" + gatt.getDevice().getAddress() + ", " + "status=" + status + ", " + "newState=" + newState); boolean oldConnected = connected; BtDevice.this.connected = status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothGatt.STATE_CONNECTED; try { if (callback != null) { callback.onConnectionStateChange(gatt, status, newState); } } finally { if (!BtDevice.this.connected) { if (oldConnected) { Log.i(TAG, "Wrapper: Lost connection, removing gatt. gatt=" + gatt); } else { Log.i(TAG, "Wrapper: Lost connection, was not connected. gatt=" + gatt); } BtDevice.this.gatt = null; } else { Log.i(TAG, "Wrapper: connected"); } } } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { if (callback != null) { callback.onServicesDiscovered(gatt, status); } } @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { if (callback != null) { callback.onCharacteristicRead(gatt, characteristic, status); } } @Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { if (callback != null) { callback.onCharacteristicWrite(gatt, characteristic, status); } } @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { if (callback != null) { callback.onCharacteristicChanged(gatt, characteristic); } } @Override public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { if (callback != null) { callback.onDescriptorRead(gatt, descriptor, status); } } @Override public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { if (callback != null) { callback.onDescriptorWrite(gatt, descriptor, status); } } @Override public void onReliableWriteCompleted(BluetoothGatt gatt, int status) { if (callback != null) { callback.onReliableWriteCompleted(gatt, status); } } @Override public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { if (callback != null) { callback.onReadRemoteRssi(gatt, rssi, status); } } } }