Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
New failure reason - PHY request fail (unsupported configuration)
  • Loading branch information
philips77 committed Sep 8, 2025
commit 2c5b148d86dea2ecf172c5a6fb0ebeeb41f5de3a
18 changes: 16 additions & 2 deletions ble/src/main/java/no/nordicsemi/android/ble/BleManagerHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,11 @@ abstract class BleManagerHandler extends RequestHandler {
* Current connection parameters. Those values are only available starting from Android Oreo.
*/
private int interval, latency, timeout;
/**
* Samsung S8 with Android 9 fails to reconnect to devices requesting PHY LE 2M just after
* connection. Workaround would be to disable PHY LE 2M on the device side.
*/
private boolean earlyPhyLe2MRequest;
/**
* Last received battery value or -1 if value wasn't received.
*
Expand Down Expand Up @@ -753,6 +758,7 @@ private boolean internalConnect(@NonNull final BluetoothDevice device,
postConnectionStateChange(o -> o.onDeviceConnecting(device));
}
connectionTime = SystemClock.elapsedRealtime();
earlyPhyLe2MRequest = false;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O) {
// connectRequest will never be null here.
final int preferredPhy = connectRequest.getPreferredPhy();
Expand Down Expand Up @@ -2301,7 +2307,10 @@ public void onConnectionStateChange(@NonNull final BluetoothGatt gatt,
// ...because the next method sets them to false.

// notifyDeviceDisconnected(...) may call close()
if (timeout) {

if (status == GattError.GATT_CONN_TIMEOUT && earlyPhyLe2MRequest) {
notifyDeviceDisconnected(gatt.getDevice(), ConnectionObserver.REASON_UNSUPPORTED_CONFIGURATION);
} else if (timeout) {
notifyDeviceDisconnected(gatt.getDevice(), ConnectionObserver.REASON_TIMEOUT);
} else if (notSupported) {
notifyDeviceDisconnected(gatt.getDevice(), ConnectionObserver.REASON_NOT_SUPPORTED);
Expand Down Expand Up @@ -2332,7 +2341,9 @@ public void onConnectionStateChange(@NonNull final BluetoothGatt gatt,
}
if (cr != null) {
int reason;
if (notSupported)
if (status == GattError.GATT_CONN_TIMEOUT && earlyPhyLe2MRequest)
reason = FailCallback.REASON_UNSUPPORTED_CONFIGURATION;
else if (notSupported)
reason = FailCallback.REASON_DEVICE_NOT_SUPPORTED;
else if (status == BluetoothGatt.GATT_SUCCESS)
reason = FailCallback.REASON_DEVICE_DISCONNECTED;
Expand Down Expand Up @@ -2948,6 +2959,9 @@ public void onPhyUpdate(@NonNull final BluetoothGatt gatt,
log(Log.INFO, () ->
"PHY updated (TX: " + ParserUtils.phyToString(txPhy) +
", RX: " + ParserUtils.phyToString(rxPhy) + ")");
// Samsung S8 fails to reconnect when PHY LE 2M request is sent before service discovery.
earlyPhyLe2MRequest = earlyPhyLe2MRequest ||
(txPhy == BluetoothDevice.PHY_LE_2M && !servicesDiscovered);
if (request instanceof final PhyRequest pr) {
pr.notifyPhyChanged(gatt.getDevice(), txPhy, rxPhy);
pr.notifySuccess(gatt.getDevice());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,37 @@
package no.nordicsemi.android.ble.callback;

import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import no.nordicsemi.android.ble.BleManager;

import androidx.annotation.NonNull;

@FunctionalInterface
public interface FailCallback {
int REASON_DEVICE_DISCONNECTED = -1;
/**
* Returned when the {@link BleManager#isRequiredServiceSupported(BluetoothGatt)}
* returns false, that is when at least required GATT service was not discovered
* on the connected device.
*/
int REASON_DEVICE_NOT_SUPPORTED = -2;
int REASON_NULL_ATTRIBUTE = -3;
int REASON_REQUEST_FAILED = -4;
int REASON_TIMEOUT = -5;
int REASON_VALIDATION = -6;
int REASON_CANCELLED = -7;
int REASON_NOT_ENABLED = -8;
/**
* The Android device is unable to reconnect to the peripheral because of internal failure.
* Most probably it cannot respond properly to PHY LE 2M update procedure, causing the
* remote device to terminate the connection.
* <p>
* Try disabling PHY LE 2M on the peripheral side, or update the Android version.
* If that's not possible, the connection to your device may not work on the given
* Android device at all. If the device is bonded, try removing bonding and connect,
* but this seems to fix the problem only before a new bond is created.
*/
int REASON_UNSUPPORTED_CONFIGURATION = -9;
int REASON_BLUETOOTH_DISABLED = -100;

/**
Expand All @@ -47,7 +65,8 @@ public interface FailCallback {
* {@link #REASON_DEVICE_DISCONNECTED}, {@link #REASON_TIMEOUT},
* {@link #REASON_DEVICE_NOT_SUPPORTED} (only for Connect request),
* {@link #REASON_BLUETOOTH_DISABLED}, {@link #REASON_NULL_ATTRIBUTE},
* {@link #REASON_VALIDATION}, {@link #REASON_CANCELLED}, {@link #REASON_NOT_ENABLED}
* {@link #REASON_VALIDATION}, {@link #REASON_CANCELLED}, {@link #REASON_NOT_ENABLED},
* {@link #REASON_UNSUPPORTED_CONFIGURATION},
* or {@link #REASON_REQUEST_FAILED} (for other reason).
*/
void onRequestFailed(@NonNull final BluetoothDevice device, final int status);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,17 @@ public interface ConnectionObserver {
* or doesn't respond for another reason.
*/
int REASON_TIMEOUT = 10;
/**
* The Android device is unable to reconnect to the peripheral because of internal failure.
* Most probably it cannot respond properly to PHY LE 2M update procedure, causing the
* remote device to terminate the connection.
* <p>
* Try disabling PHY LE 2M on the peripheral side, or update the Android version.
* If that's not possible, the connection to your device may not work on the given
* Android device at all. If the device is bonded, try removing bonding and connect,
* but this seems to fix the problem only before a new bond is created.
*/
int REASON_UNSUPPORTED_CONFIGURATION = 11;

/**
* Called when the Android device started connecting to given device.
Expand Down