aboutsummaryrefslogtreecommitdiff
path: root/bt/src/main/java/io/trygvis/android
diff options
context:
space:
mode:
Diffstat (limited to 'bt/src/main/java/io/trygvis/android')
-rw-r--r--bt/src/main/java/io/trygvis/android/Consumer.java5
-rw-r--r--bt/src/main/java/io/trygvis/android/F2.java5
-rw-r--r--bt/src/main/java/io/trygvis/android/F3.java5
-rw-r--r--bt/src/main/java/io/trygvis/android/F4.java5
-rw-r--r--bt/src/main/java/io/trygvis/android/Function.java5
-rw-r--r--bt/src/main/java/io/trygvis/android/Optional.java45
-rw-r--r--bt/src/main/java/io/trygvis/android/Supplier.java5
-rw-r--r--bt/src/main/java/io/trygvis/android/bt/BtBluetoothGattCallback.java73
-rw-r--r--bt/src/main/java/io/trygvis/android/bt/BtCallback.java74
-rw-r--r--bt/src/main/java/io/trygvis/android/bt/BtSequence.java243
-rw-r--r--bt/src/main/java/io/trygvis/android/bt/BtSequencer.java265
-rw-r--r--bt/src/main/java/io/trygvis/android/bt/NotOverriddenException.java4
12 files changed, 734 insertions, 0 deletions
diff --git a/bt/src/main/java/io/trygvis/android/Consumer.java b/bt/src/main/java/io/trygvis/android/Consumer.java
new file mode 100644
index 0000000..bf8c5e5
--- /dev/null
+++ b/bt/src/main/java/io/trygvis/android/Consumer.java
@@ -0,0 +1,5 @@
+package io.trygvis.android;
+
+public interface Consumer<T> {
+ void accept(T t);
+}
diff --git a/bt/src/main/java/io/trygvis/android/F2.java b/bt/src/main/java/io/trygvis/android/F2.java
new file mode 100644
index 0000000..1f362cc
--- /dev/null
+++ b/bt/src/main/java/io/trygvis/android/F2.java
@@ -0,0 +1,5 @@
+package io.trygvis.android;
+
+public interface F2<A, B, C> {
+ C apply(A a, B b);
+}
diff --git a/bt/src/main/java/io/trygvis/android/F3.java b/bt/src/main/java/io/trygvis/android/F3.java
new file mode 100644
index 0000000..30d3adf
--- /dev/null
+++ b/bt/src/main/java/io/trygvis/android/F3.java
@@ -0,0 +1,5 @@
+package io.trygvis.android;
+
+public interface F3<A, B, C, D> {
+ D apply(A a, B b, C c);
+}
diff --git a/bt/src/main/java/io/trygvis/android/F4.java b/bt/src/main/java/io/trygvis/android/F4.java
new file mode 100644
index 0000000..5ff50f5
--- /dev/null
+++ b/bt/src/main/java/io/trygvis/android/F4.java
@@ -0,0 +1,5 @@
+package io.trygvis.android;
+
+public interface F4<A, B, C, D, E> {
+ E apply(A a, B b, C c, D d);
+}
diff --git a/bt/src/main/java/io/trygvis/android/Function.java b/bt/src/main/java/io/trygvis/android/Function.java
new file mode 100644
index 0000000..5e3bb96
--- /dev/null
+++ b/bt/src/main/java/io/trygvis/android/Function.java
@@ -0,0 +1,5 @@
+package io.trygvis.android;
+
+public interface Function<A, B> {
+ B apply(A a);
+}
diff --git a/bt/src/main/java/io/trygvis/android/Optional.java b/bt/src/main/java/io/trygvis/android/Optional.java
new file mode 100644
index 0000000..616f9a7
--- /dev/null
+++ b/bt/src/main/java/io/trygvis/android/Optional.java
@@ -0,0 +1,45 @@
+package io.trygvis.android;
+
+public final class Optional<T> {
+ private final T value;
+
+ public Optional(T value) {
+ this.value = value;
+ }
+
+ public T get() {
+ if (value == null) {
+ throw new IllegalStateException("get() on empty");
+ }
+
+ return value;
+ }
+
+ public boolean isPresent() {
+ return value != null;
+ }
+
+ public void ifPresent(Consumer<T> consumer) {
+ if (value == null) {
+ return;
+ }
+
+ consumer.accept(value);
+ }
+
+ public static <T> Optional<T> of(T t) {
+ if (t == null) {
+ throw new IllegalArgumentException("t can't be null");
+ }
+
+ return new Optional<>(t);
+ }
+
+ public static <T> Optional<T> empty() {
+ return new Optional<>(null);
+ }
+
+ public static <T> Optional<T> ofNullable(T t) {
+ return t != null ? of(t) : empty();
+ }
+}
diff --git a/bt/src/main/java/io/trygvis/android/Supplier.java b/bt/src/main/java/io/trygvis/android/Supplier.java
new file mode 100644
index 0000000..222dff2
--- /dev/null
+++ b/bt/src/main/java/io/trygvis/android/Supplier.java
@@ -0,0 +1,5 @@
+package io.trygvis.android;
+
+public interface Supplier<A> {
+ A get();
+}
diff --git a/bt/src/main/java/io/trygvis/android/bt/BtBluetoothGattCallback.java b/bt/src/main/java/io/trygvis/android/bt/BtBluetoothGattCallback.java
new file mode 100644
index 0000000..1f4921f
--- /dev/null
+++ b/bt/src/main/java/io/trygvis/android/bt/BtBluetoothGattCallback.java
@@ -0,0 +1,73 @@
+package io.trygvis.android.bt;
+
+import android.bluetooth.BluetoothGatt;
+import android.bluetooth.BluetoothGattCallback;
+import android.bluetooth.BluetoothGattCharacteristic;
+import android.bluetooth.BluetoothGattDescriptor;
+
+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.onReliableWriteCompleted;
+import static io.trygvis.android.bt.BtSequencer.EventType.onServicesDiscovered;
+
+public class BtBluetoothGattCallback extends BluetoothGattCallback {
+
+ private final BtSequencer sequencer;
+
+ BtBluetoothGattCallback(BtSequencer sequencer) {
+ this.sequencer = sequencer;
+ }
+
+ // -----------------------------------------------------------------------
+ //
+ // -----------------------------------------------------------------------
+
+ @Override
+ public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
+ sequencer.onEvent(onConnectionStateChange, "status=" + status + ", newState=" + newState, gatt, null, null, status, newState);
+ }
+
+ @Override
+ public void onServicesDiscovered(BluetoothGatt gatt, int status) {
+ sequencer.onEvent(onServicesDiscovered, "status=" + status, gatt, null, null, status, 9);
+ }
+
+ @Override
+ public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
+ sequencer.onEvent(onCharacteristicRead, "status=" + status + ", characteristic=" + characteristic.getUuid(), gatt, characteristic, null, status, 0);
+ }
+
+ @Override
+ public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
+ sequencer.onEvent(onCharacteristicWrite, "status=" + status + ", characteristic=" + characteristic.getUuid(), gatt, characteristic, null, status, 0);
+ }
+
+ @Override
+ public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
+ sequencer.onEvent(onCharacteristicChanged, "characteristic=" + characteristic.getUuid(), gatt, characteristic, null, BluetoothGatt.GATT_SUCCESS, 0);
+ }
+
+ @Override
+ public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
+ sequencer.onEvent(onDescriptorRead, "status=" + status + ", descriptor=" + descriptor.getUuid(), gatt, null, descriptor, status, 0);
+ }
+
+ @Override
+ public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
+ sequencer.onEvent(onDescriptorWrite, "status=" + status + ", descriptor=" + descriptor.getUuid(), gatt, null, descriptor, status, 0);
+ }
+
+ @Override
+ public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
+ sequencer.onEvent(onReliableWriteCompleted, "status=" + status, gatt, null, null, status, 0);
+ }
+
+// @Override
+// public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
+// sequencer.onEvent(onReadRemoteRssi, "status=" + status, gatt, null, null, status, 0);
+// }
+} \ No newline at end of file
diff --git a/bt/src/main/java/io/trygvis/android/bt/BtCallback.java b/bt/src/main/java/io/trygvis/android/bt/BtCallback.java
new file mode 100644
index 0000000..4aa8529
--- /dev/null
+++ b/bt/src/main/java/io/trygvis/android/bt/BtCallback.java
@@ -0,0 +1,74 @@
+package io.trygvis.android.bt;
+
+import android.bluetooth.BluetoothGatt;
+import android.bluetooth.BluetoothGattCharacteristic;
+import android.bluetooth.BluetoothGattDescriptor;
+
+import static io.trygvis.android.bt.BtSequence.SequenceResult;
+import static io.trygvis.android.bt.BtSequencer.EventType;
+
+public class BtCallback {
+ public final boolean stopOnFailure;
+ public final EventType type;
+
+ public BtCallback(boolean stopOnFailure, EventType type) {
+ this.stopOnFailure = stopOnFailure;
+ this.type = type;
+ }
+
+ public SequenceResult onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
+ throw new NotOverriddenException();
+ }
+
+ public SequenceResult onServicesDiscovered(BluetoothGatt gatt) {
+ throw new NotOverriddenException();
+ }
+
+ public SequenceResult onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
+ throw new NotOverriddenException();
+ }
+
+ public SequenceResult onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
+ throw new NotOverriddenException();
+ }
+
+ public SequenceResult onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
+ throw new NotOverriddenException();
+ }
+
+ public SequenceResult onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor) {
+ throw new NotOverriddenException();
+ }
+
+ public SequenceResult onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor) {
+ throw new NotOverriddenException();
+ }
+
+ public SequenceResult onReliableWriteCompleted(BluetoothGatt gatt) {
+ throw new NotOverriddenException();
+ }
+
+ public SequenceResult onReadRemoteRssi(BluetoothGatt gatt, int rssi) {
+ throw new NotOverriddenException();
+ }
+
+ public SequenceResult onDirect(BluetoothGatt value) {
+ throw new NotOverriddenException();
+ }
+
+ public void onFailure() {
+ throw new NotOverriddenException();
+ }
+
+ public void onFinally(boolean success) {
+ throw new NotOverriddenException();
+ }
+
+ @Override
+ public String toString() {
+ return "BtCallback{" +
+ "type='" + type + '\'' +
+ ", stopOnFailure=" + stopOnFailure +
+ '}';
+ }
+}
diff --git a/bt/src/main/java/io/trygvis/android/bt/BtSequence.java b/bt/src/main/java/io/trygvis/android/bt/BtSequence.java
new file mode 100644
index 0000000..be1be4c
--- /dev/null
+++ b/bt/src/main/java/io/trygvis/android/bt/BtSequence.java
@@ -0,0 +1,243 @@
+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<BtCallback> actionQ;
+ private final List<BtCallback> finallyQ;
+ private final Optional<BtSequence> next;
+
+ private Boolean stopOnFailure = true;
+
+ public BtSequence() {
+ actionQ = new ArrayList<>();
+ finallyQ = new ArrayList<>();
+ next = Optional.empty();
+ }
+
+ private BtSequence(List<BtCallback> actionQ, List<BtCallback> finallyQ, Optional<BtSequence> 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<BtCallback> actionQ() {
+ return actionQ.listIterator();
+ }
+
+ public List<BtCallback> finallyQ() {
+ return unmodifiableList(finallyQ);
+ }
+
+ public boolean firstIsOnDirect() {
+ return actionQ.size() > 0 && actionQ.get(0).type == onDirect;
+ }
+
+ public Optional<BtSequence> getNext() {
+ return next;
+ }
+
+ public String toString() {
+ return "actionQ=" + actionQ.size() + ", finallyQ=" + finallyQ.size() + ", has next=" + next.isPresent();
+ }
+
+ private BtSequence add(BtCallback callback) {
+ List<BtCallback> 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<BluetoothGatt, Integer, Integer, SequenceResult> 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<BluetoothGatt, SequenceResult> callback) {
+ return add(new BtCallback(stopOnFailure(), onServicesDiscovered) {
+ @Override
+ public SequenceResult onServicesDiscovered(BluetoothGatt gatt) {
+ return callback.apply(gatt);
+ }
+ });
+ }
+
+ public BtSequence onCharacteristicRead(F2<BluetoothGatt, BluetoothGattCharacteristic, SequenceResult> callback) {
+ return add(new BtCallback(stopOnFailure(), onCharacteristicRead) {
+ @Override
+ public SequenceResult onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
+ return callback.apply(gatt, characteristic);
+ }
+ });
+ }
+
+ public BtSequence onCharacteristicWrite(F2<BluetoothGatt, BluetoothGattCharacteristic, SequenceResult> callback) {
+ return add(new BtCallback(stopOnFailure(), onCharacteristicWrite) {
+ @Override
+ public SequenceResult onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
+ return callback.apply(gatt, characteristic);
+ }
+ });
+ }
+
+ public BtSequence onCharacteristicChanged(F2<BluetoothGatt, BluetoothGattCharacteristic, SequenceResult> callback) {
+ return add(new BtCallback(stopOnFailure(), onCharacteristicChanged) {
+ @Override
+ public SequenceResult onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
+ return callback.apply(gatt, characteristic);
+ }
+ });
+ }
+
+ public BtSequence onDescriptorRead(F2<BluetoothGatt, BluetoothGattDescriptor, SequenceResult> callback) {
+ return add(new BtCallback(stopOnFailure(), onDescriptorRead) {
+ @Override
+ public SequenceResult onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor) {
+ return callback.apply(gatt, descriptor);
+ }
+ });
+ }
+
+ public BtSequence onDescriptorWrite(F2<BluetoothGatt, BluetoothGattDescriptor, SequenceResult> callback) {
+ return add(new BtCallback(stopOnFailure(), onDescriptorWrite) {
+ @Override
+ public SequenceResult onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor) {
+ return callback.apply(gatt, descriptor);
+ }
+ });
+ }
+
+ public BtSequence onReliableWriteCompleted(Function<BluetoothGatt, SequenceResult> callback) {
+ return add(new BtCallback(stopOnFailure(), onReliableWriteCompleted) {
+ @Override
+ public SequenceResult onReliableWriteCompleted(BluetoothGatt gatt) {
+ return callback.apply(gatt);
+ }
+ });
+ }
+
+ public BtSequence onReadRemoteRssi(F2<BluetoothGatt, Integer, SequenceResult> callback) {
+ return add(new BtCallback(stopOnFailure(), onReadRemoteRssi) {
+ @Override
+ public SequenceResult onReadRemoteRssi(BluetoothGatt gatt, int rssi) {
+ return callback.apply(gatt, rssi);
+ }
+ });
+ }
+
+ public BtSequence onDirect(Function<BluetoothGatt, SequenceResult> callback) {
+ return add(new BtCallback(stopOnFailure(), onDirect) {
+ @Override
+ public SequenceResult onDirect(BluetoothGatt value) {
+ return callback.apply(value);
+ }
+ });
+ }
+
+ public BtSequence onFinally(Consumer<Boolean> callback) {
+ List<BtCallback> 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);
+ }
+}
diff --git a/bt/src/main/java/io/trygvis/android/bt/BtSequencer.java b/bt/src/main/java/io/trygvis/android/bt/BtSequencer.java
new file mode 100644
index 0000000..7eecbed
--- /dev/null
+++ b/bt/src/main/java/io/trygvis/android/bt/BtSequencer.java
@@ -0,0 +1,265 @@
+package io.trygvis.android.bt;
+
+import android.bluetooth.BluetoothGatt;
+import android.bluetooth.BluetoothGattCharacteristic;
+import android.bluetooth.BluetoothGattDescriptor;
+import android.util.Log;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.List;
+
+import static io.trygvis.android.bt.BtSequence.ContinueDirectly;
+import static io.trygvis.android.bt.BtSequence.Detour;
+import static io.trygvis.android.bt.BtSequence.Fail;
+import static io.trygvis.android.bt.BtSequence.SequenceResult;
+import static io.trygvis.android.bt.BtSequence.Stop;
+import static io.trygvis.android.bt.BtSequencer.EventType.onDirect;
+import static io.trygvis.android.bt.BtSequencer.EventType.onFinally;
+
+class BtSequencer {
+ private final static String TAG = BtSequencer.class.getSimpleName();
+
+ enum EventType {
+ onConnectionStateChange,
+ onServicesDiscovered,
+ onCharacteristicRead,
+ onCharacteristicWrite,
+ onCharacteristicChanged,
+ onDescriptorRead,
+ onDescriptorWrite,
+ onReliableWriteCompleted,
+
+ onReadRemoteRssi,
+
+ onDirect,
+ onFailure,
+ onFinally,
+ }
+
+ private final String address;
+ private final Deque<BtSequence> sequences = new ArrayDeque<>();
+ private final Deque<Iterator<BtCallback>> iterators = new ArrayDeque<>();
+
+ private Iterator<BtCallback> callbacks;
+ private BtSequence sequence;
+ private List<String> events = new ArrayList<>();
+
+ private boolean finallyDone;
+
+ BtSequencer(String address, BtSequence sequence) {
+ this.address = address;
+ push(sequence);
+ }
+
+ private void pop() {
+ sequence = sequences.pop();
+ callbacks = iterators.pop();
+ }
+
+ private void push(BtSequence sequence) {
+ if (this.sequence != null) {
+ sequences.push(this.sequence);
+ iterators.push(this.callbacks);
+ }
+
+ this.sequence = sequence;
+ this.callbacks = sequence.actionQ();
+ }
+
+ public void onDirect() {
+ onEvent(onDirect, "initial onDirect", null, null, null, BluetoothGatt.GATT_SUCCESS,
+ BluetoothGatt.STATE_CONNECTED);
+ }
+
+ public synchronized void onEvent(EventType key, String values, BluetoothGatt gatt,
+ BluetoothGattCharacteristic characteristic, BluetoothGattDescriptor descriptor,
+ int status, int newState) {
+ if (finallyDone) {
+ Log.w(TAG, "Got event after finally has been executed: " + key + "(" + values + ").");
+ return;
+ }
+
+ boolean success = status == BluetoothGatt.GATT_SUCCESS;
+ events.add(key + "(" + values + "), success=" + success);
+
+ Log.i(TAG, "event: " + key + "(" + values + "), success=" + success);
+
+ BtCallback callback;
+ synchronized (this) {
+ if (!callbacks.hasNext() && sequence.getNext().isPresent()) {
+ Log.i(TAG, "Switching to next sequence");
+
+ doFinally(success, sequence);
+
+ sequence = sequence.getNext().get();
+ callbacks = sequence.actionQ();
+ }
+
+ if (!callbacks.hasNext()) {
+ if (!sequences.isEmpty()) {
+ Log.d(TAG, "Sequence is done, continuing on previous sequence");
+ doFinally(true, sequence);
+ pop();
+ } else {
+ Log.d(TAG, "Sequence is done, no more sequences");
+ doFinally(true);
+ return;
+ }
+ }
+
+ callback = callbacks.next();
+
+ if (!success) {
+ if (callback.stopOnFailure) {
+ doFinally(false);
+ return;
+ } else {
+ Log.i(TAG, "Last status was a failure, but the callback still want it.");
+ }
+ }
+ }
+
+ try {
+ Log.i(TAG, "Executing bt action: " + callback.type);
+ SequenceResult result = callCallback(key, gatt, characteristic, descriptor, status, newState, null,
+ callback);
+
+ if (result instanceof Stop) {
+ Log.i(TAG, "The sequence stopped.");
+ doFinally(true);
+ return;
+ }
+
+ if (result instanceof Fail) {
+ Log.i(TAG, "The sequence failed.");
+ doFinally(false);
+ return;
+ }
+
+ if (result instanceof Detour) {
+ BtSequence detour = ((Detour) result).sequence;
+ Log.i(TAG, "Adding detour: " + detour);
+
+ if (!detour.firstIsOnDirect()) {
+ throw new IllegalArgumentException("The first handler in a detour must be an onDirect.");
+ }
+
+ events.add("detour, " + detour);
+
+ push(detour);
+ onEvent(onDirect, "direct", gatt, null, null, BluetoothGatt.GATT_SUCCESS, 0);
+ return;
+ }
+
+ if (result instanceof ContinueDirectly) {
+ onEvent(onDirect, "direct", gatt, null, null, BluetoothGatt.GATT_SUCCESS, 0);
+ return;
+ }
+
+ if (!callbacks.hasNext()) {
+ if (!sequences.isEmpty()) {
+ Log.d(TAG, "Sequence is done, continuing on previous sequence");
+ doFinally(true, sequence);
+ pop();
+ } else {
+ Log.d(TAG, "Sequence is done, no more sequences");
+ doFinally(true);
+ }
+ }
+ } catch (NotOverriddenException e) {
+ Log.w(TAG, "Unexpected callback by listener: " + key);
+// doFailure();
+ doFinally(false);
+ } catch (Exception e) {
+ Log.w(TAG, "Exception in callback", e);
+// doFailure();
+ doFinally(false);
+ }
+ }
+
+ private void doFinally(boolean success) {
+ finallyDone = true;
+ showEvents();
+
+ doFinally(success, sequence);
+
+ while (!sequences.isEmpty()) {
+ doFinally(success, sequences.pop());
+ }
+ }
+
+ private void doFinally(boolean success, BtSequence s) {
+ List<BtCallback> q = s.finallyQ();
+
+ Log.w(TAG, "Executing " + q.size() + " finally handlers, success=" + success);
+ for (BtCallback callback : q) {
+ try {
+ callCallback(onFinally, null, null, null, 0, 0, success, callback);
+ } catch (NotOverriddenException e) {
+ // ignore
+ }
+ }
+ }
+
+ private void showEvents() {
+ StringBuilder msg = new StringBuilder();
+
+ msg.append("Address: ").append(address).append("\n");
+
+// msg.append("Event handlers: \n");
+// for (BtCallback cb : actionQ) {
+// msg.append("- ").append(cb.name).append("\n");
+// }
+//
+// msg.append("Finally handlers: \n");
+// for (BtCallback cb : finallyQ) {
+// msg.append("- ").append(cb.name).append("\n");
+// }
+
+ msg.append("Events received: \n");
+ for (String event : events) {
+ msg.append("- ").append(event).append("\n");
+ }
+
+ Log.w(TAG, msg.toString());
+ }
+
+ private static SequenceResult callCallback(EventType key, BluetoothGatt gatt,
+ BluetoothGattCharacteristic characteristic,
+ BluetoothGattDescriptor descriptor, int status, int newState,
+ Boolean success, BtCallback btCallback) {
+ switch (key) {
+ case onConnectionStateChange:
+ return btCallback.onConnectionStateChange(gatt, status, newState);
+ case onServicesDiscovered:
+ return btCallback.onServicesDiscovered(gatt);
+ case onCharacteristicRead:
+ return btCallback.onCharacteristicRead(gatt, characteristic);
+ case onCharacteristicWrite:
+ return btCallback.onCharacteristicWrite(gatt, characteristic);
+ case onCharacteristicChanged:
+ return btCallback.onCharacteristicChanged(gatt, characteristic);
+ case onDescriptorRead:
+ return btCallback.onDescriptorRead(gatt, descriptor);
+ case onDescriptorWrite:
+ return btCallback.onDescriptorWrite(gatt, descriptor);
+ case onReliableWriteCompleted:
+ return btCallback.onReliableWriteCompleted(gatt);
+
+ case onDirect:
+ return btCallback.onDirect(gatt);
+ case onFailure:
+ btCallback.onFailure();
+ return null;
+ case onFinally:
+ btCallback.onFinally(success);
+ return null;
+ default:
+ Log.w(TAG, "Unknown callback: " + key);
+ return null;
+ }
+ }
+}
diff --git a/bt/src/main/java/io/trygvis/android/bt/NotOverriddenException.java b/bt/src/main/java/io/trygvis/android/bt/NotOverriddenException.java
new file mode 100644
index 0000000..0f2bb6a
--- /dev/null
+++ b/bt/src/main/java/io/trygvis/android/bt/NotOverriddenException.java
@@ -0,0 +1,4 @@
+package io.trygvis.android.bt;
+
+class NotOverriddenException extends RuntimeException {
+}