From 8d47f9b968f21663e2eb3b7f7c6abe8bf7b47b0b Mon Sep 17 00:00:00 2001 From: Erik Johansson Date: Sun, 7 Oct 2018 22:26:40 +0200 Subject: [PATCH] Try to run all ble commands on the main thread --- .../bluetooth/BluetoothCommunication.java | 350 +++++++++--------- 1 file changed, 175 insertions(+), 175 deletions(-) diff --git a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothCommunication.java b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothCommunication.java index 8abe809a..e6d42d0a 100644 --- a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothCommunication.java +++ b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothCommunication.java @@ -80,7 +80,6 @@ public abstract class BluetoothCommunication { private Queue> descriptorRequestQueue; private Queue> characteristicRequestQueue; private boolean openRequest; - private final Object lock = new Object(); public BluetoothCommunication(Context context) { @@ -240,10 +239,8 @@ public abstract class BluetoothCommunication { * @param btMachineState the machine state that should be set. */ protected void setBtMachineState(BT_MACHINE_STATE btMachineState) { - synchronized (lock) { - this.btMachineState = btMachineState; - handleRequests(); - } + this.btMachineState = btMachineState; + handleRequests(); } /** @@ -254,13 +251,11 @@ public abstract class BluetoothCommunication { * @param bytes the bytes that should be write */ protected void writeBytes(UUID service, UUID characteristic, byte[] bytes) { - synchronized (lock) { - characteristicRequestQueue.add( - new GattObjectValue<>( - bluetoothGatt.getService(service).getCharacteristic(characteristic), - bytes)); - handleRequests(); - } + characteristicRequestQueue.add( + new GattObjectValue<>( + bluetoothGatt.getService(service).getCharacteristic(characteristic), + bytes)); + handleRequests(); } /** @@ -301,13 +296,11 @@ public abstract class BluetoothCommunication { bluetoothGatt.getService(service).getCharacteristic(characteristic); bluetoothGatt.setCharacteristicNotification(gattCharacteristic, true); - synchronized (lock) { - descriptorRequestQueue.add( - new GattObjectValue<>( - gattCharacteristic.getDescriptor(descriptor), - BluetoothGattDescriptor.ENABLE_INDICATION_VALUE)); - handleRequests(); - } + descriptorRequestQueue.add( + new GattObjectValue<>( + gattCharacteristic.getDescriptor(descriptor), + BluetoothGattDescriptor.ENABLE_INDICATION_VALUE)); + handleRequests(); } catch (Exception e) { Timber.e(e); @@ -328,13 +321,11 @@ public abstract class BluetoothCommunication { bluetoothGatt.getService(service).getCharacteristic(characteristic); bluetoothGatt.setCharacteristicNotification(gattCharacteristic, true); - synchronized (lock) { - descriptorRequestQueue.add( - new GattObjectValue<>( - gattCharacteristic.getDescriptor(descriptor), - BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE)); - handleRequests(); - } + descriptorRequestQueue.add( + new GattObjectValue<>( + gattCharacteristic.getDescriptor(descriptor), + BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE)); + handleRequests(); } catch (Exception e) { Timber.e(e); @@ -354,13 +345,11 @@ public abstract class BluetoothCommunication { bluetoothGatt.getService(service).getCharacteristic(characteristic); bluetoothGatt.setCharacteristicNotification(gattCharacteristic, false); - synchronized (lock) { - descriptorRequestQueue.add( - new GattObjectValue<>( - gattCharacteristic.getDescriptor(descriptor), - BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE)); - handleRequests(); - } + descriptorRequestQueue.add( + new GattObjectValue<>( + gattCharacteristic.getDescriptor(descriptor), + BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE)); + handleRequests(); } /** @@ -415,6 +404,8 @@ public abstract class BluetoothCommunication { * @param hwAddress the Bluetooth address to connect to */ public void connect(String hwAddress) { + disconnect(false); + logBluetoothStatus(); // Some good tips to improve BLE connections: @@ -481,6 +472,7 @@ public abstract class BluetoothCommunication { if (!device.getAddress().equals(hwAddress)) { return; } + // Stop scan and connect to the device on the main thread handler.post(new Runnable() { @Override public void run() { @@ -496,14 +488,13 @@ public abstract class BluetoothCommunication { Timber.d("Starting LE scan for device [%s]", hwAddress); btAdapter.startLeScan(leScanCallback); + // Stop scan and try to connect to the device directly if the device isn't found in time handler.postAtTime(new Runnable() { @Override public void run() { Timber.d("Device not found in LE scan, connecting directly"); - synchronized (lock) { - stopLeScan(); - connectGatt(hwAddress); - } + stopLeScan(); + connectGatt(hwAddress); } }, leScanCallback, SystemClock.uptimeMillis() + LE_SCAN_TIMEOUT_MS); } @@ -521,42 +512,39 @@ public abstract class BluetoothCommunication { * Disconnect from a Bluetooth device */ public void disconnect(boolean doCleanup) { - synchronized (lock) { - stopLeScan(); + stopLeScan(); - if (bluetoothGatt == null) { - return; - } - - Timber.i("Disconnecting%s", doCleanup ? " (with cleanup)" : ""); - - handler.removeCallbacksAndMessages(null); - callbackBtHandler = null; - - if (doCleanup) { - if (btMachineState != BT_MACHINE_STATE.BT_CLEANUP_STATE) { - setBtMachineState(BT_MACHINE_STATE.BT_CLEANUP_STATE); - nextMachineStateStep(); - } - handler.post(new Runnable() { - @Override - public void run() { - synchronized (lock) { - if (openRequest) { - handler.postDelayed(this, 10); - } else { - bluetoothGatt.close(); - bluetoothGatt = null; - } - } - } - }); - } - else { - bluetoothGatt.close(); - bluetoothGatt = null; - } + if (bluetoothGatt == null) { + return; } + + Timber.i("Disconnecting%s", doCleanup ? " (with cleanup)" : ""); + + if (doCleanup) { + if (btMachineState != BT_MACHINE_STATE.BT_CLEANUP_STATE) { + setBtMachineState(BT_MACHINE_STATE.BT_CLEANUP_STATE); + nextMachineStateStep(); + } + handler.post(new Runnable() { + @Override + public void run() { + if (openRequest) { + handler.postDelayed(this, 10); + } else { + bluetoothGatt.close(); + bluetoothGatt = null; + handler.removeCallbacksAndMessages(null); + } + } + }); + } + else { + bluetoothGatt.close(); + bluetoothGatt = null; + } + + handler.removeCallbacksAndMessages(null); + callbackBtHandler = null; } /** @@ -586,49 +574,48 @@ public abstract class BluetoothCommunication { } private void handleRequests() { - synchronized (lock) { - // check for pending request - if (openRequest) { - Timber.d("Request pending (queue %d %d)", - descriptorRequestQueue.size(), characteristicRequestQueue.size()); - return; // yes, do nothing - } - - // handle descriptor requests first - GattObjectValue descriptor = descriptorRequestQueue.poll(); - if (descriptor != null) { - descriptor.gattObject.setValue(descriptor.value); - - Timber.d("Write descriptor %s: %s (queue: %d %d)", - descriptor.gattObject.getUuid(), byteInHex(descriptor.gattObject.getValue()), - descriptorRequestQueue.size(), characteristicRequestQueue.size()); - if (!bluetoothGatt.writeDescriptor(descriptor.gattObject)) { - Timber.e("Failed to initiate write of descriptor %s", - descriptor.gattObject.getUuid()); - } - openRequest = true; - return; - } - - // handle characteristics requests second - GattObjectValue characteristic = characteristicRequestQueue.poll(); - if (characteristic != null) { - characteristic.gattObject.setValue(characteristic.value); - - Timber.d("Write characteristic %s: %s (queue: %d %d)", - characteristic.gattObject.getUuid(), byteInHex(characteristic.gattObject.getValue()), - descriptorRequestQueue.size(), characteristicRequestQueue.size()); - if (!bluetoothGatt.writeCharacteristic(characteristic.gattObject)) { - Timber.e("Failed to initiate write of characteristic %s", - characteristic.gattObject.getUuid()); - } - openRequest = true; - return; - } - - // After every command was executed, continue with the next step - nextMachineStateStep(); + // check for pending request + if (openRequest) { + Timber.d("Request pending (queue %d %d)", + descriptorRequestQueue.size(), characteristicRequestQueue.size()); + return; // yes, do nothing } + + // handle descriptor requests first + GattObjectValue descriptor = descriptorRequestQueue.poll(); + if (descriptor != null) { + descriptor.gattObject.setValue(descriptor.value); + + Timber.d("Write descriptor %s: %s (queue: %d %d)", + descriptor.gattObject.getUuid(), byteInHex(descriptor.gattObject.getValue()), + descriptorRequestQueue.size(), characteristicRequestQueue.size()); + if (!bluetoothGatt.writeDescriptor(descriptor.gattObject)) { + Timber.e("Failed to initiate write of descriptor %s", + descriptor.gattObject.getUuid()); + } + openRequest = true; + return; + } + + // handle characteristics requests second + GattObjectValue characteristic = characteristicRequestQueue.poll(); + if (characteristic != null) { + characteristic.gattObject.setValue(characteristic.value); + + Timber.d("Write characteristic %s: %s (type: %d; queue: %d %d)", + characteristic.gattObject.getUuid(), byteInHex(characteristic.gattObject.getValue()), + characteristic.gattObject.getWriteType(), + descriptorRequestQueue.size(), characteristicRequestQueue.size()); + if (!bluetoothGatt.writeCharacteristic(characteristic.gattObject)) { + Timber.e("Failed to initiate write of characteristic %s", + characteristic.gattObject.getUuid()); + } + openRequest = true; + return; + } + + // After every command was executed, continue with the next step + nextMachineStateStep(); } /** @@ -640,34 +627,42 @@ public abstract class BluetoothCommunication { Timber.d("onConnectionStateChange: status=%d, newState=%d", status, newState); if (newState == BluetoothProfile.STATE_CONNECTED) { - synchronized (lock) { - stopLeScan(); - } + handler.post(new Runnable() { + @Override + public void run() { + stopLeScan(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - gatt.readPhy(); - } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + gatt.readPhy(); + } - connectionEstablished = true; - setBtStatus(BT_STATUS_CODE.BT_CONNECTION_ESTABLISHED); + connectionEstablished = true; + setBtStatus(BT_STATUS_CODE.BT_CONNECTION_ESTABLISHED); + } + }); - try { - Thread.sleep(1000); - } - catch (Exception e) { - // Empty - } - if (!gatt.discoverServices()) { - Timber.e("Could not start service discovery"); - setBtStatus(BT_STATUS_CODE.BT_CONNECTION_LOST); - disconnect(false); - } + // Wait a short while after connecting before scanning for services + handler.postDelayed(new Runnable() { + @Override + public void run() { + if (!gatt.discoverServices()) { + Timber.e("Could not start service discovery"); + setBtStatus(BT_STATUS_CODE.BT_CONNECTION_LOST); + disconnect(false); + } + } + }, 1000); } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { - setBtStatus(connectionEstablished - ? BT_STATUS_CODE.BT_CONNECTION_LOST - : BT_STATUS_CODE.BT_NO_DEVICE_FOUND); - disconnect(false); + handler.post(new Runnable() { + @Override + public void run() { + setBtStatus(connectionEstablished + ? BT_STATUS_CODE.BT_CONNECTION_LOST + : BT_STATUS_CODE.BT_NO_DEVICE_FOUND); + disconnect(false); + } + }); } } @@ -677,34 +672,35 @@ public abstract class BluetoothCommunication { status, gatt.getServices().size()); if (gatt.getServices().isEmpty()) { - setBtStatus(BT_STATUS_CODE.BT_UNEXPECTED_ERROR, "No services found"); - disconnect(false); + handler.post(new Runnable() { + @Override + public void run() { + setBtStatus(BT_STATUS_CODE.BT_UNEXPECTED_ERROR, "No services found"); + disconnect(false); + } + }); return; } - synchronized (lock) { - cmdStepNr = 0; - initStepNr = 0; - cleanupStepNr = 0; + // Sleeping a while after discovering services fixes connection problems. + // See https://github.com/NordicSemiconductor/Android-DFU-Library/issues/10 + // for some technical background. + handler.postDelayed(new Runnable() { + @Override + public void run() { + cmdStepNr = 0; + initStepNr = 0; + cleanupStepNr = 0; - // Clear from possible previous setups - characteristicRequestQueue = new LinkedList<>(); - descriptorRequestQueue = new LinkedList<>(); - openRequest = false; - } + // Clear from possible previous setups + characteristicRequestQueue = new LinkedList<>(); + descriptorRequestQueue = new LinkedList<>(); + openRequest = false; - try { - // Sleeping a while after discovering services fixes connection problems. - // See https://github.com/NordicSemiconductor/Android-DFU-Library/issues/10 - // for some technical background. - Thread.sleep(1000); - } - catch (Exception e) { - // Empty - } - - // Start the state machine - setBtMachineState(BT_MACHINE_STATE.BT_INIT_STATE); + // Start the state machine + setBtMachineState(BT_MACHINE_STATE.BT_INIT_STATE); + } + }, 1000); } @Override @@ -723,10 +719,8 @@ public abstract class BluetoothCommunication { handler.postDelayed(new Runnable() { @Override public void run() { - synchronized (lock) { - openRequest = false; - handleRequests(); - } + openRequest = false; + handleRequests(); } }, 60); } @@ -746,27 +740,33 @@ public abstract class BluetoothCommunication { } @Override - public void onCharacteristicRead(BluetoothGatt gatt, - BluetoothGattCharacteristic characteristic, - int status) { + public void onCharacteristicRead(final BluetoothGatt gatt, + final BluetoothGattCharacteristic characteristic, + final int status) { Timber.d("onCharacteristicRead %s (status=%d): %s", characteristic.getUuid(), status, byteInHex(characteristic.getValue())); - synchronized (lock) { - onBluetoothDataRead(gatt, characteristic, status); - postDelayedHandleRequests(); - } + handler.post(new Runnable() { + @Override + public void run() { + onBluetoothDataRead(gatt, characteristic, status); + } + }); + postDelayedHandleRequests(); } @Override - public void onCharacteristicChanged(BluetoothGatt gatt, - BluetoothGattCharacteristic characteristic) { + public void onCharacteristicChanged(final BluetoothGatt gatt, + final BluetoothGattCharacteristic characteristic) { Timber.d("onCharacteristicChanged %s: %s", characteristic.getUuid(), byteInHex(characteristic.getValue())); - synchronized (lock) { - onBluetoothDataChange(gatt, characteristic); - } + handler.post(new Runnable() { + @Override + public void run() { + onBluetoothDataChange(gatt, characteristic); + } + }); } @Override