Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Start auto connect immediately #575

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
}
}