package io.trygvis.android.bt; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattDescriptor; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; import io.trygvis.android.Consumer; import io.trygvis.android.F2; import io.trygvis.android.F3; import io.trygvis.android.Function; import io.trygvis.android.Optional; import static io.trygvis.android.bt.BtSequencer.EventType.onCharacteristicChanged; import static io.trygvis.android.bt.BtSequencer.EventType.onCharacteristicRead; import static io.trygvis.android.bt.BtSequencer.EventType.onCharacteristicWrite; import static io.trygvis.android.bt.BtSequencer.EventType.onConnectionStateChange; import static io.trygvis.android.bt.BtSequencer.EventType.onDescriptorRead; import static io.trygvis.android.bt.BtSequencer.EventType.onDescriptorWrite; import static io.trygvis.android.bt.BtSequencer.EventType.onDirect; import static io.trygvis.android.bt.BtSequencer.EventType.onFinally; import static io.trygvis.android.bt.BtSequencer.EventType.onReadRemoteRssi; import static io.trygvis.android.bt.BtSequencer.EventType.onReliableWriteCompleted; import static io.trygvis.android.bt.BtSequencer.EventType.onServicesDiscovered; import static java.util.Collections.unmodifiableList; public class BtSequence { private static final SequenceResult waitForNextEvent = new WaitForNextEvent(); private static final SequenceResult stop = new Stop(); private static final SequenceResult fail = new Fail(); private static final SequenceResult continueDirectly = new ContinueDirectly(); public static class SequenceResult { private SequenceResult() { } public static SequenceResult waitForNextEvent() { return waitForNextEvent; } public static SequenceResult continueDirectly() { return continueDirectly; } public static SequenceResult stop() { return stop; } public static SequenceResult fail() { return fail; } public static SequenceResult detour(BtSequence sequence) { return new Detour(sequence); } } public static class WaitForNextEvent extends SequenceResult { } public static class ContinueDirectly extends SequenceResult { } public static class Stop extends SequenceResult { } public static class Fail extends SequenceResult { } public static class Detour extends SequenceResult { final BtSequence sequence; private Detour(BtSequence sequence) { this.sequence = sequence; } } private final List actionQ; private final List finallyQ; private final Optional next; private Boolean stopOnFailure = true; public BtSequence() { actionQ = new ArrayList<>(); finallyQ = new ArrayList<>(); next = Optional.empty(); } private BtSequence(List actionQ, List finallyQ, Optional next) { this.actionQ = actionQ; this.finallyQ = finallyQ; this.next = next; } public BtSequence andThen(BtSequence btSequence) { return new BtSequence(actionQ, finallyQ, Optional.of(btSequence)); } public ListIterator actionQ() { return actionQ.listIterator(); } public List finallyQ() { return unmodifiableList(finallyQ); } public boolean firstIsOnDirect() { return actionQ.size() > 0 && actionQ.get(0).type == onDirect; } public Optional getNext() { return next; } public String toString() { return "actionQ=" + actionQ.size() + ", finallyQ=" + finallyQ.size() + ", has next=" + next.isPresent(); } private BtSequence add(BtCallback callback) { List actions = new ArrayList<>(this.actionQ); actions.add(callback); return new BtSequence(actions, finallyQ, next); } private boolean stopOnFailure() { if (stopOnFailure != null) { boolean b = stopOnFailure; stopOnFailure = null; return b; } return false; } public BtSequence ignoreFailureForNext() { stopOnFailure = true; return this; } public BtSequence onConnectionStateChange(F3 callback) { return add(new BtCallback(stopOnFailure(), onConnectionStateChange) { @Override public SequenceResult onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { return callback.apply(gatt, status, newState); } }); } public BtSequence onServicesDiscovered(Function callback) { return add(new BtCallback(stopOnFailure(), onServicesDiscovered) { @Override public SequenceResult onServicesDiscovered(BluetoothGatt gatt) { return callback.apply(gatt); } }); } public BtSequence onCharacteristicRead(F2 callback) { return add(new BtCallback(stopOnFailure(), onCharacteristicRead) { @Override public SequenceResult onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { return callback.apply(gatt, characteristic); } }); } public BtSequence onCharacteristicWrite(F2 callback) { return add(new BtCallback(stopOnFailure(), onCharacteristicWrite) { @Override public SequenceResult onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { return callback.apply(gatt, characteristic); } }); } public BtSequence onCharacteristicChanged(F2 callback) { return add(new BtCallback(stopOnFailure(), onCharacteristicChanged) { @Override public SequenceResult onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { return callback.apply(gatt, characteristic); } }); } public BtSequence onDescriptorRead(F2 callback) { return add(new BtCallback(stopOnFailure(), onDescriptorRead) { @Override public SequenceResult onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor) { return callback.apply(gatt, descriptor); } }); } public BtSequence onDescriptorWrite(F2 callback) { return add(new BtCallback(stopOnFailure(), onDescriptorWrite) { @Override public SequenceResult onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor) { return callback.apply(gatt, descriptor); } }); } public BtSequence onReliableWriteCompleted(Function callback) { return add(new BtCallback(stopOnFailure(), onReliableWriteCompleted) { @Override public SequenceResult onReliableWriteCompleted(BluetoothGatt gatt) { return callback.apply(gatt); } }); } public BtSequence onReadRemoteRssi(F2 callback) { return add(new BtCallback(stopOnFailure(), onReadRemoteRssi) { @Override public SequenceResult onReadRemoteRssi(BluetoothGatt gatt, int rssi) { return callback.apply(gatt, rssi); } }); } public BtSequence onDirect(Function callback) { return add(new BtCallback(stopOnFailure(), onDirect) { @Override public SequenceResult onDirect(BluetoothGatt value) { return callback.apply(value); } }); } public BtSequence onFinally(Consumer callback) { List finallyQ = new ArrayList<>(this.finallyQ); finallyQ.add(new BtCallback(stopOnFailure(), onFinally) { @Override public void onFinally(boolean success) { callback.accept(success); } }); return new BtSequence(actionQ, finallyQ, next); } }