@@ -180,6 +180,11 @@ abstract class BleManagerHandler extends RequestHandler {
180180 * Current connection parameters. Those values are only available starting from Android Oreo.
181181 */
182182 private int interval , latency , timeout ;
183+ /**
184+ * Samsung S8 with Android 9 fails to reconnect to devices requesting PHY LE 2M just after
185+ * connection. Workaround would be to disable PHY LE 2M on the device side.
186+ */
187+ private boolean earlyPhyLe2MRequest ;
183188 /**
184189 * Last received battery value or -1 if value wasn't received.
185190 *
@@ -753,6 +758,7 @@ private boolean internalConnect(@NonNull final BluetoothDevice device,
753758 postConnectionStateChange (o -> o .onDeviceConnecting (device ));
754759 }
755760 connectionTime = SystemClock .elapsedRealtime ();
761+ earlyPhyLe2MRequest = false ;
756762 if (Build .VERSION .SDK_INT > Build .VERSION_CODES .O ) {
757763 // connectRequest will never be null here.
758764 final int preferredPhy = connectRequest .getPreferredPhy ();
@@ -2301,7 +2307,10 @@ public void onConnectionStateChange(@NonNull final BluetoothGatt gatt,
23012307 // ...because the next method sets them to false.
23022308
23032309 // notifyDeviceDisconnected(...) may call close()
2304- if (timeout ) {
2310+
2311+ if (status == GattError .GATT_CONN_TIMEOUT && earlyPhyLe2MRequest ) {
2312+ notifyDeviceDisconnected (gatt .getDevice (), ConnectionObserver .REASON_UNSUPPORTED_CONFIGURATION );
2313+ } else if (timeout ) {
23052314 notifyDeviceDisconnected (gatt .getDevice (), ConnectionObserver .REASON_TIMEOUT );
23062315 } else if (notSupported ) {
23072316 notifyDeviceDisconnected (gatt .getDevice (), ConnectionObserver .REASON_NOT_SUPPORTED );
@@ -2332,7 +2341,9 @@ public void onConnectionStateChange(@NonNull final BluetoothGatt gatt,
23322341 }
23332342 if (cr != null ) {
23342343 int reason ;
2335- if (notSupported )
2344+ if (status == GattError .GATT_CONN_TIMEOUT && earlyPhyLe2MRequest )
2345+ reason = FailCallback .REASON_UNSUPPORTED_CONFIGURATION ;
2346+ else if (notSupported )
23362347 reason = FailCallback .REASON_DEVICE_NOT_SUPPORTED ;
23372348 else if (status == BluetoothGatt .GATT_SUCCESS )
23382349 reason = FailCallback .REASON_DEVICE_DISCONNECTED ;
@@ -2524,13 +2535,9 @@ public void onCharacteristicRead(@NonNull final BluetoothGatt gatt,
25242535 rr .notifySuccess (gatt .getDevice ());
25252536 }
25262537 }
2527- } else if (status == 137 /* GATT AUTH FAIL */ ) {
2528- // Bonding failed or was cancelled.
2529- Log .w (TAG , "Reading failed with status " + status );
2530- // The bond state receiver will fail the request. Stop here.
2531- return ;
25322538 } else if (status == BluetoothGatt .GATT_INSUFFICIENT_AUTHENTICATION
2533- || status == 8 /* GATT INSUF AUTHORIZATION */ ) {
2539+ || status == 8 /* GATT INSUF AUTHORIZATION */
2540+ || status == 137 /* GATT AUTH FAIL */ ) {
25342541 // This is called when bonding attempt failed, but the app is still trying to read.
25352542 // We need to cancel the request here, as bonding won't start.
25362543 log (Log .WARN , () -> "Authentication required (" + status + ")" );
@@ -2578,13 +2585,9 @@ public void onCharacteristicWrite(final BluetoothGatt gatt,
25782585 wr .notifySuccess (gatt .getDevice ());
25792586 }
25802587 }
2581- } else if (status == 137 /* GATT AUTH FAIL */ ) {
2582- // This never happens for Write operations, for some reason.
2583- Log .w (TAG , "Writing failed with status " + status );
2584- // The bond state receiver will fail the request. Stop here.
2585- return ;
25862588 } else if (status == BluetoothGatt .GATT_INSUFFICIENT_AUTHENTICATION
2587- || status == 8 /* GATT INSUF AUTHORIZATION */ ) {
2589+ || status == 8 /* GATT INSUF AUTHORIZATION */
2590+ || status == 137 /* GATT AUTH FAIL */ ) {
25882591 // This is called when bonding attempt failed, but the app is still trying to write.
25892592 // We need to cancel the request here, as bonding won't start.
25902593 log (Log .WARN , () -> "Authentication required (" + status + ")" );
@@ -2595,6 +2598,9 @@ public void onCharacteristicWrite(final BluetoothGatt gatt,
25952598 }
25962599 if (request instanceof final WriteRequest wr ) {
25972600 wr .notifyFail (gatt .getDevice (), status );
2601+ // Automatically abort Reliable Write when write error happen
2602+ if (requestQueue instanceof final ReliableWriteRequest rwr )
2603+ rwr .notifyAndCancelQueue (gatt .getDevice ());
25982604 }
25992605 } else {
26002606 Log .e (TAG , "onCharacteristicWrite error " + status + ", bond state: " + gatt .getDevice ().getBondState ());
@@ -2658,13 +2664,9 @@ public void onDescriptorRead(final @NonNull BluetoothGatt gatt,
26582664 rr .notifySuccess (gatt .getDevice ());
26592665 }
26602666 }
2661- } else if (status == 137 /* GATT AUTH FAIL */ ) {
2662- // Bonding failed or was cancelled.
2663- Log .w (TAG , "Reading descriptor failed with status " + status );
2664- // The bond state receiver will fail the request. Stop here.
2665- return ;
26662667 } else if (status == BluetoothGatt .GATT_INSUFFICIENT_AUTHENTICATION
2667- || status == 8 /* GATT INSUF AUTHORIZATION */ ) {
2668+ || status == 8 /* GATT INSUF AUTHORIZATION */
2669+ || status == 137 /* GATT AUTH FAIL */ ) {
26682670 // This is called when bonding attempt failed, but the app is still trying to read.
26692671 // We need to cancel the request here, as bonding won't start.
26702672 log (Log .WARN , () -> "Authentication required (" + status + ")" );
@@ -2722,13 +2724,9 @@ public void onDescriptorWrite(final BluetoothGatt gatt,
27222724 wr .notifySuccess (gatt .getDevice ());
27232725 }
27242726 }
2725- } else if (status == 137 /* GATT AUTH FAIL */ ) {
2726- // This never happens for Write operations, for some reason.
2727- Log .w (TAG , "Writing descriptor failed with status " + status );
2728- // The bond state receiver will fail the request. Stop here.
2729- return ;
27302727 } else if (status == BluetoothGatt .GATT_INSUFFICIENT_AUTHENTICATION
2731- || status == 8 /* GATT INSUF AUTHORIZATION */ ) {
2728+ || status == 8 /* GATT INSUF AUTHORIZATION */
2729+ || status == 137 /* GATT AUTH FAIL */ ) {
27322730 // This is called when bonding attempt failed, but the app is still trying to write.
27332731 // We need to cancel the request here, as bonding won't start.
27342732 log (Log .WARN , () -> "Authentication required (" + status + ")" );
@@ -2739,6 +2737,9 @@ public void onDescriptorWrite(final BluetoothGatt gatt,
27392737 }
27402738 if (request instanceof final WriteRequest wr ) {
27412739 wr .notifyFail (gatt .getDevice (), status );
2740+ // Automatically abort Reliable Write when write error happen
2741+ if (requestQueue instanceof final ReliableWriteRequest rwr )
2742+ rwr .notifyAndCancelQueue (gatt .getDevice ());
27422743 }
27432744 } else {
27442745 Log .e (TAG , "onDescriptorWrite error " + status + ", bond state: " + gatt .getDevice ().getBondState ());
@@ -2958,6 +2959,9 @@ public void onPhyUpdate(@NonNull final BluetoothGatt gatt,
29582959 log (Log .INFO , () ->
29592960 "PHY updated (TX: " + ParserUtils .phyToString (txPhy ) +
29602961 ", RX: " + ParserUtils .phyToString (rxPhy ) + ")" );
2962+ // Samsung S8 fails to reconnect when PHY LE 2M request is sent before service discovery.
2963+ earlyPhyLe2MRequest = earlyPhyLe2MRequest ||
2964+ (txPhy == BluetoothDevice .PHY_LE_2M && !servicesDiscovered );
29612965 if (request instanceof final PhyRequest pr ) {
29622966 pr .notifyPhyChanged (gatt .getDevice (), txPhy , rxPhy );
29632967 pr .notifySuccess (gatt .getDevice ());
0 commit comments