diff options
Diffstat (limited to 'app/src/main/java/io/trygvis/android/bt')
6 files changed, 301 insertions, 255 deletions
diff --git a/app/src/main/java/io/trygvis/android/bt/BtActionExecutor.java b/app/src/main/java/io/trygvis/android/bt/BtActionExecutor.java index 8cbf87c..984c738 100644 --- a/app/src/main/java/io/trygvis/android/bt/BtActionExecutor.java +++ b/app/src/main/java/io/trygvis/android/bt/BtActionExecutor.java @@ -12,6 +12,9 @@ import java.util.Iterator; import java.util.List; import java.util.Queue; +import io.trygvis.android.F2; +import io.trygvis.android.Function; + import static io.trygvis.android.bt.BtActionExecutor.EventType.onCharacteristicChanged; import static io.trygvis.android.bt.BtActionExecutor.EventType.onCharacteristicRead; import static io.trygvis.android.bt.BtActionExecutor.EventType.onCharacteristicWrite; @@ -19,239 +22,146 @@ import static io.trygvis.android.bt.BtActionExecutor.EventType.onConnectionState import static io.trygvis.android.bt.BtActionExecutor.EventType.onDescriptorRead; import static io.trygvis.android.bt.BtActionExecutor.EventType.onDescriptorWrite; import static io.trygvis.android.bt.BtActionExecutor.EventType.onFailure; +import static io.trygvis.android.bt.BtActionExecutor.EventType.onFinally; import static io.trygvis.android.bt.BtActionExecutor.EventType.onReliableWriteCompleted; import static io.trygvis.android.bt.BtActionExecutor.EventType.onServicesDiscovered; public class BtActionExecutor { private final static String TAG = BtActionExecutor.class.getSimpleName(); private final Queue<BtCallback> actionQ = new ArrayDeque<>(); + private final Queue<BtCallback> failureQ = new ArrayDeque<>(); private final Queue<BtCallback> finallyQ = new ArrayDeque<>(); - private final List<BluetoothGattCallback> remoteRssi = new ArrayList<>(); - - public BtActionExecutor() { - } - - public BtActionExecutor(BtCallback first) { - actionQ.add(first); - } -// public static final BtCallback waitForIt = new BtCallback("Wait for it") { -// @Override -// public boolean onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { -// Log.w(TAG, "wait for it...!"); -// return true; -// } -// }; - -// public synchronized BtActionExecutor onSuccess(BtCallback btCallback) { -// actionQ.add(btCallback); -// return this; -// } - - public synchronized BtActionExecutor onConnectionStateChange(OnConnectionStateChange callback) { + public synchronized BtActionExecutor onConnectionStateChange(F2<BluetoothGatt, Integer, Boolean> callback) { actionQ.add(new BtCallback("onConnectionStateChange") { @Override public boolean onConnectionStateChange(BluetoothGatt gatt, int newState) { - return callback.onConnectionStateChange(gatt, newState); + return callback.apply(gatt, newState); } }); return this; } - public synchronized BtActionExecutor onServicesDiscovered(OnServicesDiscovered callback) { + public synchronized BtActionExecutor onServicesDiscovered(Function<BluetoothGatt, Boolean> callback) { actionQ.add(new BtCallback("onServicesDiscovered") { @Override public boolean onServicesDiscovered(BluetoothGatt gatt) { - return callback.onServicesDiscovered(gatt); + return callback.apply(gatt); } }); return this; } - public synchronized BtActionExecutor onCharacteristicRead(OnCharacteristicRead callback) { + public synchronized BtActionExecutor onCharacteristicRead(F2<BluetoothGatt, BluetoothGattCharacteristic, Boolean> callback) { actionQ.add(new BtCallback("onCharacteristicRead") { @Override public boolean onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { - return callback.onCharacteristicRead(gatt, characteristic); + return callback.apply(gatt, characteristic); } }); return this; } - public synchronized BtActionExecutor onCharacteristicWrite(OnCharacteristicWrite callback) { + public synchronized BtActionExecutor onCharacteristicWrite(F2<BluetoothGatt, BluetoothGattCharacteristic, Boolean> callback) { actionQ.add(new BtCallback("onCharacteristicWrite") { @Override public boolean onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { - return callback.onCharacteristicWrite(gatt, characteristic); + return callback.apply(gatt, characteristic); } }); return this; } - public synchronized BtActionExecutor onCharacteristicChanged(OnCharacteristicChanged callback) { + public synchronized BtActionExecutor onCharacteristicChanged(F2<BluetoothGatt, BluetoothGattCharacteristic, Boolean> callback) { actionQ.add(new BtCallback("onCharacteristicChanged") { @Override public boolean onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { - return callback.onCharacteristicChanged(gatt, characteristic); + return callback.apply(gatt, characteristic); } }); return this; } - public synchronized BtActionExecutor onDescriptorRead(OnDescriptorRead callback) { + public synchronized BtActionExecutor onDescriptorRead(F2<BluetoothGatt, BluetoothGattDescriptor, Boolean> callback) { actionQ.add(new BtCallback("onDescriptorRead") { @Override public boolean onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor) { - return callback.onDescriptorRead(gatt, descriptor); + return callback.apply(gatt, descriptor); } }); return this; } - public synchronized BtActionExecutor onDescriptorWrite(OnDescriptorWrite callback) { + public synchronized BtActionExecutor onDescriptorWrite(F2<BluetoothGatt, BluetoothGattDescriptor, Boolean> callback) { actionQ.add(new BtCallback("onDescriptorWrite") { @Override public boolean onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor) { - return callback.onDescriptorWrite(gatt, descriptor); + return callback.apply(gatt, descriptor); } }); return this; } - public synchronized BtActionExecutor onReliableWriteCompleted(OnReliableWriteCompleted callback) { + public synchronized BtActionExecutor onReliableWriteCompleted(Function<BluetoothGatt, Boolean> callback) { actionQ.add(new BtCallback("onReliableWriteCompleted") { @Override public boolean onReliableWriteCompleted(BluetoothGatt gatt) { - return callback.onReliableWriteCompleted(gatt); + return callback.apply(gatt); } }); return this; } - public synchronized BtActionExecutor onReadRemoteRssi(OnReadRemoteRssi callback) { + public synchronized BtActionExecutor onReadRemoteRssi(F2<BluetoothGatt, Integer, Boolean> callback) { actionQ.add(new BtCallback("onReadRemoteRssi") { @Override public boolean onReadRemoteRssi(BluetoothGatt gatt, int rssi) { - return callback.onReadRemoteRssi(gatt, rssi); + return callback.apply(gatt, rssi); } }); return this; } - public synchronized BtActionExecutor onFailure(OnFailure callback) { - actionQ.add(new BtCallback("onFailure") { + public synchronized BtActionExecutor onFailure(Runnable callback) { + failureQ.add(new BtCallback("onFailure") { @Override public void onFailure() { - callback.onFailure(); + callback.run(); } }); return this; } - public static interface OnConnectionStateChange { - boolean onConnectionStateChange(BluetoothGatt gatt, int newState); - } - - public static interface OnServicesDiscovered { - boolean onServicesDiscovered(BluetoothGatt gatt); - } - - public static interface OnCharacteristicRead { - boolean onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic); - } - - public static interface OnCharacteristicWrite { - boolean onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic); - } - - public static interface OnCharacteristicChanged { - boolean onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic); - } - - public static interface OnDescriptorRead { - boolean onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor); - } - - public static interface OnDescriptorWrite { - boolean onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor); - } - - public static interface OnReliableWriteCompleted { - boolean onReliableWriteCompleted(BluetoothGatt gatt); - } - - public static interface OnReadRemoteRssi { - boolean onReadRemoteRssi(BluetoothGatt gatt, int rssi); - } - - public static interface OnFailure { - void onFailure(); - } - - public synchronized BtActionExecutor addFinally(BtCallback btCallback) { - finallyQ.add(btCallback); + public synchronized BtActionExecutor onFinally(Runnable callback) { + finallyQ.add(new BtCallback("finally") { + @Override + public void onFinally() { + callback.run(); + } + }); return this; } -// public synchronized BtActionExecutor onRemoteRssi(BluetoothGattCallback callback) { -// remoteRssi.add(callback); -// return this; -// } - - void onEvent(EventType key, String values, BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, BluetoothGattDescriptor descriptor, int status, int newState) { - if (status != BluetoothGatt.GATT_SUCCESS) { - Log.w(TAG, "Operation failed: " + key + ", " + values); - doFinally(); - return; - } - - Log.i(TAG, "Bt action completed successfully: callback=" + key); - - BtCallback btCallback; - synchronized (this) { - if (actionQ.isEmpty()) { - Log.d(TAG, "All Bluetooth actions are done"); + public String toString() { + StringBuilder s = new StringBuilder("Queue: "); - doFinally(); - return; - } + Iterator<BtCallback> it = actionQ.iterator(); - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - // ignore + int i = 0; + while (it.hasNext()) { + BtCallback c = it.next(); + if (i > 0) { + s.append(", "); } - btCallback = actionQ.remove(); - Log.i(TAG, "Executing bt action: " + btCallback.name); + s.append(c.name); + i++; } - try { - boolean ok = callCallback(key, gatt, characteristic, descriptor, newState, btCallback); - - if (!ok) { - Log.w(TAG, "The callback don't want to continue."); - doFinally(); - } - - if (actionQ.isEmpty()) { - Log.i(TAG, "The queue is empty"); - } - } catch (NotOverriddenException e) { - Log.w(TAG, "Unexpected callback by listener: " + key); - doFinally(); - } + return s.toString(); } - private void doFinally() { - actionQ.clear(); - - for (BtCallback callback = finallyQ.poll(); callback != null; callback = finallyQ.poll()) { - try { - callCallback(onFailure, null, null, null, 0, callback); - } catch (NotOverriddenException e) { - return; - } - } + public BluetoothGattCallback asCallback() { + return new MyBluetoothGattCallback(); } enum EventType { @@ -264,10 +174,13 @@ public class BtActionExecutor { onDescriptorWrite, onReliableWriteCompleted, + onReadRemoteRssi, + onFailure, + onFinally, } - private Boolean callCallback(EventType key, BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, BluetoothGattDescriptor descriptor, int newState, BtCallback btCallback) { + private static Boolean callCallback(EventType key, BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, BluetoothGattDescriptor descriptor, int newState, BtCallback btCallback) { switch (key) { case onConnectionStateChange: return btCallback.onConnectionStateChange(gatt, newState); @@ -289,78 +202,155 @@ public class BtActionExecutor { case onFailure: btCallback.onFailure(); return null; + case onFinally: + btCallback.onFinally(); + return null; default: Log.w(TAG, "Unknown callback: " + key); return null; } } - public String toString() { - StringBuilder s = new StringBuilder("Queue: "); + private class MyBluetoothGattCallback extends BluetoothGattCallback { - Iterator<BtCallback> it = actionQ.iterator(); + private Queue<BtCallback> initialActionQ = new ArrayDeque<>(actionQ); + private List<String> events = new ArrayList<>(); - int i = 0; - while (it.hasNext()) { - BtCallback c = it.next(); - if (i > 0) { - s.append(", "); - } - s.append(c.name); - i++; - } + void onEvent(EventType key, String values, BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, BluetoothGattDescriptor descriptor, int status, int newState) { + boolean success = status == BluetoothGatt.GATT_SUCCESS; + events.add(key + ", " + values + ", success=" + success); - return s.toString(); - } + Log.i(TAG, "Operation failed: " + key + ", " + values + ", success=" + success); - public BluetoothGattCallback asCallback() { - return new BluetoothGattCallback() { - @Override - public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { - onEvent(onConnectionStateChange, "status=" + status + ", newState=" + newState, gatt, null, null, status, newState); + if (!success) { + doFailure(); + return; } - @Override - public void onServicesDiscovered(BluetoothGatt gatt, int status) { - onEvent(onServicesDiscovered, "status=" + status, gatt, null, null, status, 9); - } + BtCallback btCallback; + synchronized (this) { + if (actionQ.isEmpty()) { + Log.d(TAG, "All Bluetooth actions are done"); - @Override - public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { - onEvent(onCharacteristicRead, "status=" + status + ", characteristic=" + characteristic.getUuid(), gatt, characteristic, null, status, 0); - } + doFinally(); + return; + } - @Override - public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { - onEvent(onCharacteristicWrite, "status=" + status + ", characteristic=" + characteristic.getUuid(), gatt, characteristic, null, status, 0); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + // ignore + } + btCallback = actionQ.remove(); + Log.i(TAG, "Executing bt action: " + btCallback.name); } - @Override - public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { - onEvent(onCharacteristicChanged, "characteristic=" + characteristic.getUuid(), gatt, characteristic, null, BluetoothGatt.GATT_SUCCESS, 0); + try { + boolean ok = callCallback(key, gatt, characteristic, descriptor, newState, btCallback); + + if (!ok) { + Log.w(TAG, "The callback don't want to continue."); + doFinally(); + } + + if (actionQ.isEmpty()) { + Log.i(TAG, "The queue is empty"); + } + } catch (NotOverriddenException e) { + Log.w(TAG, "Unexpected callback by listener: " + key); + doFailure(); } + } - @Override - public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { - onEvent(onDescriptorRead, "status=" + status + ", descriptor=" + descriptor.getUuid(), gatt, null, descriptor, status, 0); + private void doFailure() { + StringBuilder msg = new StringBuilder(); + + msg.append("Expected events: \n"); + for (BtCallback cb : initialActionQ) { + msg.append(" ").append(cb.name).append("\n"); } - @Override - public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { - onEvent(onDescriptorWrite, "status=" + status + ", descriptor=" + descriptor.getUuid(), gatt, null, descriptor, status, 0); + msg.append("Actual events: \n"); + for (String event : events) { + msg.append(" ").append(event).append("\n"); } - @Override - public void onReliableWriteCompleted(BluetoothGatt gatt, int status) { - onEvent(onReliableWriteCompleted, "status=" + status, gatt, null, null, status, 0); + Log.w(TAG, msg.toString()); + + Log.w(TAG, "Executing " + failureQ.size() + " failure handlers"); + + for (BtCallback callback = failureQ.poll(); callback != null; callback = failureQ.poll()) { + try { + callCallback(onFailure, null, null, null, 0, callback); + } catch (NotOverriddenException e) { + return; + } } - @Override - public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { - for (BluetoothGattCallback callback : remoteRssi) { - callback.onReadRemoteRssi(gatt, rssi, status); + doFinally(); + } + + private void doFinally() { + actionQ.clear(); + + Log.w(TAG, "Executing " + finallyQ.size() + " finally handlers"); + + for (BtCallback callback = finallyQ.poll(); callback != null; callback = finallyQ.poll()) { + try { + callCallback(onFinally, null, null, null, 0, callback); + } catch (NotOverriddenException e) { + return; } } - }; + } + + // ----------------------------------------------------------------------- + // + // ----------------------------------------------------------------------- + + @Override + public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { + onEvent(onConnectionStateChange, "status=" + status + ", newState=" + newState, gatt, null, null, status, newState); + } + + @Override + public void onServicesDiscovered(BluetoothGatt gatt, int status) { + onEvent(onServicesDiscovered, "status=" + status, gatt, null, null, status, 9); + } + + @Override + public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { + onEvent(onCharacteristicRead, "status=" + status + ", characteristic=" + characteristic.getUuid(), gatt, characteristic, null, status, 0); + } + + @Override + public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { + onEvent(onCharacteristicWrite, "status=" + status + ", characteristic=" + characteristic.getUuid(), gatt, characteristic, null, status, 0); + } + + @Override + public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { + onEvent(onCharacteristicChanged, "characteristic=" + characteristic.getUuid(), gatt, characteristic, null, BluetoothGatt.GATT_SUCCESS, 0); + } + + @Override + public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { + onEvent(onDescriptorRead, "status=" + status + ", descriptor=" + descriptor.getUuid(), gatt, null, descriptor, status, 0); + } + + @Override + public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { + onEvent(onDescriptorWrite, "status=" + status + ", descriptor=" + descriptor.getUuid(), gatt, null, descriptor, status, 0); + } + + @Override + public void onReliableWriteCompleted(BluetoothGatt gatt, int status) { + onEvent(onReliableWriteCompleted, "status=" + status, gatt, null, null, status, 0); + } + + @Override + public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { +// onEvent(onReadRemoteRssi, "status=" + status, gatt, null, null, status, 0); + } } } diff --git a/app/src/main/java/io/trygvis/android/bt/BtCallback.java b/app/src/main/java/io/trygvis/android/bt/BtCallback.java index 7702962..29ea9e1 100644 --- a/app/src/main/java/io/trygvis/android/bt/BtCallback.java +++ b/app/src/main/java/io/trygvis/android/bt/BtCallback.java @@ -50,4 +50,8 @@ public class BtCallback { public void onFailure() { throw new NotOverriddenException(); } + + public void onFinally() { + throw new NotOverriddenException(); + } } diff --git a/app/src/main/java/io/trygvis/android/bt/BtDevice.java b/app/src/main/java/io/trygvis/android/bt/BtDevice.java index ba10d2d..e34e9ea 100644 --- a/app/src/main/java/io/trygvis/android/bt/BtDevice.java +++ b/app/src/main/java/io/trygvis/android/bt/BtDevice.java @@ -3,6 +3,8 @@ package io.trygvis.android.bt; import android.bluetooth.BluetoothDevice; import android.util.Log; +import io.trygvis.android.Function; + public class BtDevice<A> { private final static String TAG = BtDevice.class.getSimpleName(); @@ -14,31 +16,22 @@ public class BtDevice<A> { private boolean seenNow; - private BtDeviceListener l = null; - - private BtDeviceListener listener = new BtDeviceListener() { - }; + public static interface BtDeviceWrapper<A> { + BtDevice<A> getBtDevice(); + } - public BtDevice(DefaultBtService btService, BluetoothDevice bluetoothDevice, A tag, Integer rssi, BtScanResult scanResult) { + BtDevice(DefaultBtService btService, BluetoothDevice bluetoothDevice, Function<BtDevice<A>, A> tagConstructor, Integer rssi, BtScanResult scanResult) { this.btService = btService; this.bluetoothDevice = bluetoothDevice; - this.tag = tag; + this.tag = tagConstructor.apply(this); this.rssi = rssi; this.scanResult = scanResult; } - public void addListener(BtDeviceListener listener) { - this.l = listener; - } - public A getTag() { return tag; } - public void setTag(A tag) { - this.tag = tag; - } - public String getAddress() { return bluetoothDevice.getAddress(); } @@ -65,4 +58,23 @@ public class BtDevice<A> { 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(); + } } diff --git a/app/src/main/java/io/trygvis/android/bt/BtDeviceListener.java b/app/src/main/java/io/trygvis/android/bt/BtDeviceListener.java deleted file mode 100644 index 57eabc6..0000000 --- a/app/src/main/java/io/trygvis/android/bt/BtDeviceListener.java +++ /dev/null @@ -1,4 +0,0 @@ -package io.trygvis.android.bt; - -public interface BtDeviceListener { -} diff --git a/app/src/main/java/io/trygvis/android/bt/BtService.java b/app/src/main/java/io/trygvis/android/bt/BtService.java index 123be3a..968a4a8 100644 --- a/app/src/main/java/io/trygvis/android/bt/BtService.java +++ b/app/src/main/java/io/trygvis/android/bt/BtService.java @@ -1,12 +1,17 @@ package io.trygvis.android.bt; -import android.os.Binder; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; -import java.util.List; +import java.util.Collection; -public interface BtService<A> { +import io.trygvis.android.Function; - boolean initialize(BtServiceListener<A> btServiceListener, Supplier<A> dataSupplier); +public interface BtService<A extends BtDevice.BtDeviceWrapper<A>> { + + boolean initialize(Function<BtDevice<A>, A> tagConstructor); void clearCache(); @@ -16,40 +21,35 @@ public interface BtService<A> { void stopScanning(); -// BtDevice<A> getDevice(String macAddress); + BtDevice<A> getDevice(String address); - List<BtDevice<A>> getDevices(); + A getTag(String address); - interface Supplier<A> { - A get(); - } + Collection<BtDevice<A>> getDevices(); - interface BtServiceListener<A> { - void onScanStarted(); + Collection<A> getTags(); - void onNewDevice(BtDevice<A> device); + public static class BtServiceListenerBroadcastReceiver extends BroadcastReceiver { - void onScanStopped(); - } + public static final String INTENT_NAME = BtServiceListenerBroadcastReceiver.class.getName(); - public abstract class AbstractBtServiceListener<A> implements BtServiceListener<A> { + public static final IntentFilter INTENT_FILTER = new IntentFilter(INTENT_NAME); - public void onScanStarted() { - } + public void onReceive(Context context, Intent intent) { + if (!intent.getAction().equals(INTENT_NAME)) { + return; + } - public void onScanStopped() { + DefaultBtService.dispatchEvent(intent, this); } - } - public class LocalBinder<A> extends Binder { - private final BtService<A> service; + public void onScanStarted() { + } - public LocalBinder(BtService<A> service) { - this.service = service; + public void onNewDevice(String address) { } - public BtService<A> getService() { - return service; + public void onScanStopped() { } } } diff --git a/app/src/main/java/io/trygvis/android/bt/DefaultBtService.java b/app/src/main/java/io/trygvis/android/bt/DefaultBtService.java index 8638544..51d84af 100644 --- a/app/src/main/java/io/trygvis/android/bt/DefaultBtService.java +++ b/app/src/main/java/io/trygvis/android/bt/DefaultBtService.java @@ -13,12 +13,17 @@ import android.util.Log; import android.widget.Toast; import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; +import io.trygvis.android.Function; +import io.trygvis.android.LocalBinder; import io.trygvis.soilmoisture.R; -public class DefaultBtService<A> extends Service implements BtService<A> { +import static java.util.Collections.unmodifiableCollection; + +public class DefaultBtService<A extends BtDevice.BtDeviceWrapper<A>> extends Service implements BtService<A> { private final static String TAG = DefaultBtService.class.getSimpleName(); private final IBinder binder = new LocalBinder<>(this); @@ -29,19 +34,13 @@ public class DefaultBtService<A> extends Service implements BtService<A> { // State // ----------------------------------------------------------------------- - private BtServiceListener<A> serviceListener = new AbstractBtServiceListener<A>() { - @Override - public void onNewDevice(BtDevice<A> device) { - } - }; - - private Supplier<A> tagConstructor; + private Function<BtDevice<A>, A> tagConstructor; private BluetoothManager bluetoothManager; private BluetoothAdapter bluetoothAdapter; - private final List<BtDevice<A>> devices = new ArrayList<>(); + private final Set<BtDevice<A>> devices = new HashSet<>(); private boolean scanning = false; @@ -50,17 +49,13 @@ public class DefaultBtService<A> extends Service implements BtService<A> { // ----------------------------------------------------------------------- @Override - public boolean initialize(BtServiceListener<A> serviceListener, Supplier<A> dataSupplier) { + public boolean initialize(Function<BtDevice<A>, A> tagConstructor) { if (bluetoothManager != null) { - Log.e(TAG, "Already initialized"); + Log.i(TAG, "Already initialized"); return false; } - this.tagConstructor = dataSupplier; - - if (serviceListener != null) { - this.serviceListener = serviceListener; - } + this.tagConstructor = tagConstructor; // Use this check to determine whether BLE is supported on the device. Then you can // selectively disable BLE-related features. @@ -85,7 +80,7 @@ public class DefaultBtService<A> extends Service implements BtService<A> { return false; } - Log.e(TAG, "Bluetooth initialized"); + Log.i(TAG, "Bluetooth initialized"); return true; } @@ -100,13 +95,15 @@ public class DefaultBtService<A> extends Service implements BtService<A> { @Override public boolean startScanning(long timeoutMs) { + Log.d(TAG, "startScanning, timeoutMs=" + timeoutMs); + if (timeoutMs > 0) { handler.postDelayed(this::stopScanning, timeoutMs); } if (bluetoothAdapter.startLeScan(leScanCallback)) { scanning = true; - serviceListener.onScanStarted(); + sendBroadcast(createScanStarted()); return true; } @@ -115,15 +112,16 @@ public class DefaultBtService<A> extends Service implements BtService<A> { @Override public void stopScanning() { + Log.d(TAG, "stopScanning"); + // This doesn't mind being called twice. bluetoothAdapter.stopLeScan(leScanCallback); scanning = false; - serviceListener.onScanStopped(); + sendBroadcast(createScanStopped()); } -// @Override public BtDevice<A> getDevice(String mac) { BtDevice<A> device = findDevice(mac); @@ -136,8 +134,22 @@ public class DefaultBtService<A> extends Service implements BtService<A> { } @Override - public List<BtDevice<A>> getDevices() { - return Collections.unmodifiableList(devices); + public A getTag(String address) { + return getDevice(address).getTag(); + } + + @Override + public Collection<BtDevice<A>> getDevices() { + return unmodifiableCollection(devices); + } + + @Override + public Collection<A> getTags() { + ArrayList<A> tags = new ArrayList<>(); + for (BtDevice<A> device : devices) { + tags.add(device.getTag()); + } + return tags; } // ----------------------------------------------------------------------- @@ -145,8 +157,6 @@ public class DefaultBtService<A> extends Service implements BtService<A> { // ----------------------------------------------------------------------- private BluetoothAdapter.LeScanCallback leScanCallback = (device, rssi, scanRecord) -> { -// Log.i(TAG, "onLeScan()"); - BtScanResult scanResult = new BtScanResult(scanRecord); register(device, rssi, scanResult); @@ -173,14 +183,48 @@ public class DefaultBtService<A> extends Service implements BtService<A> { } Log.i(TAG, "New device: " + bluetoothDevice.getAddress()); - btDevice = new BtDevice<>(this, bluetoothDevice, tagConstructor.get(), rssi, scanResult); + btDevice = new BtDevice<>(this, bluetoothDevice, tagConstructor, rssi, scanResult); devices.add(btDevice); - serviceListener.onNewDevice(btDevice); + sendBroadcast(createNewDevice(btDevice.getAddress())); return btDevice; } + private Intent createScanStarted() { + return new Intent(BtServiceListenerBroadcastReceiver.INTENT_NAME). + putExtra("event", "scanStarted"); + } + + private Intent createScanStopped() { + return new Intent(BtServiceListenerBroadcastReceiver.INTENT_NAME). + putExtra("event", "scanStopped"); + } + + private Intent createNewDevice(String address) { + return new Intent(BtServiceListenerBroadcastReceiver.INTENT_NAME). + putExtra("event", "newDevice"). + putExtra("address", address); + } + + public static void dispatchEvent(Intent intent, BtServiceListenerBroadcastReceiver listener) { + String event = intent.getStringExtra("event"); + Log.i(TAG, "Dispatching event " + intent.getAction() + "/" + event); + switch (event) { + case "newDevice": + listener.onNewDevice(intent.getStringExtra("address")); + break; + case "scanStarted": + listener.onScanStarted(); + break; + case "scanStopped": + listener.onScanStopped(); + break; + default: + break; + } + } + private BtDevice<A> findDevice(String mac) { for (BtDevice<A> d : devices) { if (d.getAddress().equals(mac)) { |