Loading framework/tests/bumble/src/android/bluetooth/GattClientTest.java +51 −25 Original line number Diff line number Diff line Loading @@ -31,7 +31,6 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.verify; import android.bluetooth.le.BluetoothLeScanner; import android.bluetooth.test_utils.EnableBluetoothRule; import android.content.Context; import android.platform.test.annotations.RequiresFlagsEnabled; Loading @@ -40,15 +39,17 @@ import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.util.Log; import androidx.test.core.app.ApplicationProvider; import androidx.test.platform.app.InstrumentationRegistry; import com.android.bluetooth.flags.Flags; import com.android.compatibility.common.util.AdoptShellPermissionsRule; import com.google.protobuf.ByteString; import com.google.testing.junit.testparameterinjector.TestParameter; import com.google.testing.junit.testparameterinjector.TestParameterInjector; import org.junit.After; import org.junit.Assume; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; Loading @@ -73,6 +74,7 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Set; import java.util.UUID; @RunWith(TestParameterInjector.class) Loading @@ -98,15 +100,38 @@ public class GattClientTest { public final PandoraDevice mBumble = new PandoraDevice(); @Rule(order = 2) public final AdoptShellPermissionsRule mPermissionRule = new AdoptShellPermissionsRule(); @Rule(order = 3) public final EnableBluetoothRule mEnableBluetoothRule = new EnableBluetoothRule(false, true); private final Context mContext = ApplicationProvider.getApplicationContext(); private final BluetoothManager mManager = mContext.getSystemService(BluetoothManager.class); private final BluetoothAdapter mAdapter = mManager.getAdapter(); private final BluetoothLeScanner mLeScanner = mAdapter.getBluetoothLeScanner(); private Host mHost; private BluetoothDevice mRemoteLeDevice; @Before public void setUp() throws Exception { InstrumentationRegistry.getInstrumentation() .getUiAutomation() .adoptShellPermissionIdentity(); mHost = new Host(mContext); mRemoteLeDevice = mAdapter.getRemoteLeDevice( Utils.BUMBLE_RANDOM_ADDRESS, BluetoothDevice.ADDRESS_TYPE_RANDOM); mRemoteLeDevice.removeBond(); } @After public void tearUp() throws Exception { InstrumentationRegistry.getInstrumentation() .getUiAutomation() .dropShellPermissionIdentity(); Set<BluetoothDevice> bondedDevices = mAdapter.getBondedDevices(); if (bondedDevices.contains(mRemoteLeDevice)) { mRemoteLeDevice.removeBond(); } } @Test public void directConnectGattAfterClose() throws Exception { Loading Loading @@ -138,9 +163,12 @@ public class GattClientTest { } @Test public void fullGattClientLifecycle() throws Exception { public void fullGattClientLifecycle(@TestParameter boolean autoConnect) { if (autoConnect) { createLeBondAndWaitBonding(mRemoteLeDevice); } BluetoothGattCallback gattCallback = mock(BluetoothGattCallback.class); BluetoothGatt gatt = connectGattAndWaitConnection(gattCallback); BluetoothGatt gatt = connectGattAndWaitConnection(gattCallback, autoConnect); disconnectAndWaitDisconnection(gatt, gattCallback); } Loading @@ -148,13 +176,10 @@ public class GattClientTest { public void reconnectExistingClient() throws Exception { advertiseWithBumble(); BluetoothDevice device = mAdapter.getRemoteLeDevice( Utils.BUMBLE_RANDOM_ADDRESS, BluetoothDevice.ADDRESS_TYPE_RANDOM); BluetoothGattCallback gattCallback = mock(BluetoothGattCallback.class); InOrder inOrder = inOrder(gattCallback); BluetoothGatt gatt = device.connectGatt(mContext, false, gattCallback); BluetoothGatt gatt = mRemoteLeDevice.connectGatt(mContext, false, gattCallback); inOrder.verify(gattCallback, timeout(1000)) .onConnectionStateChange(any(), anyInt(), eq(STATE_CONNECTED)); Loading Loading @@ -465,30 +490,27 @@ public class GattClientTest { } private BluetoothGatt connectGattAndWaitConnection(BluetoothGattCallback callback) { return connectGattAndWaitConnection(callback, /* autoConnect= */ false); } private BluetoothGatt connectGattAndWaitConnection( BluetoothGattCallback callback, boolean autoConnect) { final int status = GATT_SUCCESS; final int state = STATE_CONNECTED; advertiseWithBumble(); BluetoothDevice device = mAdapter.getRemoteLeDevice( Utils.BUMBLE_RANDOM_ADDRESS, BluetoothDevice.ADDRESS_TYPE_RANDOM); BluetoothGatt gatt = device.connectGatt(mContext, false, callback); BluetoothGatt gatt = mRemoteLeDevice.connectGatt(mContext, autoConnect, callback); verify(callback, timeout(1000)).onConnectionStateChange(eq(gatt), eq(status), eq(state)); return gatt; } /** Tries to connect GATT, it could fail and return null. */ private BluetoothGatt tryConnectGatt(BluetoothGattCallback callback) { private BluetoothGatt tryConnectGatt(BluetoothGattCallback callback, boolean autoConnect) { advertiseWithBumble(); BluetoothDevice device = mAdapter.getRemoteLeDevice( Utils.BUMBLE_RANDOM_ADDRESS, BluetoothDevice.ADDRESS_TYPE_RANDOM); BluetoothGatt gatt = device.connectGatt(mContext, false, callback); BluetoothGatt gatt = mRemoteLeDevice.connectGatt(mContext, autoConnect, callback); ArgumentCaptor<Integer> statusCaptor = ArgumentCaptor.forClass(Integer.class); ArgumentCaptor<Integer> stateCaptor = ArgumentCaptor.forClass(Integer.class); Loading Loading @@ -596,7 +618,6 @@ public class GattClientTest { @Test @RequiresFlagsEnabled(Flags.FLAG_GATT_CLIENT_DYNAMIC_ALLOCATION) public void connectGatt_multipleClients() { advertiseWithBumble(); registerGattService(); List<BluetoothGatt> gatts = new ArrayList<>(); Loading @@ -606,7 +627,7 @@ public class GattClientTest { try { for (int i = 0; i < repeatTimes; i++) { BluetoothGattCallback gattCallback = mock(BluetoothGattCallback.class); BluetoothGatt gatt = tryConnectGatt(gattCallback); BluetoothGatt gatt = tryConnectGatt(gattCallback, false); // If it fails, close an existing gatt instance and try again. if (gatt == null) { failed = true; Loading Loading @@ -664,4 +685,9 @@ public class GattClientTest { gatt.close(); } } private void createLeBondAndWaitBonding(BluetoothDevice device) { advertiseWithBumble(); mHost.createBondAndVerify(device); } } system/bta/gatt/bta_gattc_utils.cc +15 −6 Original line number Diff line number Diff line Loading @@ -691,9 +691,12 @@ bool bta_gattc_mark_bg_conn(tGATT_IF client_if, const RawAddress& remote_bda_ptr p_bg_tck->in_use = true; p_bg_tck->remote_bda = remote_bda_ptr; if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { p_bg_tck->cif_set = {client_if}; } else { p_cif_mask = &p_bg_tck->cif_mask; *p_cif_mask = ((tBTA_GATTC_CIF_MASK)1 << (client_if - 1)); } return true; } } Loading @@ -719,12 +722,18 @@ bool bta_gattc_check_bg_conn(tGATT_IF client_if, const RawAddress& remote_bda, u for (i = 0; i < ble_acceptlist_size() && !is_bg_conn; i++, p_bg_tck++) { if (p_bg_tck->in_use && (p_bg_tck->remote_bda == remote_bda || p_bg_tck->remote_bda.IsEmpty())) { if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { if (p_bg_tck->cif_set.contains(client_if) && role == HCI_ROLE_CENTRAL) { is_bg_conn = true; } } else { if (((p_bg_tck->cif_mask & ((tBTA_GATTC_CIF_MASK)1 << (client_if - 1))) != 0) && role == HCI_ROLE_CENTRAL) { is_bg_conn = true; } } } } return is_bg_conn; } /******************************************************************************* Loading Loading
framework/tests/bumble/src/android/bluetooth/GattClientTest.java +51 −25 Original line number Diff line number Diff line Loading @@ -31,7 +31,6 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.verify; import android.bluetooth.le.BluetoothLeScanner; import android.bluetooth.test_utils.EnableBluetoothRule; import android.content.Context; import android.platform.test.annotations.RequiresFlagsEnabled; Loading @@ -40,15 +39,17 @@ import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.util.Log; import androidx.test.core.app.ApplicationProvider; import androidx.test.platform.app.InstrumentationRegistry; import com.android.bluetooth.flags.Flags; import com.android.compatibility.common.util.AdoptShellPermissionsRule; import com.google.protobuf.ByteString; import com.google.testing.junit.testparameterinjector.TestParameter; import com.google.testing.junit.testparameterinjector.TestParameterInjector; import org.junit.After; import org.junit.Assume; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; Loading @@ -73,6 +74,7 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Set; import java.util.UUID; @RunWith(TestParameterInjector.class) Loading @@ -98,15 +100,38 @@ public class GattClientTest { public final PandoraDevice mBumble = new PandoraDevice(); @Rule(order = 2) public final AdoptShellPermissionsRule mPermissionRule = new AdoptShellPermissionsRule(); @Rule(order = 3) public final EnableBluetoothRule mEnableBluetoothRule = new EnableBluetoothRule(false, true); private final Context mContext = ApplicationProvider.getApplicationContext(); private final BluetoothManager mManager = mContext.getSystemService(BluetoothManager.class); private final BluetoothAdapter mAdapter = mManager.getAdapter(); private final BluetoothLeScanner mLeScanner = mAdapter.getBluetoothLeScanner(); private Host mHost; private BluetoothDevice mRemoteLeDevice; @Before public void setUp() throws Exception { InstrumentationRegistry.getInstrumentation() .getUiAutomation() .adoptShellPermissionIdentity(); mHost = new Host(mContext); mRemoteLeDevice = mAdapter.getRemoteLeDevice( Utils.BUMBLE_RANDOM_ADDRESS, BluetoothDevice.ADDRESS_TYPE_RANDOM); mRemoteLeDevice.removeBond(); } @After public void tearUp() throws Exception { InstrumentationRegistry.getInstrumentation() .getUiAutomation() .dropShellPermissionIdentity(); Set<BluetoothDevice> bondedDevices = mAdapter.getBondedDevices(); if (bondedDevices.contains(mRemoteLeDevice)) { mRemoteLeDevice.removeBond(); } } @Test public void directConnectGattAfterClose() throws Exception { Loading Loading @@ -138,9 +163,12 @@ public class GattClientTest { } @Test public void fullGattClientLifecycle() throws Exception { public void fullGattClientLifecycle(@TestParameter boolean autoConnect) { if (autoConnect) { createLeBondAndWaitBonding(mRemoteLeDevice); } BluetoothGattCallback gattCallback = mock(BluetoothGattCallback.class); BluetoothGatt gatt = connectGattAndWaitConnection(gattCallback); BluetoothGatt gatt = connectGattAndWaitConnection(gattCallback, autoConnect); disconnectAndWaitDisconnection(gatt, gattCallback); } Loading @@ -148,13 +176,10 @@ public class GattClientTest { public void reconnectExistingClient() throws Exception { advertiseWithBumble(); BluetoothDevice device = mAdapter.getRemoteLeDevice( Utils.BUMBLE_RANDOM_ADDRESS, BluetoothDevice.ADDRESS_TYPE_RANDOM); BluetoothGattCallback gattCallback = mock(BluetoothGattCallback.class); InOrder inOrder = inOrder(gattCallback); BluetoothGatt gatt = device.connectGatt(mContext, false, gattCallback); BluetoothGatt gatt = mRemoteLeDevice.connectGatt(mContext, false, gattCallback); inOrder.verify(gattCallback, timeout(1000)) .onConnectionStateChange(any(), anyInt(), eq(STATE_CONNECTED)); Loading Loading @@ -465,30 +490,27 @@ public class GattClientTest { } private BluetoothGatt connectGattAndWaitConnection(BluetoothGattCallback callback) { return connectGattAndWaitConnection(callback, /* autoConnect= */ false); } private BluetoothGatt connectGattAndWaitConnection( BluetoothGattCallback callback, boolean autoConnect) { final int status = GATT_SUCCESS; final int state = STATE_CONNECTED; advertiseWithBumble(); BluetoothDevice device = mAdapter.getRemoteLeDevice( Utils.BUMBLE_RANDOM_ADDRESS, BluetoothDevice.ADDRESS_TYPE_RANDOM); BluetoothGatt gatt = device.connectGatt(mContext, false, callback); BluetoothGatt gatt = mRemoteLeDevice.connectGatt(mContext, autoConnect, callback); verify(callback, timeout(1000)).onConnectionStateChange(eq(gatt), eq(status), eq(state)); return gatt; } /** Tries to connect GATT, it could fail and return null. */ private BluetoothGatt tryConnectGatt(BluetoothGattCallback callback) { private BluetoothGatt tryConnectGatt(BluetoothGattCallback callback, boolean autoConnect) { advertiseWithBumble(); BluetoothDevice device = mAdapter.getRemoteLeDevice( Utils.BUMBLE_RANDOM_ADDRESS, BluetoothDevice.ADDRESS_TYPE_RANDOM); BluetoothGatt gatt = device.connectGatt(mContext, false, callback); BluetoothGatt gatt = mRemoteLeDevice.connectGatt(mContext, autoConnect, callback); ArgumentCaptor<Integer> statusCaptor = ArgumentCaptor.forClass(Integer.class); ArgumentCaptor<Integer> stateCaptor = ArgumentCaptor.forClass(Integer.class); Loading Loading @@ -596,7 +618,6 @@ public class GattClientTest { @Test @RequiresFlagsEnabled(Flags.FLAG_GATT_CLIENT_DYNAMIC_ALLOCATION) public void connectGatt_multipleClients() { advertiseWithBumble(); registerGattService(); List<BluetoothGatt> gatts = new ArrayList<>(); Loading @@ -606,7 +627,7 @@ public class GattClientTest { try { for (int i = 0; i < repeatTimes; i++) { BluetoothGattCallback gattCallback = mock(BluetoothGattCallback.class); BluetoothGatt gatt = tryConnectGatt(gattCallback); BluetoothGatt gatt = tryConnectGatt(gattCallback, false); // If it fails, close an existing gatt instance and try again. if (gatt == null) { failed = true; Loading Loading @@ -664,4 +685,9 @@ public class GattClientTest { gatt.close(); } } private void createLeBondAndWaitBonding(BluetoothDevice device) { advertiseWithBumble(); mHost.createBondAndVerify(device); } }
system/bta/gatt/bta_gattc_utils.cc +15 −6 Original line number Diff line number Diff line Loading @@ -691,9 +691,12 @@ bool bta_gattc_mark_bg_conn(tGATT_IF client_if, const RawAddress& remote_bda_ptr p_bg_tck->in_use = true; p_bg_tck->remote_bda = remote_bda_ptr; if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { p_bg_tck->cif_set = {client_if}; } else { p_cif_mask = &p_bg_tck->cif_mask; *p_cif_mask = ((tBTA_GATTC_CIF_MASK)1 << (client_if - 1)); } return true; } } Loading @@ -719,12 +722,18 @@ bool bta_gattc_check_bg_conn(tGATT_IF client_if, const RawAddress& remote_bda, u for (i = 0; i < ble_acceptlist_size() && !is_bg_conn; i++, p_bg_tck++) { if (p_bg_tck->in_use && (p_bg_tck->remote_bda == remote_bda || p_bg_tck->remote_bda.IsEmpty())) { if (com::android::bluetooth::flags::gatt_client_dynamic_allocation()) { if (p_bg_tck->cif_set.contains(client_if) && role == HCI_ROLE_CENTRAL) { is_bg_conn = true; } } else { if (((p_bg_tck->cif_mask & ((tBTA_GATTC_CIF_MASK)1 << (client_if - 1))) != 0) && role == HCI_ROLE_CENTRAL) { is_bg_conn = true; } } } } return is_bg_conn; } /******************************************************************************* Loading