Skip to content

Commit

Permalink
Merge pull request #575 from muscardinus/start-auto-connect-immediately
Browse files Browse the repository at this point in the history
Start auto connect immediately
  • Loading branch information
philips77 authored Aug 16, 2024
2 parents 061e98c + 85459c7 commit 02e7efb
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 18 deletions.
50 changes: 32 additions & 18 deletions ble/src/main/java/no/nordicsemi/android/ble/BleManagerHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -689,48 +689,62 @@ private boolean internalConnect(@NonNull final BluetoothDevice device,
// when retrying to create a connection.
if (connectRequest == null)
return false;

final boolean shouldAutoConnect = connectRequest.shouldAutoConnect();
// We will receive Link Loss events only when the device is connected with autoConnect=true.
userDisconnected = !shouldAutoConnect;
// 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.
final boolean autoConnect;
if (shouldAutoConnect) {
initialConnection = true;
// If shouldAutoConnectCreateDirectConnectionFirst() returns 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.
initialConnection = connectRequest.shouldAutoConnectCreateDirectConnectionFirst();
autoConnect = !initialConnection;
} else {
autoConnect = false;
}
// We will receive Link Loss events only when the device is connected with autoConnect=true.
userDisconnected = !shouldAutoConnect;

bluetoothDevice = device;
log(Log.VERBOSE, () -> connectRequest.isFirstAttempt() ? "Connecting..." : "Retrying...");
connectionState = BluetoothGatt.STATE_CONNECTING;
postCallback(c -> c.onDeviceConnecting(device));
postConnectionStateChange(o -> o.onDeviceConnecting(device));
if (!autoConnect) {
log(Log.VERBOSE, () -> connectRequest.isFirstAttempt() ? "Connecting..." : "Retrying...");
connectionState = BluetoothGatt.STATE_CONNECTING;
postCallback(c -> c.onDeviceConnecting(device));
postConnectionStateChange(o -> o.onDeviceConnecting(device));
}
connectionTime = SystemClock.elapsedRealtime();
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O) {
// connectRequest will never be null here.
final int preferredPhy = connectRequest.getPreferredPhy();
log(Log.DEBUG, () ->
"gatt = device.connectGatt(autoConnect = false, TRANSPORT_LE, "
"gatt = device.connectGatt(autoConnect = " + autoConnect + ", TRANSPORT_LE, "
+ ParserUtils.phyMaskToString(preferredPhy) + ")");

bluetoothGatt = device.connectGatt(context, false, gattCallback,
bluetoothGatt = device.connectGatt(context, autoConnect, gattCallback,
BluetoothDevice.TRANSPORT_LE, preferredPhy, handler);
} else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O) {
// connectRequest will never be null here.
final int preferredPhy = connectRequest.getPreferredPhy();
log(Log.DEBUG, () ->
"gatt = device.connectGatt(autoConnect = false, TRANSPORT_LE, "
"gatt = device.connectGatt(autoConnect = " + autoConnect + ", TRANSPORT_LE, "
+ ParserUtils.phyMaskToString(preferredPhy) + ")");
// A variant of connectGatt with Handled can't be used here.
// Check https://github.com/NordicSemiconductor/Android-BLE-Library/issues/54
// This bug specifically occurs in SDK 26 and is fixed in SDK 27
bluetoothGatt = device.connectGatt(context, false, gattCallback,
bluetoothGatt = device.connectGatt(context, autoConnect, gattCallback,
BluetoothDevice.TRANSPORT_LE, preferredPhy/*, handler*/);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
log(Log.DEBUG, () -> "gatt = device.connectGatt(autoConnect = false, TRANSPORT_LE)");
bluetoothGatt = device.connectGatt(context, false, gattCallback,
log(Log.DEBUG, () -> "gatt = device.connectGatt(autoConnect = " + autoConnect + ", TRANSPORT_LE)");
bluetoothGatt = device.connectGatt(context, autoConnect, gattCallback,
BluetoothDevice.TRANSPORT_LE);
} else {
log(Log.DEBUG, () -> "gatt = device.connectGatt(autoConnect = false)");
bluetoothGatt = device.connectGatt(context, false, gattCallback);
log(Log.DEBUG, () -> "gatt = device.connectGatt(autoConnect = " + autoConnect + ")");
bluetoothGatt = device.connectGatt(context, autoConnect, gattCallback);
}

if (autoConnect && this.connectRequest != null) {
this.connectRequest.notifySuccess(device);
this.connectRequest = null;
}
return true;
}
Expand Down
46 changes: 46 additions & 0 deletions ble/src/main/java/no/nordicsemi/android/ble/ConnectRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public class ConnectRequest extends TimeoutableRequest {
@IntRange(from = 0)
private int delay = 0;
private boolean autoConnect = false;
private boolean autoConnectCreateDirectConnectionFirst = true;

ConnectRequest(@NonNull final Type type, @NonNull final BluetoothDevice device) {
super(type);
Expand Down Expand Up @@ -209,6 +210,47 @@ public ConnectRequest useAutoConnect(final boolean autoConnect) {
return this;
}

/**
* Sets whether to connect to the remote device just once (autoConnect == false) or to add
* the address to white list of devices that will be automatically connect as soon as they
* become available (autoConnect == true). In the latter case, if Bluetooth adapter is enabled,
* Android scans periodically for devices from the white list and, if an advertising packet
* is received from such, it tries to connect to it.
* When the connection is lost, the system will keep trying to reconnect to
* it. If method is called with autoConnect set to true, and the connection to the device is
* lost, the {@link BleManagerCallbacks#onLinkLossOccurred(BluetoothDevice)} callback is
* called instead of {@link BleManagerCallbacks#onDeviceDisconnected(BluetoothDevice)}.
* <p>
* This feature works much better on newer Android phone models and may have issues on older
* phones.
* <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 a non-bonded device with private resolvable address will fail.
* <p>
* If createDirectConnectionFirst is set to true, 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. If autoConnect is
* used (true), the following connections will be done using {@link BluetoothGatt#connect()},
* which forces the autoConnect parameter to true.
* If autoConnect is used (true) and createDirectConnectionFirst is set to false, the connection
* to a device will be created with autoConnect flag to true from the start.
*
* @param autoConnect true to use autoConnect feature.
* @param createDirectConnectionFirst If true, the first connection is always done with autoConnect
* parameter equal to false, to make it faster and allow to timeout
* if the device is unreachable.
* If false, the connection to a device will be created with
* autoConnect flag to true from the start.
* @return The request.
*/
public ConnectRequest useAutoConnect(final boolean autoConnect, final boolean createDirectConnectionFirst) {
this.autoConnect = autoConnect;
this.autoConnectCreateDirectConnectionFirst = createDirectConnectionFirst;
return this;
}

/**
* Sets the preferred PHY used for connection. The value should be a bitmask composed of
* {@link PhyRequest#PHY_LE_1M_MASK}, {@link PhyRequest#PHY_LE_2M_MASK} or
Expand Down Expand Up @@ -293,4 +335,8 @@ int getRetryDelay() {
boolean shouldAutoConnect() {
return autoConnect;
}

boolean shouldAutoConnectCreateDirectConnectionFirst() {
return autoConnectCreateDirectConnectionFirst;
}
}

0 comments on commit 02e7efb

Please sign in to comment.