• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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.cts;
18 
19 import static android.Manifest.permission.BLUETOOTH_CONNECT;
20 
21 import static com.google.common.truth.Truth.assertThat;
22 
23 import static org.junit.Assert.assertThrows;
24 
25 import android.app.UiAutomation;
26 import android.bluetooth.BluetoothAdapter;
27 import android.bluetooth.BluetoothDevice;
28 import android.bluetooth.BluetoothGattCharacteristic;
29 import android.bluetooth.BluetoothGattServer;
30 import android.bluetooth.BluetoothGattServerCallback;
31 import android.bluetooth.BluetoothGattService;
32 import android.bluetooth.BluetoothManager;
33 import android.content.Context;
34 
35 import androidx.test.ext.junit.runners.AndroidJUnit4;
36 import androidx.test.platform.app.InstrumentationRegistry;
37 
38 import com.android.compatibility.common.util.CddTest;
39 
40 import org.junit.After;
41 import org.junit.Assume;
42 import org.junit.Before;
43 import org.junit.Test;
44 import org.junit.runner.RunWith;
45 
46 import java.util.Arrays;
47 import java.util.UUID;
48 import java.util.concurrent.CountDownLatch;
49 import java.util.concurrent.TimeUnit;
50 
51 @RunWith(AndroidJUnit4.class)
52 public class BluetoothGattServerTest {
53 
54     private static final int LATCH_TIMEOUT_MS = 1000;
55     private final UUID TEST_UUID = UUID.fromString("0000110a-0000-1000-8000-00805f9b34fb");
56     private Context mContext;
57     private BluetoothAdapter mBluetoothAdapter;
58     private BluetoothGattServer mBluetoothGattServer;
59     private BluetoothManager mBluetoothManager;
60     private UiAutomation mUIAutomation;
61     private CountDownLatch mLatch;
62 
63     @Before
setUp()64     public void setUp() throws Exception {
65         mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
66 
67         Assume.assumeTrue(TestUtils.isBleSupported(mContext));
68 
69         mUIAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
70         mUIAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
71         mBluetoothAdapter = mContext.getSystemService(BluetoothManager.class).getAdapter();
72         assertThat(BTAdapterUtils.enableAdapter(mBluetoothAdapter, mContext)).isTrue();
73         mBluetoothManager = mContext.getSystemService(BluetoothManager.class);
74         mLatch = new CountDownLatch(1);
75         mBluetoothGattServer =
76                 mBluetoothManager.openGattServer(
77                         mContext,
78                         new BluetoothGattServerCallback() {
79                             @Override
80                             public void onServiceAdded(int status, BluetoothGattService service) {
81                                 mLatch.countDown();
82                             }
83                         });
84     }
85 
86     @After
tearDown()87     public void tearDown() throws Exception {
88         if (mUIAutomation != null) {
89             mUIAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
90         }
91 
92         if (mBluetoothAdapter != null && mBluetoothGattServer != null) {
93             mBluetoothGattServer.close();
94             mBluetoothGattServer = null;
95         }
96 
97         mBluetoothAdapter = null;
98         mLatch = null;
99 
100         if (mUIAutomation != null) {
101             mUIAutomation.dropShellPermissionIdentity();
102         }
103     }
104 
105     @CddTest(requirements = {"7.4.3/C-2-1", "7.4.3/C-3-2"})
106     @Test
getConnectedDevices()107     public void getConnectedDevices() {
108         assertThrows(
109                 UnsupportedOperationException.class,
110                 () -> mBluetoothGattServer.getConnectedDevices());
111     }
112 
113     @CddTest(requirements = {"7.4.3/C-2-1", "7.4.3/C-3-2"})
114     @Test
getConnectionState()115     public void getConnectionState() {
116         assertThrows(
117                 UnsupportedOperationException.class,
118                 () -> mBluetoothGattServer.getConnectionState(null));
119     }
120 
121     @CddTest(requirements = {"7.4.3/C-2-1", "7.4.3/C-3-2"})
122     @Test
getDevicesMatchingConnectionStates()123     public void getDevicesMatchingConnectionStates() {
124         assertThrows(
125                 UnsupportedOperationException.class,
126                 () -> mBluetoothGattServer.getDevicesMatchingConnectionStates(null));
127     }
128 
129     @CddTest(requirements = {"7.4.3/C-2-1", "7.4.3/C-3-2"})
130     @Test
getService()131     public void getService() throws InterruptedException {
132         // Service is null after initialization with public constructor
133         assertThat(mBluetoothGattServer.getService(TEST_UUID)).isNull();
134         BluetoothGattCharacteristic characteristic =
135                 new BluetoothGattCharacteristic(TEST_UUID, 0x0A, 0x11);
136         BluetoothGattService service =
137                 new BluetoothGattService(TEST_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY);
138 
139         service.addCharacteristic(characteristic);
140         // If service is added successfully, latch.countDown() happens in the callback
141         mBluetoothGattServer.addService(service);
142         mLatch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
143 
144         assertThat(mBluetoothGattServer.getService(TEST_UUID)).isEqualTo(service);
145     }
146 
147     @CddTest(requirements = {"7.4.3/C-2-1", "7.4.3/C-3-2"})
148     @Test
getServices()149     public void getServices() {
150         assertThat(mBluetoothGattServer.getServices()).isEmpty();
151     }
152 
153     @CddTest(requirements = {"7.4.3/C-2-1", "7.4.3/C-3-2"})
154     @Test
readPhy()155     public void readPhy() {
156         BluetoothDevice testDevice = mBluetoothAdapter.getRemoteDevice("00:11:22:AA:BB:CC");
157         mUIAutomation.dropShellPermissionIdentity();
158         assertThrows(SecurityException.class, () -> mBluetoothGattServer.readPhy(testDevice));
159     }
160 
161     @CddTest(requirements = {"7.4.3/C-2-1", "7.4.3/C-3-2"})
162     @Test
setPreferredPhy()163     public void setPreferredPhy() {
164         BluetoothDevice testDevice = mBluetoothAdapter.getRemoteDevice("00:11:22:AA:BB:CC");
165         mUIAutomation.dropShellPermissionIdentity();
166         assertThrows(
167                 SecurityException.class,
168                 () ->
169                         mBluetoothGattServer.setPreferredPhy(
170                                 testDevice,
171                                 BluetoothDevice.PHY_LE_1M_MASK,
172                                 BluetoothDevice.PHY_LE_1M_MASK,
173                                 BluetoothDevice.PHY_OPTION_NO_PREFERRED));
174     }
175 
176     @CddTest(requirements = {"7.4.3/C-2-1", "7.4.3/C-3-2"})
177     @Test
notifyCharacteristicChanged_withValueOverMaxLength()178     public void notifyCharacteristicChanged_withValueOverMaxLength() {
179         BluetoothDevice testDevice = mBluetoothAdapter.getRemoteDevice("00:11:22:AA:BB:CC");
180         BluetoothGattCharacteristic characteristic =
181                 new BluetoothGattCharacteristic(TEST_UUID, 0x0A, 0x11);
182         BluetoothGattService service =
183                 new BluetoothGattService(TEST_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY);
184         service.addCharacteristic(characteristic);
185 
186         // 512 is the max attribute length
187         byte[] notification = new byte[513];
188         Arrays.fill(notification, (byte) 0x01);
189 
190         assertThrows(
191                 IllegalArgumentException.class,
192                 () ->
193                         mBluetoothGattServer.notifyCharacteristicChanged(
194                                 testDevice, characteristic, false, notification));
195     }
196 }
197