I am building an Android application that has specific requirements regarding Bluetooth Low Energy.
I need to write to a Write-only characteristic and receive responses on a separate notification characteristic, and I need to do it in many, many activities. Is there a Rx way to send a request on the 1st characteristic, wait for the answer on the second one, then proceed to another request?
Also, to share my instance of RxAndroidBle I thought about doing some sort of BleManager Singleton where I would expose the Observables, so I can easily subscribe to them in my Presenter. I just want to avoid having to copy the connection logic for each activity and have (ideally) a persistant connection. This way I could only expose the connectionObservable and subscribe to it, so I can easily send Write Requests and get Notifications, but I am sure there is a better way to do it.
This is what I have for now:
@Singleton public class BleManager { private PublishSubject disconnectTriggerSubject = PublishSubject.create(); private Observable connectionObservable; private boolean isConnected; private final UUID CTRL_FROM_BRIDGE_UUID = UUID.fromString("someUUID"); private final UUID BLE_WRITE_CHARACTERISTIC_UUID = UUID.fromString("someOtherUUID"); private final RxBleClient bleClient; private String mMacAddress; private final Context context; private RxBleDevice bleDevice; @Inject public BleManager(Context context, RxBleClient client) { Timber.d("Constructing BleManager and injecting members"); this.context = context; this.bleClient = client; } public void setMacAddress(String mMacAddress) { this.mMacAddress = mMacAddress; // Set the associated device on MacAddress change bleDevice = bleClient.getBleDevice(this.mMacAddress); } public String getMacAddress() { return mMacAddress; } public RxBleDevice getBleDevice() { Preconditions.checkNotNull(mMacAddress); return bleClient.getBleDevice(mMacAddress); } public Observable getScanSubscription() { Preconditions.checkNotNull(context); Preconditions.checkNotNull(bleClient); return bleClient.scanBleDevices().distinct(); } public Observable getConnectionSubscription() { Preconditions.checkNotNull(context); Preconditions.checkNotNull(bleDevice); if (connectionObservable == null) { connectionObservable = bleDevice.establishConnection(context, false) .takeUntil(disconnectTriggerSubject) .observeOn(AndroidSchedulers.mainThread()) .doOnUnsubscribe(this::clearSubscription) .compose(new ConnectionSharingAdapter()); } return connectionObservable; } public Observable setupListeners() { return connectionObservable.flatMap(rxBleConnection -> rxBleConnection.setupNotification(CTRL_FROM_BRIDGE_UUID)) .doOnNext(notificationObservable -> Timber.d("Notification Setup")) .flatMap(notificationObservable -> notificationObservable) .observeOn(AndroidSchedulers.mainThread()); } private void triggerDisconnect() { disconnectTriggerSubject.onNext(null); } public Observable writeBytes(byte[] bytes) { return connectionObservable.flatMap(rxBleConnection -> rxBleConnection.writeCharacteristic( BLE_WRITE_CHARACTERISTIC_UUID, bytes)).observeOn(AndroidSchedulers.mainThread()); } private boolean isConnected() { return bleDevice.getConnectionState() == RxBleConnection.RxBleConnectionState.CONNECTED; } /** * Will update the UI with the current state of the Ble Connection */ private void registerConnectionStateChange() { bleDevice.observeConnectionStateChanges().observeOn(AndroidSchedulers.mainThread()).subscribe(connectionState -> { isConnected = connectionState.equals(RxBleConnection.RxBleConnectionState.CONNECTED); }); } private void clearSubscription() { connectionObservable = null; } }