mirror of
https://github.com/aljazceru/Android-nRF-Toolbox.git
synced 2025-12-22 00:44:26 +01:00
Stability improvements in BleManager
Requires more testing on different phones.
This commit is contained in:
@@ -114,8 +114,9 @@ public abstract class BleManager<E extends BleManagerCallbacks> implements ILogg
|
|||||||
if (mConnected && previousState != BluetoothAdapter.STATE_TURNING_OFF && previousState != BluetoothAdapter.STATE_OFF) {
|
if (mConnected && previousState != BluetoothAdapter.STATE_TURNING_OFF && previousState != BluetoothAdapter.STATE_OFF) {
|
||||||
// The connection is killed by the system, no need to gently disconnect
|
// The connection is killed by the system, no need to gently disconnect
|
||||||
mGattCallback.notifyDeviceDisconnected(mBluetoothDevice);
|
mGattCallback.notifyDeviceDisconnected(mBluetoothDevice);
|
||||||
close();
|
|
||||||
}
|
}
|
||||||
|
// Calling close() will prevent the STATE_OFF event from being logged (this receiver will be unregistered). But it doesn't matter.
|
||||||
|
close();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -241,9 +242,34 @@ public abstract class BleManager<E extends BleManagerCallbacks> implements ILogg
|
|||||||
|
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
if (mBluetoothGatt != null) {
|
if (mBluetoothGatt != null) {
|
||||||
Logger.d(mLogSession, "gatt.close()");
|
// There are 2 ways of reconnecting to the same device:
|
||||||
mBluetoothGatt.close();
|
// 1. Reusing the same BluetoothGatt object and calling connect() on it or
|
||||||
mBluetoothGatt = null;
|
// 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)
|
||||||
|
Logger.d(mLogSession, "gatt.close()");
|
||||||
|
mBluetoothGatt.close();
|
||||||
|
mBluetoothGatt = null;
|
||||||
|
try {
|
||||||
|
Logger.d(mLogSession, "wait(200)");
|
||||||
|
Thread.sleep(200); // Is 200 ms enough?
|
||||||
|
} catch (final InterruptedException e) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Instead, the gatt.connect() method will be used to reconnect to the same device.
|
||||||
|
Logger.v(mLogSession, "Connecting...");
|
||||||
|
mConnectionState = BluetoothGatt.STATE_CONNECTING;
|
||||||
|
mCallbacks.onDeviceConnecting(device);
|
||||||
|
Logger.d(mLogSession, "gatt.connect()");
|
||||||
|
mBluetoothGatt.connect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Register bonding broadcast receiver
|
// Register bonding broadcast receiver
|
||||||
mContext.registerReceiver(mBluetoothStateBroadcastReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
|
mContext.registerReceiver(mBluetoothStateBroadcastReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
|
||||||
@@ -890,7 +916,7 @@ public abstract class BleManager<E extends BleManagerCallbacks> implements ILogg
|
|||||||
private final Queue<Request> mTaskQueue = new LinkedList<>();
|
private final Queue<Request> mTaskQueue = new LinkedList<>();
|
||||||
private Deque<Request> mInitQueue;
|
private Deque<Request> mInitQueue;
|
||||||
private boolean mInitInProgress;
|
private boolean mInitInProgress;
|
||||||
private boolean mOperationInProgress;
|
private boolean mOperationInProgress = true; // Initially true to block operations before services are discovered.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method should return <code>true</code> when the gatt device supports the required services.
|
* This method should return <code>true</code> when the gatt device supports the required services.
|
||||||
@@ -1057,12 +1083,27 @@ public abstract class BleManager<E extends BleManagerCallbacks> implements ILogg
|
|||||||
* If the mBluetoothGatt.discoverServices() method would be invoked here, if would returned cached services,
|
* If the mBluetoothGatt.discoverServices() method would be invoked here, if would returned cached services,
|
||||||
* as the SC indication wouldn't be received yet.
|
* as the SC indication wouldn't be received yet.
|
||||||
* Therefore we have to postpone the service discovery operation until we are (almost, as there is no such callback) sure, that it had to be handled.
|
* Therefore we have to postpone the service discovery operation until we are (almost, as there is no such callback) sure, that it had to be handled.
|
||||||
* Our tests has shown that 600 ms is enough. It is important to call it AFTER receiving the SC indication, but not necessarily
|
* Our tests has shown that 600 ms is enough(*). It is important to call it AFTER receiving the SC indication, but not necessarily
|
||||||
* after Android finishes the internal service discovery.
|
* after Android finishes the internal service discovery.
|
||||||
*
|
*
|
||||||
* NOTE: This applies only for bonded devices with Service Changed characteristic, but to be sure we will postpone
|
* NOTE: This applies only for bonded devices with Service Changed characteristic, but to be sure we will postpone
|
||||||
* service discovery for all devices.
|
* service discovery for all devices.
|
||||||
|
*
|
||||||
|
* (*) - While testing on Nexus 4 with Android 5.0.1 it appeared that 600 ms may be not enough.
|
||||||
|
* The service discovery initiated by the system was still in progress while gatt.serviceDiscovery() below
|
||||||
|
* was called and (due to a bug on older Android versions, where there can be only one callback registered)
|
||||||
|
* the onServicesDiscovered(...) callback has never been called.
|
||||||
*/
|
*/
|
||||||
|
// On Android Nougat or never devices no delay is necessary any more.
|
||||||
|
int delay = 0;
|
||||||
|
// TODO: modify the delay to match your use case. More services require longer discovery time. Use Nexus 4, 7 or other phone with bad throughput.
|
||||||
|
// The delays here are based on a guess. Newer phones should handle service discovery it faster, I guess.
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N)
|
||||||
|
delay = 600;
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
|
||||||
|
delay = 1200;
|
||||||
|
if (delay > 0)
|
||||||
|
Logger.d(mLogSession, "wait(" + delay + ")");
|
||||||
mHandler.postDelayed(new Runnable() {
|
mHandler.postDelayed(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -1073,14 +1114,16 @@ public abstract class BleManager<E extends BleManagerCallbacks> implements ILogg
|
|||||||
gatt.discoverServices();
|
gatt.discoverServices();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 600);
|
}, delay);
|
||||||
} else {
|
} else {
|
||||||
if (newState == BluetoothProfile.STATE_DISCONNECTED) {
|
if (newState == BluetoothProfile.STATE_DISCONNECTED) {
|
||||||
if (status != BluetoothGatt.GATT_SUCCESS)
|
if (status != BluetoothGatt.GATT_SUCCESS)
|
||||||
Logger.w(mLogSession, "Error: (0x" + Integer.toHexString(status) + "): " + GattError.parseConnectionError(status));
|
Logger.w(mLogSession, "Error: (0x" + Integer.toHexString(status) + "): " + GattError.parseConnectionError(status));
|
||||||
|
|
||||||
mOperationInProgress = true; // no more calls are possible
|
mOperationInProgress = true; // no more calls are possible
|
||||||
notifyDeviceDisconnected(gatt.getDevice());
|
if (mConnected) {
|
||||||
|
notifyDeviceDisconnected(gatt.getDevice());
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user