Loading framework/api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -627,6 +627,7 @@ package android.bluetooth { field public static final int CONNECTION_PRIORITY_HIGH = 1; // 0x1 field public static final int CONNECTION_PRIORITY_LOW_POWER = 2; // 0x2 field public static final int GATT_CONNECTION_CONGESTED = 143; // 0x8f field @FlaggedApi("com.android.bluetooth.flags.enumerate_gatt_errors") public static final int GATT_CONNECTION_TIMEOUT = 147; // 0x93 field public static final int GATT_FAILURE = 257; // 0x101 field public static final int GATT_INSUFFICIENT_AUTHENTICATION = 5; // 0x5 field public static final int GATT_INSUFFICIENT_AUTHORIZATION = 8; // 0x8 Loading framework/java/android/bluetooth/BluetoothGatt.java +9 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package android.bluetooth; import static android.bluetooth.BluetoothUtils.getSyncTimeout; import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.RequiresNoPermission; Loading @@ -35,6 +36,7 @@ import android.os.ParcelUuid; import android.os.RemoteException; import android.util.Log; import com.android.bluetooth.flags.Flags; import com.android.modules.utils.SynchronousResultReceiver; import java.lang.annotation.Retention; Loading Loading @@ -128,6 +130,13 @@ public final class BluetoothGatt implements BluetoothProfile { /** A remote device connection is congested. */ public static final int GATT_CONNECTION_CONGESTED = 0x8f; /** * GATT connection timed out, likely due to the remote device being out of range or not * advertising as connectable. */ @FlaggedApi(Flags.FLAG_ENUMERATE_GATT_ERRORS) public static final int GATT_CONNECTION_TIMEOUT = 0x93; /** A GATT operation failed, errors other than the above */ public static final int GATT_FAILURE = 0x101; Loading framework/tests/bumble/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ android_test_helper_app { "androidx.test.rules", "bluetooth-test-util-lib", "compatibility-device-util-axt", "flag-junit", "grpc-java-lite", "grpc-java-okhttp-client-lite", "mockito-kotlin2", Loading framework/tests/bumble/src/android/bluetooth/GattClientTest.java +28 −3 Original line number Diff line number Diff line Loading @@ -31,10 +31,14 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import android.bluetooth.le.BluetoothLeScanner; import android.content.Context; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.android.bluetooth.flags.Flags; import com.android.compatibility.common.util.AdoptShellPermissionsRule; import org.junit.ClassRule; Loading @@ -45,6 +49,9 @@ import org.junit.runner.RunWith; import org.mockito.InOrder; import org.mockito.invocation.Invocation; import java.util.Collection; import java.util.UUID; import pandora.GattProto.GattCharacteristicParams; import pandora.GattProto.GattServiceParams; import pandora.GattProto.RegisterServiceRequest; Loading @@ -52,9 +59,6 @@ import pandora.HostProto.AdvertiseRequest; import pandora.HostProto.AdvertiseResponse; import pandora.HostProto.OwnAddressType; import java.util.Collection; import java.util.UUID; @RunWith(AndroidJUnit4.class) public class GattClientTest { private static final String TAG = "GattClientTest"; Loading @@ -68,6 +72,9 @@ public class GattClientTest { @Rule public final PandoraDevice mBumble = new PandoraDevice(); @Rule public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); private final Context mContext = ApplicationProvider.getApplicationContext(); private final BluetoothManager mManager = mContext.getSystemService(BluetoothManager.class); private final BluetoothAdapter mAdapter = mManager.getAdapter(); Loading Loading @@ -221,6 +228,24 @@ public class GattClientTest { } } @Test @RequiresFlagsEnabled(Flags.FLAG_ENUMERATE_GATT_ERRORS) public void connectTimeout() { BluetoothDevice device = mAdapter.getRemoteLeDevice( Utils.BUMBLE_RANDOM_ADDRESS, BluetoothDevice.ADDRESS_TYPE_RANDOM); BluetoothGattCallback gattCallback = mock(BluetoothGattCallback.class); // Connecting to a device not advertising results in connection timeout after 30 seconds device.connectGatt(mContext, false, gattCallback); verify(gattCallback, timeout(35000)) .onConnectionStateChange( any(), eq(BluetoothGatt.GATT_CONNECTION_TIMEOUT), eq(BluetoothProfile.STATE_DISCONNECTED)); } private void registerWritableGattService() { String characteristicUuidString = "11111111-1111-1111-1111-111111111111"; Loading system/bta/gatt/bta_gattc_act.cc +17 −5 Original line number Diff line number Diff line Loading @@ -358,12 +358,24 @@ void bta_gattc_open_error(tBTA_GATTC_CLCB* p_clcb, void bta_gattc_open_fail(tBTA_GATTC_CLCB* p_clcb, UNUSED_ATTR const tBTA_GATTC_DATA* p_data) { if (IS_FLAG_ENABLED(enumerate_gatt_errors) && p_data->int_conn.reason == GATT_CONN_TIMEOUT) { LOG(WARNING) << __func__ << ": Connection timed out after 30 seconds. conn_id=" << loghex(p_clcb->bta_conn_id) << ". Return GATT_CONNECTION_TIMEOUT(" << +GATT_CONNECTION_TIMEOUT << ")"; bta_gattc_send_open_cback(p_clcb->p_rcb, GATT_CONNECTION_TIMEOUT, p_clcb->bda, p_clcb->bta_conn_id, p_clcb->transport, 0); } else { LOG(WARNING) << __func__ << ": Cannot establish Connection. conn_id=" << loghex(p_clcb->bta_conn_id) << ". Return GATT_ERROR(" << +GATT_ERROR << ")"; bta_gattc_send_open_cback(p_clcb->p_rcb, GATT_ERROR, p_clcb->bda, p_clcb->bta_conn_id, p_clcb->transport, 0); } /* open failure, remove clcb */ bta_gattc_clcb_dealloc(p_clcb); } Loading Loading
framework/api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -627,6 +627,7 @@ package android.bluetooth { field public static final int CONNECTION_PRIORITY_HIGH = 1; // 0x1 field public static final int CONNECTION_PRIORITY_LOW_POWER = 2; // 0x2 field public static final int GATT_CONNECTION_CONGESTED = 143; // 0x8f field @FlaggedApi("com.android.bluetooth.flags.enumerate_gatt_errors") public static final int GATT_CONNECTION_TIMEOUT = 147; // 0x93 field public static final int GATT_FAILURE = 257; // 0x101 field public static final int GATT_INSUFFICIENT_AUTHENTICATION = 5; // 0x5 field public static final int GATT_INSUFFICIENT_AUTHORIZATION = 8; // 0x8 Loading
framework/java/android/bluetooth/BluetoothGatt.java +9 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package android.bluetooth; import static android.bluetooth.BluetoothUtils.getSyncTimeout; import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.RequiresNoPermission; Loading @@ -35,6 +36,7 @@ import android.os.ParcelUuid; import android.os.RemoteException; import android.util.Log; import com.android.bluetooth.flags.Flags; import com.android.modules.utils.SynchronousResultReceiver; import java.lang.annotation.Retention; Loading Loading @@ -128,6 +130,13 @@ public final class BluetoothGatt implements BluetoothProfile { /** A remote device connection is congested. */ public static final int GATT_CONNECTION_CONGESTED = 0x8f; /** * GATT connection timed out, likely due to the remote device being out of range or not * advertising as connectable. */ @FlaggedApi(Flags.FLAG_ENUMERATE_GATT_ERRORS) public static final int GATT_CONNECTION_TIMEOUT = 0x93; /** A GATT operation failed, errors other than the above */ public static final int GATT_FAILURE = 0x101; Loading
framework/tests/bumble/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ android_test_helper_app { "androidx.test.rules", "bluetooth-test-util-lib", "compatibility-device-util-axt", "flag-junit", "grpc-java-lite", "grpc-java-okhttp-client-lite", "mockito-kotlin2", Loading
framework/tests/bumble/src/android/bluetooth/GattClientTest.java +28 −3 Original line number Diff line number Diff line Loading @@ -31,10 +31,14 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import android.bluetooth.le.BluetoothLeScanner; import android.content.Context; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.android.bluetooth.flags.Flags; import com.android.compatibility.common.util.AdoptShellPermissionsRule; import org.junit.ClassRule; Loading @@ -45,6 +49,9 @@ import org.junit.runner.RunWith; import org.mockito.InOrder; import org.mockito.invocation.Invocation; import java.util.Collection; import java.util.UUID; import pandora.GattProto.GattCharacteristicParams; import pandora.GattProto.GattServiceParams; import pandora.GattProto.RegisterServiceRequest; Loading @@ -52,9 +59,6 @@ import pandora.HostProto.AdvertiseRequest; import pandora.HostProto.AdvertiseResponse; import pandora.HostProto.OwnAddressType; import java.util.Collection; import java.util.UUID; @RunWith(AndroidJUnit4.class) public class GattClientTest { private static final String TAG = "GattClientTest"; Loading @@ -68,6 +72,9 @@ public class GattClientTest { @Rule public final PandoraDevice mBumble = new PandoraDevice(); @Rule public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); private final Context mContext = ApplicationProvider.getApplicationContext(); private final BluetoothManager mManager = mContext.getSystemService(BluetoothManager.class); private final BluetoothAdapter mAdapter = mManager.getAdapter(); Loading Loading @@ -221,6 +228,24 @@ public class GattClientTest { } } @Test @RequiresFlagsEnabled(Flags.FLAG_ENUMERATE_GATT_ERRORS) public void connectTimeout() { BluetoothDevice device = mAdapter.getRemoteLeDevice( Utils.BUMBLE_RANDOM_ADDRESS, BluetoothDevice.ADDRESS_TYPE_RANDOM); BluetoothGattCallback gattCallback = mock(BluetoothGattCallback.class); // Connecting to a device not advertising results in connection timeout after 30 seconds device.connectGatt(mContext, false, gattCallback); verify(gattCallback, timeout(35000)) .onConnectionStateChange( any(), eq(BluetoothGatt.GATT_CONNECTION_TIMEOUT), eq(BluetoothProfile.STATE_DISCONNECTED)); } private void registerWritableGattService() { String characteristicUuidString = "11111111-1111-1111-1111-111111111111"; Loading
system/bta/gatt/bta_gattc_act.cc +17 −5 Original line number Diff line number Diff line Loading @@ -358,12 +358,24 @@ void bta_gattc_open_error(tBTA_GATTC_CLCB* p_clcb, void bta_gattc_open_fail(tBTA_GATTC_CLCB* p_clcb, UNUSED_ATTR const tBTA_GATTC_DATA* p_data) { if (IS_FLAG_ENABLED(enumerate_gatt_errors) && p_data->int_conn.reason == GATT_CONN_TIMEOUT) { LOG(WARNING) << __func__ << ": Connection timed out after 30 seconds. conn_id=" << loghex(p_clcb->bta_conn_id) << ". Return GATT_CONNECTION_TIMEOUT(" << +GATT_CONNECTION_TIMEOUT << ")"; bta_gattc_send_open_cback(p_clcb->p_rcb, GATT_CONNECTION_TIMEOUT, p_clcb->bda, p_clcb->bta_conn_id, p_clcb->transport, 0); } else { LOG(WARNING) << __func__ << ": Cannot establish Connection. conn_id=" << loghex(p_clcb->bta_conn_id) << ". Return GATT_ERROR(" << +GATT_ERROR << ")"; bta_gattc_send_open_cback(p_clcb->p_rcb, GATT_ERROR, p_clcb->bda, p_clcb->bta_conn_id, p_clcb->transport, 0); } /* open failure, remove clcb */ bta_gattc_clcb_dealloc(p_clcb); } Loading