From c4685214d8db34166213ffa373a16af1a99401a5 Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Tue, 27 Jan 2015 21:23:50 +0100 Subject: o Adding 'recently seen' on BtDevice. Updated when scanning. o Removing BtScanResult, it was never used. o Getting MainActivity to listen on device property changed so the UI is properly updated. o Adding a status bar with color to indicate if the device is available, connected or not seen. --- .../main/java/io/trygvis/android/bt/BtDevice.java | 49 +++++++++----- .../main/java/io/trygvis/android/bt/BtPromise.java | 12 +--- .../java/io/trygvis/android/bt/BtScanResult.java | 9 --- .../main/java/io/trygvis/android/bt/BtService.java | 3 + .../io/trygvis/android/bt/DefaultBtService.java | 77 +++++++++++++++------- 5 files changed, 90 insertions(+), 60 deletions(-) delete mode 100644 app/src/main/java/io/trygvis/android/bt/BtScanResult.java (limited to 'app/src/main/java/io/trygvis/android') 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 fd9e2b9..b90ac4f 100644 --- a/app/src/main/java/io/trygvis/android/bt/BtDevice.java +++ b/app/src/main/java/io/trygvis/android/bt/BtDevice.java @@ -15,14 +15,13 @@ import static io.trygvis.android.bt.BtPromise.PromiseResult.detour; import static io.trygvis.android.bt.BtPromise.PromiseResult.fail; import static io.trygvis.android.bt.BtPromise.PromiseResult.waitForNextEvent; -public class BtDevice { +public class BtDevice implements Comparable { private final static String TAG = BtDevice.class.getSimpleName(); private final DefaultBtService btService; private final BluetoothDevice bluetoothDevice; private BluetoothGatt gatt; private Integer rssi; - private BtScanResult scanResult; private A tag; private final String address; @@ -30,6 +29,10 @@ public class BtDevice { private final boolean seenBefore; private final Date firstSeen; private Date lastSeen; + /** + * If seen in last scan. + */ + private boolean recentlySeen; private boolean connected; private final WrappingBluetoothGattCallback wrappingCallback = new WrappingBluetoothGattCallback(); @@ -37,15 +40,15 @@ public class BtDevice { BtDevice(DefaultBtService btService, BluetoothDevice bluetoothDevice, SQLiteDatabase db, BtService.BtDbIntegration btDbIntegration, long id, Integer rssi, - BtScanResult scanResult, boolean seenBefore, Date firstSeen, Date lastSeen) { + boolean seenBefore, Date firstSeen, Date lastSeen, boolean recentlySeen) { this.btService = btService; this.bluetoothDevice = bluetoothDevice; this.id = id; this.rssi = rssi; - this.scanResult = scanResult; this.seenBefore = seenBefore; this.firstSeen = firstSeen; this.lastSeen = lastSeen; + this.recentlySeen = recentlySeen; this.tag = btDbIntegration.createTag(db, this); this.address = bluetoothDevice.getAddress(); @@ -60,7 +63,7 @@ public class BtDevice { } public String getAddress() { - return bluetoothDevice.getAddress(); + return address; } public String getName() { @@ -71,10 +74,6 @@ public class BtDevice { return rssi; } - public BtScanResult getScanResult() { - return scanResult; - } - public boolean isSeenBefore() { return seenBefore; } @@ -91,6 +90,14 @@ public class BtDevice { this.lastSeen = lastSeen; } + public boolean isRecentlySeen() { + return recentlySeen; + } + + public void setRecentlySeen(boolean recentlySeen) { + this.recentlySeen = recentlySeen; + } + /** * The first handler must handle a onDirect(). *

@@ -101,7 +108,7 @@ public class BtDevice { throw new RuntimeException("The current callback is not done."); } - Log.i(TAG, "withConnection(), address=" + bluetoothDevice.getAddress() + ", connected: " + (gatt != null)); + Log.i(TAG, "withConnection(), address=" + address + ", connected: " + (gatt != null)); BtPromise newPromise; if (gatt == null) { @@ -160,7 +167,7 @@ public class BtDevice { @Override public String toString() { - return "BtDevice{address=" + bluetoothDevice.getAddress() + '}'; + return "BtDevice{address=" + address + '}'; } @Override @@ -174,12 +181,17 @@ public class BtDevice { BtDevice other = (BtDevice) o; - return getAddress().equals(other.getAddress()); + return address.equals(other.getAddress()); } @Override public int hashCode() { - return getAddress().hashCode(); + return address.hashCode(); + } + + @Override + public int compareTo(BtDevice that) { + return address.compareTo(that.address); } private class WrappingBluetoothGattCallback extends BluetoothGattCallback { @@ -196,6 +208,11 @@ public class BtDevice { BtDevice.this.connected = status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothGatt.STATE_CONNECTED; + if (oldConnected && BtDevice.this.connected) { + Log.i(TAG, "Wrapping: Extra 'onConnectionStateChange' event, ignoring. gatt=" + gatt); + return; + } + try { if (callback != null) { callback.onConnectionStateChange(gatt, status, newState); @@ -203,14 +220,14 @@ public class BtDevice { } finally { if (!BtDevice.this.connected) { if (oldConnected) { - Log.i(TAG, "Wrapper: Lost connection, removing gatt. gatt=" + gatt); + Log.i(TAG, "Wrapping: Lost connection, removing gatt. gatt=" + gatt); } else { - Log.i(TAG, "Wrapper: Lost connection, was not connected. gatt=" + gatt); + Log.i(TAG, "Wrapping: Lost connection, was not connected. gatt=" + gatt); } BtDevice.this.gatt = null; } else { - Log.i(TAG, "Wrapper: connected"); + Log.i(TAG, "Wrapping: connected"); } } } diff --git a/app/src/main/java/io/trygvis/android/bt/BtPromise.java b/app/src/main/java/io/trygvis/android/bt/BtPromise.java index 50aad13..bffdd19 100644 --- a/app/src/main/java/io/trygvis/android/bt/BtPromise.java +++ b/app/src/main/java/io/trygvis/android/bt/BtPromise.java @@ -371,17 +371,11 @@ public class BtPromise { if (result instanceof Detour) { BtPromise detour = ((Detour) result).promise; - Log.i(TAG, "Adding detour with " + detour.actionQ.size() + " actions."); +// Log.i(TAG, "Adding detour with " + detour.actionQ.size() + " actions."); events.add("detour, action size=" + detour.actionQ.size() + ", " + // "failure size=" + detour.failureQ.size() + ", " + "finally size=" + detour.finallyQ.size()); - Log.i(TAG, "hasNext(): " + hasNext()); - Log.i(TAG, "currentAction: " + currentAction); - if (hasNext()) { - Log.i(TAG, "next action: " + actionQ.get(currentAction).name); - } - // The new promise should probably be stacked on top, so that all of its // finally handlers are executed after the added set concludes and then the // current stack can continue. @@ -389,10 +383,6 @@ public class BtPromise { actionQ.addAll(currentAction, detour.actionQ); // failureQ.addAll(detour.failureQ);B finallyQ.addAll(detour.finallyQ); - Log.i(TAG, "hasNext(): " + hasNext()); - if (hasNext()) { - Log.i(TAG, "next action: " + actionQ.get(currentAction).name); - } result = PromiseResult.continueDirectly(); } diff --git a/app/src/main/java/io/trygvis/android/bt/BtScanResult.java b/app/src/main/java/io/trygvis/android/bt/BtScanResult.java deleted file mode 100644 index c443afa..0000000 --- a/app/src/main/java/io/trygvis/android/bt/BtScanResult.java +++ /dev/null @@ -1,9 +0,0 @@ -package io.trygvis.android.bt; - -public class BtScanResult { - private final byte[] scanRecord; - - public BtScanResult(byte[] scanRecord) { - this.scanRecord = scanRecord; - } -} 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 06857ee..46f1a80 100644 --- a/app/src/main/java/io/trygvis/android/bt/BtService.java +++ b/app/src/main/java/io/trygvis/android/bt/BtService.java @@ -61,5 +61,8 @@ public interface BtService { public void onDeviceConnection(String address) { } + + public void onDevicePropertyUpdated(String address) { + } } } 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 e42e685..2487bd8 100644 --- a/app/src/main/java/io/trygvis/android/bt/DefaultBtService.java +++ b/app/src/main/java/io/trygvis/android/bt/DefaultBtService.java @@ -31,6 +31,7 @@ import io.trygvis.android.Function; import io.trygvis.android.LocalBinder; import io.trygvis.soilmoisture.R; +import static android.bluetooth.BluetoothAdapter.LeScanCallback; import static java.util.Collections.unmodifiableCollection; public class DefaultBtService extends Service implements BtService { @@ -54,6 +55,8 @@ public class DefaultBtService extends Service implements BtService { private boolean scanning = false; + private Scanner scanner = new Scanner(); + // ----------------------------------------------------------------------- // BtService Implementation // ----------------------------------------------------------------------- @@ -111,7 +114,7 @@ public class DefaultBtService extends Service implements BtService { for (String address : addresses) { BluetoothDevice bluetoothDevice = bluetoothAdapter.getRemoteDevice(address); - register(bluetoothDevice, null, null); + register(bluetoothDevice, null, false); } return true; @@ -134,8 +137,9 @@ public class DefaultBtService extends Service implements BtService { handler.postDelayed(this::stopScanning, timeoutMs); } - if (bluetoothAdapter.startLeScan(leScanCallback)) { + if (bluetoothAdapter.startLeScan(scanner)) { scanning = true; + scanner.found.clear(); sendBroadcast(createScanStarted()); return true; } @@ -148,9 +152,22 @@ public class DefaultBtService extends Service implements BtService { Log.d(TAG, "stopScanning"); // This doesn't mind being called twice. - bluetoothAdapter.stopLeScan(leScanCallback); + bluetoothAdapter.stopLeScan(scanner); scanning = false; + for (BtDevice device : devices) { + boolean recentlySeen = scanner.found.contains(device); + Log.i(TAG, "scanner.found.contains(device)=" + recentlySeen + ", " + + "address=" + device.getAddress()); + + boolean old = device.isRecentlySeen(); + device.setRecentlySeen(recentlySeen); + + // Only if it not seen and it wasn't previously seen + if (!recentlySeen && old) { + sendBroadcast(createDevicePropertyUpdated(device.getAddress())); + } + } sendBroadcast(createScanStopped()); } @@ -163,7 +180,7 @@ public class DefaultBtService extends Service implements BtService { } BluetoothDevice bluetoothDevice = bluetoothAdapter.getRemoteDevice(mac); - return register(bluetoothDevice, null, null); + return register(bluetoothDevice, null, false); } @Override @@ -204,16 +221,6 @@ public class DefaultBtService extends Service implements BtService { } } - // ----------------------------------------------------------------------- - // Scanning - // ----------------------------------------------------------------------- - - private BluetoothAdapter.LeScanCallback leScanCallback = (device, rssi, scanRecord) -> { - BtScanResult scanResult = new BtScanResult(scanRecord); - - register(device, rssi, scanResult); - }; - // ----------------------------------------------------------------------- // Service Implementation // ----------------------------------------------------------------------- @@ -278,17 +285,19 @@ public class DefaultBtService extends Service implements BtService { return openOrCreateDatabase("bt-devices", MODE_ENABLE_WRITE_AHEAD_LOGGING, null); } - private BtDevice register(BluetoothDevice bluetoothDevice, Integer rssi, BtScanResult scanResult) { + private BtDevice register(BluetoothDevice bluetoothDevice, Integer rssi, boolean fromScan) { String address = bluetoothDevice.getAddress(); - BtDevice btDevice = findDevice(address); + BtDevice device = findDevice(address); - if (btDevice != null) { - return btDevice; + if (device != null) { + device.setRecentlySeen(true); + sendBroadcast(createDevicePropertyUpdated(device.getAddress())); + return device; } long now = System.currentTimeMillis(); - btDevice = runTx(db -> { + device = runTx(db -> { Cursor cursor = db.query(Tables.T_BT_DEVICE, new String[]{Tables.C_ID, Tables.C_FIRST_SEEN}, Tables.C_ADDRESS + "=?", new String[]{address}, null, null, null); @@ -315,15 +324,15 @@ public class DefaultBtService extends Service implements BtService { Log.i(TAG, "New device: " + address + ", seenBefore=" + seenBefore); cursor.close(); - return new BtDevice<>(this, bluetoothDevice, db, btDbIntegration, id, rssi, scanResult, - seenBefore, firstSeen, lastSeen); + return new BtDevice<>(this, bluetoothDevice, db, btDbIntegration, id, rssi, seenBefore, + firstSeen, lastSeen, fromScan); }); - devices.add(btDevice); + devices.add(device); - sendBroadcast(createNewDevice(btDevice.getAddress())); + sendBroadcast(createNewDevice(device.getAddress())); - return btDevice; + return device; } Intent createScanStarted() { @@ -348,6 +357,12 @@ public class DefaultBtService extends Service implements BtService { putExtra("address", address); } + Intent createDevicePropertyUpdated(String address) { + return new Intent(BtServiceListenerBroadcastReceiver.INTENT_NAME). + putExtra("event", "devicePropertyUpdated"). + putExtra("address", address); + } + public static void dispatchEvent(Intent intent, BtServiceListenerBroadcastReceiver listener) { String event = intent.getStringExtra("event"); Log.i(TAG, "Dispatching event " + intent.getAction() + "/" + event); @@ -361,6 +376,9 @@ public class DefaultBtService extends Service implements BtService { case "newDevice": listener.onNewDevice(intent.getStringExtra("address")); break; + case "devicePropertyUpdated": + listener.onDevicePropertyUpdated(intent.getStringExtra("address")); + break; case "deviceConnection": listener.onDeviceConnection(intent.getStringExtra("address")); break; @@ -377,4 +395,15 @@ public class DefaultBtService extends Service implements BtService { } return null; } + + private class Scanner implements LeScanCallback { + + private List found = new ArrayList<>(); + + @Override + public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) { + BtDevice d = register(device, rssi, true); + found.add(d); + } + } } -- cgit v1.2.3