1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.bluetooth;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static org.mockito.Mockito.any;
22 import static org.mockito.Mockito.anyInt;
23 import static org.mockito.Mockito.eq;
24 import static org.mockito.Mockito.mock;
25 import static org.mockito.Mockito.timeout;
26 import static org.mockito.Mockito.verify;
27 
28 import android.content.Context;
29 import android.platform.test.annotations.RequiresFlagsEnabled;
30 import android.platform.test.flag.junit.CheckFlagsRule;
31 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
32 
33 import androidx.test.core.app.ApplicationProvider;
34 import androidx.test.runner.AndroidJUnit4;
35 
36 import com.android.bluetooth.flags.Flags;
37 import com.android.compatibility.common.util.AdoptShellPermissionsRule;
38 
39 import org.junit.Ignore;
40 import org.junit.Rule;
41 import org.junit.Test;
42 import org.junit.runner.RunWith;
43 
44 import pandora.HostProto.AdvertiseRequest;
45 import pandora.HostProto.OwnAddressType;
46 
47 /** Test cases for {@link BluetoothGattServer}. */
48 @RunWith(AndroidJUnit4.class)
49 public class GattServerConnectWithoutScanTest {
50     private static final String TAG = "GattServerConnectWithoutScanTest";
51     private static final int TIMEOUT_GATT_CONNECTION_MS = 2_000;
52 
53     @Rule public final AdoptShellPermissionsRule mPermissionRule = new AdoptShellPermissionsRule();
54 
55     @Rule public final PandoraDevice mBumble = new PandoraDevice();
56 
57     @Rule
58     public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
59 
60     private final Context mContext = ApplicationProvider.getApplicationContext();
61     private final BluetoothManager mBluetoothManager =
62             mContext.getSystemService(BluetoothManager.class);
63     private final BluetoothAdapter mBluetoothAdapter = mBluetoothManager.getAdapter();
64 
65     @Test
66     @RequiresFlagsEnabled(Flags.FLAG_BLE_GATT_SERVER_USE_ADDRESS_TYPE_IN_CONNECTION)
67     @Ignore("b/343749428: Remove hidden api's dependencies to enable the test.")
serverConnectToRandomAddress_withTransportAuto()68     public void serverConnectToRandomAddress_withTransportAuto() throws Exception {
69         advertiseWithBumble(OwnAddressType.RANDOM);
70 
71         BluetoothGattServerCallback mockGattServerCallback =
72                 mock(BluetoothGattServerCallback.class);
73         BluetoothGattServer gattServer =
74                 mBluetoothManager.openGattServer(
75                         mContext, mockGattServerCallback, BluetoothDevice.TRANSPORT_AUTO);
76 
77         assertThat(gattServer).isNotNull();
78 
79         try {
80             BluetoothDevice device =
81                     mBluetoothAdapter.getRemoteLeDevice(
82                             Utils.BUMBLE_RANDOM_ADDRESS, BluetoothDevice.ADDRESS_TYPE_RANDOM);
83 
84             gattServer.connect(device, false);
85             verify(mockGattServerCallback, timeout(TIMEOUT_GATT_CONNECTION_MS))
86                     .onConnectionStateChange(any(), anyInt(), eq(BluetoothProfile.STATE_CONNECTED));
87         } finally {
88             gattServer.close();
89         }
90     }
91 
92     @Test
93     @RequiresFlagsEnabled(Flags.FLAG_BLE_GATT_SERVER_USE_ADDRESS_TYPE_IN_CONNECTION)
94     @Ignore("b/343749428: Remove hidden api's dependencies to enable the test.")
serverConnectToRandomAddress_withTransportLE()95     public void serverConnectToRandomAddress_withTransportLE() throws Exception {
96         advertiseWithBumble(OwnAddressType.RANDOM);
97 
98         BluetoothGattServerCallback mockGattServerCallback =
99                 mock(BluetoothGattServerCallback.class);
100         BluetoothGattServer gattServer =
101                 mBluetoothManager.openGattServer(
102                         mContext, mockGattServerCallback, BluetoothDevice.TRANSPORT_LE);
103 
104         assertThat(gattServer).isNotNull();
105 
106         try {
107             BluetoothDevice device =
108                     mBluetoothAdapter.getRemoteLeDevice(
109                             Utils.BUMBLE_RANDOM_ADDRESS, BluetoothDevice.ADDRESS_TYPE_RANDOM);
110 
111             gattServer.connect(device, false);
112             verify(mockGattServerCallback, timeout(TIMEOUT_GATT_CONNECTION_MS))
113                     .onConnectionStateChange(any(), anyInt(), eq(BluetoothProfile.STATE_CONNECTED));
114         } finally {
115             gattServer.close();
116         }
117     }
118 
119     @Test
120     @Ignore("b/333018293")
serverConnectToPublicAddress_withTransportAuto()121     public void serverConnectToPublicAddress_withTransportAuto() throws Exception {
122         advertiseWithBumble(OwnAddressType.PUBLIC);
123 
124         BluetoothGattServerCallback mockGattServerCallback =
125                 mock(BluetoothGattServerCallback.class);
126         BluetoothGattServer gattServer =
127                 mBluetoothManager.openGattServer(
128                         mContext, mockGattServerCallback, BluetoothDevice.TRANSPORT_AUTO);
129 
130         assertThat(gattServer).isNotNull();
131 
132         try {
133             gattServer.connect(mBumble.getRemoteDevice(), false);
134             verify(mockGattServerCallback, timeout(TIMEOUT_GATT_CONNECTION_MS))
135                     .onConnectionStateChange(any(), anyInt(), eq(BluetoothProfile.STATE_CONNECTED));
136         } finally {
137             gattServer.close();
138         }
139     }
140 
141     @Test
142     @Ignore("b/343749428: Remove hidden api's dependencies to enable the test.")
serverConnectToPublicAddress_withTransportLE()143     public void serverConnectToPublicAddress_withTransportLE() throws Exception {
144         advertiseWithBumble(OwnAddressType.PUBLIC);
145 
146         BluetoothGattServerCallback mockGattServerCallback =
147                 mock(BluetoothGattServerCallback.class);
148         BluetoothGattServer gattServer =
149                 mBluetoothManager.openGattServer(
150                         mContext, mockGattServerCallback, BluetoothDevice.TRANSPORT_LE);
151 
152         assertThat(gattServer).isNotNull();
153 
154         try {
155             gattServer.connect(mBumble.getRemoteDevice(), false);
156             verify(mockGattServerCallback, timeout(TIMEOUT_GATT_CONNECTION_MS))
157                     .onConnectionStateChange(any(), anyInt(), eq(BluetoothProfile.STATE_CONNECTED));
158         } finally {
159             gattServer.close();
160         }
161     }
162 
advertiseWithBumble(OwnAddressType ownAddressType)163     private void advertiseWithBumble(OwnAddressType ownAddressType) {
164         AdvertiseRequest request =
165                 AdvertiseRequest.newBuilder()
166                         .setLegacy(true)
167                         .setConnectable(true)
168                         .setOwnAddressType(ownAddressType)
169                         .build();
170         mBumble.hostBlocking().advertise(request);
171     }
172 }
173