From c07824c38a3d69194c64d3a0425591fda00d81b1 Mon Sep 17 00:00:00 2001 From: Aleksander Nowakowski Date: Thu, 16 Mar 2017 13:09:21 +0100 Subject: [PATCH] Improvement: autoConnect=false on first connection First connection will always be done with autoConnect=false (improves initial connection speed) --- .../nrftoolbox/profile/BleManager.java | 41 ++++++++++++++----- .../android/nrftoolbox/ble/BleManager.java | 24 +++++++++-- 2 files changed, 52 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleManager.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleManager.java index 81c1a8da..403e44e0 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleManager.java +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleManager.java @@ -95,6 +95,12 @@ public abstract class BleManager implements ILogg * If {@link #shouldAutoConnect()} returns false (default) this is always set to true. */ private boolean mUserDisconnected; + /** + * Flag set to true when {@link #shouldAutoConnect()} method returned true. The first connection attempt is done with autoConnect + * flag set to false (to make the first connection quick) but on connection lost the manager will call {@link #connect(BluetoothDevice)} again. + * This time this method will call {@link BluetoothGatt#connect()} which always uses autoConnect equal true. + */ + private boolean mInitialConnection; /** Flag set to true when the device is connected. */ private boolean mConnected; private int mConnectionState = BluetoothGatt.STATE_DISCONNECTED; @@ -226,6 +232,10 @@ public abstract class BleManager implements ILogg *

This method should only be used with bonded devices, as otherwise the device may change it's address. * It will however work also with non-bonded devices with private static address. A connection attempt to * a device with private resolvable address will fail.

+ *

The first connection to a device will always be created with autoConnect flag to false + * (see {@link BluetoothDevice#connectGatt(Context, boolean, BluetoothGattCallback)}). This is to make it quick as the + * user most probably waits for a quick response. However, if this method returned true during first connection and the link was lost, + * the manager will try to reconnect to it using {@link BluetoothGatt#connect()} which forces autoConnect to true .

* * @return autoConnect flag value */ @@ -245,15 +255,13 @@ public abstract class BleManager implements ILogg synchronized (mLock) { if (mBluetoothGatt != null) { // There are 2 ways of reconnecting to the same device: - // 1. Reusing the same BluetoothGatt object and calling connect() on it or + // 1. Reusing the same BluetoothGatt object and calling connect() - this will force the autoConnect flag to true // 2. Closing it and reopening a new instance of BluetoothGatt object. // The gatt.close() is an asynchronous method. It requires some time before it's finished and // device.connectGatt(...) can't be called immediately or service discovery // may never finish on some older devices (Nexus 4, Android 5.0.1). - // However, the autoConnect flag settings may have changed. If it did, try closing and opening new BluetoothGatt - // despite the difficulties. - final boolean autoConnect = shouldAutoConnect(); - if (autoConnect == mUserDisconnected) { // autoConnect has changed. Previously mUserDisconnected was set to !autoConnect (see below) + // If shouldAutoConnect() method returned false we can't call gatt.connect() and have to close gatt and open it again. + if (!mInitialConnection) { Logger.d(mLogSession, "gatt.close()"); mBluetoothGatt.close(); mBluetoothGatt = null; @@ -265,6 +273,8 @@ public abstract class BleManager implements ILogg } } else { // Instead, the gatt.connect() method will be used to reconnect to the same device. + // This method forces autoConnect = true even if the gatt was created with this flag set to false. + mInitialConnection = false; Logger.v(mLogSession, "Connecting..."); mConnectionState = BluetoothGatt.STATE_CONNECTING; mCallbacks.onDeviceConnecting(device); @@ -280,14 +290,18 @@ public abstract class BleManager implements ILogg } } - final boolean autoConnect = shouldAutoConnect(); - mUserDisconnected = !autoConnect; // We will receive Linkloss events only when the device is connected with autoConnect=true + final boolean shouldAutoConnect = shouldAutoConnect(); + mUserDisconnected = !shouldAutoConnect; // We will receive Linkloss events only when the device is connected with autoConnect=true + // The first connection will always be done with autoConnect = false to make the connection quick. + // If the shouldAutoConnect() method returned true, the manager will automatically try to reconnect to this device on link loss. + if (shouldAutoConnect) + mInitialConnection = true; mBluetoothDevice = device; Logger.v(mLogSession, "Connecting..."); mConnectionState = BluetoothGatt.STATE_CONNECTING; mCallbacks.onDeviceConnecting(device); - Logger.d(mLogSession, "gatt = device.connectGatt(autoConnect = " + autoConnect + ")"); - mBluetoothGatt = device.connectGatt(mContext, autoConnect, mGattCallback = getGattCallback()); + Logger.d(mLogSession, "gatt = device.connectGatt(autoConnect = false)"); + mBluetoothGatt = device.connectGatt(mContext, false, mGattCallback = getGattCallback()); } /** @@ -296,6 +310,7 @@ public abstract class BleManager implements ILogg */ public boolean disconnect() { mUserDisconnected = true; + mInitialConnection = false; if (mConnected && mBluetoothGatt != null) { Logger.v(mLogSession, "Disconnecting..."); @@ -353,6 +368,7 @@ public abstract class BleManager implements ILogg mBluetoothGatt = null; } mConnected = false; + mInitialConnection = false; mConnectionState = BluetoothGatt.STATE_DISCONNECTED; mGattCallback = null; mBluetoothDevice = null; @@ -1185,7 +1201,12 @@ public abstract class BleManager implements ILogg mInitQueue = null; mTaskQueue.clear(); if (mConnected) { - notifyDeviceDisconnected(gatt.getDevice()); + notifyDeviceDisconnected(gatt.getDevice()); // This sets the mConnected flag to false + } + // Try to reconnect if the initial connection was lost because of a link loss or timeout, and shouldAutoConnect() returned true during connection attempt. + // This time it will set the autoConnect flag to true (gatt.connect() forces autoConnect true) + if (mInitialConnection) { + connect(gatt.getDevice()); } return; } diff --git a/wear/src/main/java/no/nordicsemi/android/nrftoolbox/ble/BleManager.java b/wear/src/main/java/no/nordicsemi/android/nrftoolbox/ble/BleManager.java index 4efa11aa..09744b1b 100644 --- a/wear/src/main/java/no/nordicsemi/android/nrftoolbox/ble/BleManager.java +++ b/wear/src/main/java/no/nordicsemi/android/nrftoolbox/ble/BleManager.java @@ -85,6 +85,12 @@ public class BleManager implements BleProfileApi { * If {@link #shouldAutoConnect()} returns false (default) this is always set to true. */ private boolean mUserDisconnected; + /** + * Flag set to true when {@link #shouldAutoConnect()} method returned true. The first connection attempt is done with autoConnect + * flag set to false (to make the first connection quick) but on connection lost the manager will call {@link #connect(BluetoothDevice)} again. + * This time this method will call {@link BluetoothGatt#connect()} which always uses autoConnect equal true. + */ + private boolean mInitialConnection; /** Flag set to true when the device is connected. */ private boolean mConnected; private int mConnectionState = BluetoothGatt.STATE_DISCONNECTED; @@ -175,6 +181,10 @@ public class BleManager implements BleProfileApi { *

This method should only be used with bonded devices, as otherwise the device may change it's address. * It will however work also with non-bonded devices with private static address. A connection attempt to * a device with private resolvable address will fail.

+ *

The first connection to a device will always be created with autoConnect flag to false + * (see {@link BluetoothDevice#connectGatt(Context, boolean, BluetoothGattCallback)}). This is to make it quick as the + * user most probably waits for a quick response. However, if this method returned true during first connection and the link was lost, + * the manager will try to reconnect to it using {@link BluetoothGatt#connect()} which forces autoConnect to true .

* * @return autoConnect flag value */ @@ -201,8 +211,7 @@ public class BleManager implements BleProfileApi { // may never finish on some older devices (Nexus 4, Android 5.0.1). // However, the autoConnect flag settings may have changed. If it did, try closing and opening new BluetoothGatt // despite the difficulties. - final boolean autoConnect = shouldAutoConnect(); - if (autoConnect == mUserDisconnected) { // autoConnect has changed. Previously mUserDisconnected was set to !autoConnect (see below) + if (!mInitialConnection) { mBluetoothGatt.close(); mBluetoothGatt = null; try { @@ -212,6 +221,8 @@ public class BleManager implements BleProfileApi { } } else { // Instead, the gatt.connect() method will be used to reconnect to the same device. + // This method forces autoConnect = true even if the gatt was created with this flag set to false. + mInitialConnection = false; mConnectionState = BluetoothGatt.STATE_CONNECTING; mCallbacks.onDeviceConnecting(device); mBluetoothGatt.connect(); @@ -238,6 +249,7 @@ public class BleManager implements BleProfileApi { */ public boolean disconnect() { mUserDisconnected = true; + mInitialConnection = false; if (mConnected && mBluetoothGatt != null) { mConnectionState = BluetoothGatt.STATE_DISCONNECTING; @@ -291,6 +303,7 @@ public class BleManager implements BleProfileApi { mBluetoothGatt = null; } mConnected = false; + mInitialConnection = false; mConnectionState = BluetoothGatt.STATE_DISCONNECTED; mGattCallback = null; mBluetoothDevice = null; @@ -614,7 +627,12 @@ public class BleManager implements BleProfileApi { mInitQueue = null; mTaskQueue.clear(); if (mConnected) { - notifyDeviceDisconnected(gatt.getDevice()); + notifyDeviceDisconnected(gatt.getDevice()); // This sets the mConnected flag to false + } + // Try to reconnect if the initial connection was lost because of a link loss or timeout, and shouldAutoConnect() returned true during connection attempt. + // This time it will set the autoConnect flag to true (gatt.connect() forces autoConnect true) + if (mInitialConnection) { + connect(gatt.getDevice()); } return; }