Improvement: autoConnect=false on first connection

First connection will always be done with autoConnect=false (improves
initial connection speed)
This commit is contained in:
Aleksander Nowakowski
2017-03-16 13:09:21 +01:00
parent 409f9573bd
commit c07824c38a
2 changed files with 52 additions and 13 deletions

View File

@@ -95,6 +95,12 @@ public abstract class BleManager<E extends BleManagerCallbacks> implements ILogg
* If {@link #shouldAutoConnect()} returns false (default) this is always set to true. * If {@link #shouldAutoConnect()} returns false (default) this is always set to true.
*/ */
private boolean mUserDisconnected; private boolean mUserDisconnected;
/**
* Flag set to true when {@link #shouldAutoConnect()} method returned <code>true</code>. The first connection attempt is done with <code>autoConnect</code>
* 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 <code>autoConnect</code> equal true.
*/
private boolean mInitialConnection;
/** Flag set to true when the device is connected. */ /** Flag set to true when the device is connected. */
private boolean mConnected; private boolean mConnected;
private int mConnectionState = BluetoothGatt.STATE_DISCONNECTED; private int mConnectionState = BluetoothGatt.STATE_DISCONNECTED;
@@ -226,6 +232,10 @@ public abstract class BleManager<E extends BleManagerCallbacks> implements ILogg
* <p>This method should only be used with bonded devices, as otherwise the device may change it's address. * <p>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 * 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.</p> * a device with private resolvable address will fail.</p>
* <p>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 .</p>
* *
* @return autoConnect flag value * @return autoConnect flag value
*/ */
@@ -245,15 +255,13 @@ public abstract class BleManager<E extends BleManagerCallbacks> implements ILogg
synchronized (mLock) { synchronized (mLock) {
if (mBluetoothGatt != null) { if (mBluetoothGatt != null) {
// There are 2 ways of reconnecting to the same device: // 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. // 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 // 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 // device.connectGatt(...) can't be called immediately or service discovery
// may never finish on some older devices (Nexus 4, Android 5.0.1). // 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 // If shouldAutoConnect() method returned false we can't call gatt.connect() and have to close gatt and open it again.
// despite the difficulties. if (!mInitialConnection) {
final boolean autoConnect = shouldAutoConnect();
if (autoConnect == mUserDisconnected) { // autoConnect has changed. Previously mUserDisconnected was set to !autoConnect (see below)
Logger.d(mLogSession, "gatt.close()"); Logger.d(mLogSession, "gatt.close()");
mBluetoothGatt.close(); mBluetoothGatt.close();
mBluetoothGatt = null; mBluetoothGatt = null;
@@ -265,6 +273,8 @@ public abstract class BleManager<E extends BleManagerCallbacks> implements ILogg
} }
} else { } else {
// Instead, the gatt.connect() method will be used to reconnect to the same device. // 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..."); Logger.v(mLogSession, "Connecting...");
mConnectionState = BluetoothGatt.STATE_CONNECTING; mConnectionState = BluetoothGatt.STATE_CONNECTING;
mCallbacks.onDeviceConnecting(device); mCallbacks.onDeviceConnecting(device);
@@ -280,14 +290,18 @@ public abstract class BleManager<E extends BleManagerCallbacks> implements ILogg
} }
} }
final boolean autoConnect = shouldAutoConnect(); final boolean shouldAutoConnect = shouldAutoConnect();
mUserDisconnected = !autoConnect; // We will receive Linkloss events only when the device is connected with autoConnect=true 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; mBluetoothDevice = device;
Logger.v(mLogSession, "Connecting..."); Logger.v(mLogSession, "Connecting...");
mConnectionState = BluetoothGatt.STATE_CONNECTING; mConnectionState = BluetoothGatt.STATE_CONNECTING;
mCallbacks.onDeviceConnecting(device); mCallbacks.onDeviceConnecting(device);
Logger.d(mLogSession, "gatt = device.connectGatt(autoConnect = " + autoConnect + ")"); Logger.d(mLogSession, "gatt = device.connectGatt(autoConnect = false)");
mBluetoothGatt = device.connectGatt(mContext, autoConnect, mGattCallback = getGattCallback()); mBluetoothGatt = device.connectGatt(mContext, false, mGattCallback = getGattCallback());
} }
/** /**
@@ -296,6 +310,7 @@ public abstract class BleManager<E extends BleManagerCallbacks> implements ILogg
*/ */
public boolean disconnect() { public boolean disconnect() {
mUserDisconnected = true; mUserDisconnected = true;
mInitialConnection = false;
if (mConnected && mBluetoothGatt != null) { if (mConnected && mBluetoothGatt != null) {
Logger.v(mLogSession, "Disconnecting..."); Logger.v(mLogSession, "Disconnecting...");
@@ -353,6 +368,7 @@ public abstract class BleManager<E extends BleManagerCallbacks> implements ILogg
mBluetoothGatt = null; mBluetoothGatt = null;
} }
mConnected = false; mConnected = false;
mInitialConnection = false;
mConnectionState = BluetoothGatt.STATE_DISCONNECTED; mConnectionState = BluetoothGatt.STATE_DISCONNECTED;
mGattCallback = null; mGattCallback = null;
mBluetoothDevice = null; mBluetoothDevice = null;
@@ -1185,7 +1201,12 @@ public abstract class BleManager<E extends BleManagerCallbacks> implements ILogg
mInitQueue = null; mInitQueue = null;
mTaskQueue.clear(); mTaskQueue.clear();
if (mConnected) { 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; return;
} }

View File

@@ -85,6 +85,12 @@ public class BleManager implements BleProfileApi {
* If {@link #shouldAutoConnect()} returns false (default) this is always set to true. * If {@link #shouldAutoConnect()} returns false (default) this is always set to true.
*/ */
private boolean mUserDisconnected; private boolean mUserDisconnected;
/**
* Flag set to true when {@link #shouldAutoConnect()} method returned <code>true</code>. The first connection attempt is done with <code>autoConnect</code>
* 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 <code>autoConnect</code> equal true.
*/
private boolean mInitialConnection;
/** Flag set to true when the device is connected. */ /** Flag set to true when the device is connected. */
private boolean mConnected; private boolean mConnected;
private int mConnectionState = BluetoothGatt.STATE_DISCONNECTED; private int mConnectionState = BluetoothGatt.STATE_DISCONNECTED;
@@ -175,6 +181,10 @@ public class BleManager implements BleProfileApi {
* <p>This method should only be used with bonded devices, as otherwise the device may change it's address. * <p>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 * 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.</p> * a device with private resolvable address will fail.</p>
* <p>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 .</p>
* *
* @return autoConnect flag value * @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). // 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 // However, the autoConnect flag settings may have changed. If it did, try closing and opening new BluetoothGatt
// despite the difficulties. // despite the difficulties.
final boolean autoConnect = shouldAutoConnect(); if (!mInitialConnection) {
if (autoConnect == mUserDisconnected) { // autoConnect has changed. Previously mUserDisconnected was set to !autoConnect (see below)
mBluetoothGatt.close(); mBluetoothGatt.close();
mBluetoothGatt = null; mBluetoothGatt = null;
try { try {
@@ -212,6 +221,8 @@ public class BleManager implements BleProfileApi {
} }
} else { } else {
// Instead, the gatt.connect() method will be used to reconnect to the same device. // 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; mConnectionState = BluetoothGatt.STATE_CONNECTING;
mCallbacks.onDeviceConnecting(device); mCallbacks.onDeviceConnecting(device);
mBluetoothGatt.connect(); mBluetoothGatt.connect();
@@ -238,6 +249,7 @@ public class BleManager implements BleProfileApi {
*/ */
public boolean disconnect() { public boolean disconnect() {
mUserDisconnected = true; mUserDisconnected = true;
mInitialConnection = false;
if (mConnected && mBluetoothGatt != null) { if (mConnected && mBluetoothGatt != null) {
mConnectionState = BluetoothGatt.STATE_DISCONNECTING; mConnectionState = BluetoothGatt.STATE_DISCONNECTING;
@@ -291,6 +303,7 @@ public class BleManager implements BleProfileApi {
mBluetoothGatt = null; mBluetoothGatt = null;
} }
mConnected = false; mConnected = false;
mInitialConnection = false;
mConnectionState = BluetoothGatt.STATE_DISCONNECTED; mConnectionState = BluetoothGatt.STATE_DISCONNECTED;
mGattCallback = null; mGattCallback = null;
mBluetoothDevice = null; mBluetoothDevice = null;
@@ -614,7 +627,12 @@ public class BleManager implements BleProfileApi {
mInitQueue = null; mInitQueue = null;
mTaskQueue.clear(); mTaskQueue.clear();
if (mConnected) { 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; return;
} }