1 /* 2 * Copyright (C) 2021 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 import static android.Manifest.permission.BLUETOOTH_PRIVILEGED; 21 import static android.bluetooth.BluetoothDevice.ACCESS_ALLOWED; 22 import static android.bluetooth.BluetoothDevice.ACCESS_REJECTED; 23 import static android.bluetooth.BluetoothDevice.ACCESS_UNKNOWN; 24 import static android.bluetooth.BluetoothDevice.TRANSPORT_AUTO; 25 import static android.bluetooth.BluetoothDevice.TRANSPORT_BREDR; 26 import static android.bluetooth.BluetoothDevice.TRANSPORT_LE; 27 28 import static com.android.compatibility.common.util.SystemUtil.runShellCommand; 29 30 import static org.junit.Assert.assertEquals; 31 import static org.junit.Assert.assertFalse; 32 import static org.junit.Assert.assertNull; 33 import static org.junit.Assert.assertThrows; 34 import static org.junit.Assert.assertTrue; 35 import static org.junit.Assume.assumeTrue; 36 37 import android.app.UiAutomation; 38 import android.bluetooth.BluetoothAdapter; 39 import android.bluetooth.BluetoothDevice; 40 import android.bluetooth.BluetoothManager; 41 import android.bluetooth.BluetoothProfile; 42 import android.bluetooth.BluetoothSinkAudioPolicy; 43 import android.bluetooth.BluetoothSocket; 44 import android.bluetooth.BluetoothSocketException; 45 import android.bluetooth.BluetoothStatusCodes; 46 import android.bluetooth.OobData; 47 import android.content.AttributionSource; 48 import android.content.Context; 49 import android.content.pm.PackageManager; 50 import android.platform.test.annotations.RequiresFlagsEnabled; 51 import android.platform.test.flag.junit.CheckFlagsRule; 52 import android.platform.test.flag.junit.DeviceFlagsValueProvider; 53 54 import androidx.test.ext.junit.runners.AndroidJUnit4; 55 import androidx.test.filters.LargeTest; 56 import androidx.test.platform.app.InstrumentationRegistry; 57 58 import com.android.bluetooth.flags.Flags; 59 60 import org.junit.After; 61 import org.junit.Before; 62 import org.junit.Rule; 63 import org.junit.Test; 64 import org.junit.runner.RunWith; 65 66 import java.io.IOException; 67 import java.io.UnsupportedEncodingException; 68 import java.util.UUID; 69 70 @RunWith(AndroidJUnit4.class) 71 @LargeTest 72 public class BluetoothDeviceTest { 73 74 private Context mContext; 75 private boolean mHasBluetooth; 76 private boolean mHasCompanionDevice; 77 private BluetoothAdapter mAdapter; 78 private UiAutomation mUiAutomation;; 79 80 private final String mFakeDeviceAddress = "00:11:22:AA:BB:CC"; 81 private BluetoothDevice mFakeDevice; 82 private int mFakePsm = 100; 83 private UUID mFakeUuid = UUID.fromString("0000111E-0000-1000-8000-00805F9B34FB"); 84 85 @Rule 86 public final CheckFlagsRule mCheckFlagsRule = 87 DeviceFlagsValueProvider.createCheckFlagsRule(); 88 89 @Before setUp()90 public void setUp() throws Exception { 91 mContext = InstrumentationRegistry.getInstrumentation().getContext(); 92 93 mHasBluetooth = mContext.getPackageManager().hasSystemFeature( 94 PackageManager.FEATURE_BLUETOOTH); 95 96 mHasCompanionDevice = mContext.getPackageManager().hasSystemFeature( 97 PackageManager.FEATURE_COMPANION_DEVICE_SETUP); 98 99 if (mHasBluetooth && mHasCompanionDevice) { 100 BluetoothManager manager = mContext.getSystemService(BluetoothManager.class); 101 mAdapter = manager.getAdapter(); 102 mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 103 mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT); 104 assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext)); 105 mFakeDevice = mAdapter.getRemoteDevice(mFakeDeviceAddress); 106 } 107 } 108 109 @After tearDown()110 public void tearDown() throws Exception { 111 if (mHasBluetooth && mHasCompanionDevice) { 112 mAdapter = null; 113 mUiAutomation.dropShellPermissionIdentity(); 114 } 115 } 116 117 @Test setAlias_getAlias()118 public void setAlias_getAlias() { 119 // Skip the test if bluetooth or companion device are not present. 120 assumeTrue(mHasBluetooth && mHasCompanionDevice); 121 122 int userId = mContext.getUser().getIdentifier(); 123 String packageName = mContext.getOpPackageName(); 124 125 AttributionSource source = AttributionSource.myAttributionSource(); 126 assertEquals("android.bluetooth.cts", source.getPackageName()); 127 128 // Verifies that when there is no alias, we return the device name 129 assertNull(mFakeDevice.getAlias()); 130 131 assertThrows(IllegalArgumentException.class, () -> mFakeDevice.setAlias("")); 132 133 String testDeviceAlias = "Test Device Alias"; 134 135 // This should throw a SecurityException because there is no CDM association 136 assertThrows("BluetoothDevice.setAlias without" 137 + " a CDM association or BLUETOOTH_PRIVILEGED permission", 138 SecurityException.class, () -> mFakeDevice.setAlias(testDeviceAlias)); 139 140 runShellCommand(String.format( 141 "cmd companiondevice associate %d %s %s", userId, packageName, mFakeDeviceAddress)); 142 String output = runShellCommand("dumpsys companiondevice"); 143 assertTrue("Package name missing from output", output.contains(packageName)); 144 assertTrue("Device address missing from output", 145 output.toLowerCase().contains(mFakeDeviceAddress.toLowerCase())); 146 147 // Takes time to update the CDM cache, so sleep to ensure the association is cached 148 try { 149 Thread.sleep(1000); 150 } catch (Exception e) { 151 e.printStackTrace(); 152 } 153 154 /* 155 * Device properties don't exist for non-existent BluetoothDevice, so calling setAlias with 156 * permissions should return false 157 */ 158 assertEquals(BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED, mFakeDevice 159 .setAlias(testDeviceAlias)); 160 runShellCommand(String.format("cmd companiondevice disassociate %d %s %s", userId, 161 packageName, mFakeDeviceAddress)); 162 163 assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext)); 164 assertNull(mFakeDevice.getAlias()); 165 assertEquals(BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED, 166 mFakeDevice.setAlias(testDeviceAlias)); 167 } 168 169 @Test 170 @RequiresFlagsEnabled(Flags.FLAG_GET_ADDRESS_TYPE_API) getAddressType()171 public void getAddressType() { 172 // Skip the test if bluetooth or companion device are not present. 173 assumeTrue(mHasBluetooth && mHasCompanionDevice); 174 175 assertEquals(BluetoothDevice.ADDRESS_TYPE_PUBLIC, mFakeDevice.getAddressType()); 176 } 177 178 @Test getIdentityAddress()179 public void getIdentityAddress() { 180 // Skip the test if bluetooth or companion device are not present. 181 assumeTrue(mHasBluetooth && mHasCompanionDevice); 182 183 // This should throw a SecurityException because no BLUETOOTH_PRIVILEGED permission 184 assertThrows("No BLUETOOTH_PRIVILEGED permission", SecurityException.class, 185 () -> mFakeDevice.getIdentityAddress()); 186 } 187 188 @Test getConnectionHandle()189 public void getConnectionHandle() { 190 // Skip the test if bluetooth or companion device are not present. 191 assumeTrue(mHasBluetooth && mHasCompanionDevice); 192 193 // This should throw a SecurityException because no BLUETOOTH_PRIVILEGED permission 194 assertThrows("No BLUETOOTH_PRIVILEGED permission", SecurityException.class, 195 () -> mFakeDevice.getConnectionHandle(TRANSPORT_LE)); 196 197 // but it should work after we get the permission 198 mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED); 199 var handle = mFakeDevice.getConnectionHandle(TRANSPORT_LE); 200 assertEquals(handle, BluetoothDevice.ERROR); 201 } 202 203 @Test getAnonymizedAddress()204 public void getAnonymizedAddress() { 205 // Skip the test if bluetooth or companion device are not present. 206 assumeTrue(mHasBluetooth && mHasCompanionDevice); 207 208 assertEquals("XX:XX:XX:XX:BB:CC", mFakeDevice.getAnonymizedAddress()); 209 } 210 211 @Test getBatteryLevel()212 public void getBatteryLevel() { 213 // Skip the test if bluetooth or companion device are not present. 214 assumeTrue(mHasBluetooth && mHasCompanionDevice); 215 216 assertEquals(BluetoothDevice.BATTERY_LEVEL_UNKNOWN, mFakeDevice.getBatteryLevel()); 217 218 mUiAutomation.dropShellPermissionIdentity(); 219 assertThrows(SecurityException.class, () -> mFakeDevice.getBatteryLevel()); 220 mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT); 221 222 assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext)); 223 assertEquals(BluetoothDevice.BATTERY_LEVEL_BLUETOOTH_OFF, mFakeDevice.getBatteryLevel()); 224 } 225 226 @Test isBondingInitiatedLocally()227 public void isBondingInitiatedLocally() { 228 // Skip the test if bluetooth or companion device are not present. 229 assumeTrue(mHasBluetooth && mHasCompanionDevice); 230 231 assertFalse(mFakeDevice.isBondingInitiatedLocally()); 232 233 mUiAutomation.dropShellPermissionIdentity(); 234 assertThrows(SecurityException.class, () -> mFakeDevice.isBondingInitiatedLocally()); 235 mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT); 236 237 assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext)); 238 assertFalse(mFakeDevice.isBondingInitiatedLocally()); 239 } 240 241 @Test prepareToEnterProcess()242 public void prepareToEnterProcess() { 243 // Skip the test if bluetooth or companion device are not present. 244 assumeTrue(mHasBluetooth && mHasCompanionDevice); 245 246 mFakeDevice.prepareToEnterProcess(null); 247 } 248 249 @Test setPin()250 public void setPin() { 251 // Skip the test if bluetooth or companion device are not present. 252 assumeTrue(mHasBluetooth && mHasCompanionDevice); 253 254 assertFalse(mFakeDevice.setPin((String) null)); 255 assertFalse(mFakeDevice.setPin("12345678901234567")); // check PIN too big 256 257 assertFalse(mFakeDevice.setPin("123456")); //device is not bonding 258 259 mUiAutomation.dropShellPermissionIdentity(); 260 assertThrows(SecurityException.class, () -> mFakeDevice.setPin("123456")); 261 mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT); 262 263 assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext)); 264 assertFalse(mFakeDevice.setPin("123456")); 265 } 266 267 @Test connect_disconnect()268 public void connect_disconnect() { 269 // Skip the test if bluetooth or companion device are not present. 270 assumeTrue(mHasBluetooth && mHasCompanionDevice); 271 272 // This should throw a SecurityException because no BLUETOOTH_PRIVILEGED permission 273 assertThrows(SecurityException.class, () -> mFakeDevice.connect()); 274 assertThrows(SecurityException.class, () -> mFakeDevice.disconnect()); 275 } 276 277 @Test cancelBondProcess()278 public void cancelBondProcess() { 279 // Skip the test if bluetooth or companion device are not present. 280 assumeTrue(mHasBluetooth && mHasCompanionDevice); 281 282 mUiAutomation.dropShellPermissionIdentity(); 283 assertThrows(SecurityException.class, () -> mFakeDevice.cancelBondProcess()); 284 mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT); 285 286 assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext)); 287 assertFalse(mFakeDevice.cancelBondProcess()); 288 } 289 290 @Test createBond()291 public void createBond() { 292 // Skip the test if bluetooth or companion device are not present. 293 assumeTrue(mHasBluetooth && mHasCompanionDevice); 294 295 mUiAutomation.dropShellPermissionIdentity(); 296 assertThrows(SecurityException.class, () -> mFakeDevice.createBond(TRANSPORT_AUTO)); 297 mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT); 298 299 assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext)); 300 assertFalse(mFakeDevice.createBond(TRANSPORT_AUTO)); 301 } 302 303 @Test createBondOutOfBand()304 public void createBondOutOfBand() { 305 // Skip the test if bluetooth or companion device are not present. 306 assumeTrue(mHasBluetooth && mHasCompanionDevice); 307 308 OobData data = new OobData.ClassicBuilder( 309 new byte[16], new byte[2], new byte[7]).build(); 310 311 assertThrows(IllegalArgumentException.class, () -> mFakeDevice.createBondOutOfBand( 312 TRANSPORT_AUTO, null, null)); 313 314 mUiAutomation.dropShellPermissionIdentity(); 315 assertThrows(SecurityException.class, () -> mFakeDevice 316 .createBondOutOfBand(TRANSPORT_AUTO, data, null)); 317 mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT); 318 } 319 320 @Test getUuids()321 public void getUuids() { 322 // Skip the test if bluetooth or companion device are not present. 323 assumeTrue(mHasBluetooth && mHasCompanionDevice); 324 325 assertNull(mFakeDevice.getUuids()); 326 mUiAutomation.dropShellPermissionIdentity(); 327 assertThrows(SecurityException.class, () -> mFakeDevice.getUuids()); 328 mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT); 329 330 assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext)); 331 assertNull(mFakeDevice.getUuids()); 332 } 333 334 @Test isEncrypted()335 public void isEncrypted() { 336 // Skip the test if bluetooth or companion device are not present. 337 assumeTrue(mHasBluetooth && mHasCompanionDevice); 338 339 //Device is not connected 340 assertFalse(mFakeDevice.isEncrypted()); 341 342 mUiAutomation.dropShellPermissionIdentity(); 343 assertThrows(SecurityException.class, () -> mFakeDevice.isEncrypted()); 344 mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT); 345 346 assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext)); 347 assertFalse(mFakeDevice.isEncrypted()); 348 } 349 350 @Test removeBond()351 public void removeBond() { 352 // Skip the test if bluetooth or companion device are not present. 353 assumeTrue(mHasBluetooth && mHasCompanionDevice); 354 355 //Device is not bonded 356 assertFalse(mFakeDevice.removeBond()); 357 358 mUiAutomation.dropShellPermissionIdentity(); 359 assertThrows(SecurityException.class, () -> mFakeDevice.removeBond()); 360 mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT); 361 362 assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext)); 363 assertFalse(mFakeDevice.removeBond()); 364 } 365 366 @Test setPinByteArray()367 public void setPinByteArray() { 368 // Skip the test if bluetooth or companion device are not present. 369 assumeTrue(mHasBluetooth && mHasCompanionDevice); 370 371 assertThrows(NullPointerException.class, () -> mFakeDevice.setPin((byte[]) null)); 372 373 // check PIN too big 374 assertFalse(mFakeDevice.setPin(convertPinToBytes("12345678901234567"))); 375 assertFalse(mFakeDevice.setPin(convertPinToBytes("123456"))); // device is not bonding 376 377 mUiAutomation.dropShellPermissionIdentity(); 378 assertThrows(SecurityException.class, () -> mFakeDevice 379 .setPin(convertPinToBytes("123456"))); 380 mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT); 381 382 assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext)); 383 assertFalse(mFakeDevice.setPin(convertPinToBytes("123456"))); 384 } 385 386 @Test connectGatt()387 public void connectGatt() { 388 // Skip the test if bluetooth or companion device are not present. 389 assumeTrue(mHasBluetooth && mHasCompanionDevice); 390 391 assertThrows(NullPointerException.class, () -> mFakeDevice 392 .connectGatt(mContext, false, null, 393 TRANSPORT_AUTO, BluetoothDevice.PHY_LE_1M_MASK)); 394 395 assertThrows(NullPointerException.class, () -> 396 mFakeDevice.connectGatt(mContext, false, null, 397 TRANSPORT_AUTO, BluetoothDevice.PHY_LE_1M_MASK, null)); 398 } 399 400 @Test fetchUuidsWithSdp()401 public void fetchUuidsWithSdp() { 402 // Skip the test if bluetooth or companion device are not present. 403 assumeTrue(mHasBluetooth && mHasCompanionDevice); 404 405 // TRANSPORT_AUTO doesn't need BLUETOOTH_PRIVILEGED permission 406 assertTrue(mFakeDevice.fetchUuidsWithSdp(TRANSPORT_AUTO)); 407 408 // This should throw a SecurityException because no BLUETOOTH_PRIVILEGED permission 409 assertThrows(SecurityException.class, () -> mFakeDevice.fetchUuidsWithSdp(TRANSPORT_BREDR)); 410 assertThrows(SecurityException.class, () -> mFakeDevice.fetchUuidsWithSdp(TRANSPORT_LE)); 411 412 assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext)); 413 assertFalse(mFakeDevice.fetchUuidsWithSdp(TRANSPORT_AUTO)); 414 } 415 416 @Test messageAccessPermission()417 public void messageAccessPermission() { 418 // Skip the test if bluetooth or companion device are not present 419 // or if MAP is not enabled. 420 assumeTrue(mHasBluetooth && mHasCompanionDevice 421 && TestUtils.isProfileEnabled(BluetoothProfile.MAP)); 422 423 // This should throw a SecurityException because no BLUETOOTH_PRIVILEGED permission 424 assertThrows(SecurityException.class, () -> mFakeDevice 425 .setMessageAccessPermission(ACCESS_ALLOWED)); 426 assertThrows(SecurityException.class, () -> mFakeDevice 427 .setMessageAccessPermission(ACCESS_UNKNOWN)); 428 assertThrows(SecurityException.class, () -> mFakeDevice 429 .setMessageAccessPermission(ACCESS_REJECTED)); 430 431 TestUtils.adoptPermissionAsShellUid(BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED); 432 433 // Should be able to set permissions after adopting the BLUETOOTH_PRIVILEGED permission 434 assertTrue(mFakeDevice.setMessageAccessPermission(ACCESS_UNKNOWN)); 435 assertEquals(ACCESS_UNKNOWN, mFakeDevice.getMessageAccessPermission()); 436 assertTrue(mFakeDevice.setMessageAccessPermission(ACCESS_ALLOWED)); 437 assertEquals(ACCESS_ALLOWED, mFakeDevice.getMessageAccessPermission()); 438 assertTrue(mFakeDevice.setMessageAccessPermission(ACCESS_REJECTED)); 439 assertEquals(ACCESS_REJECTED, mFakeDevice.getMessageAccessPermission()); 440 } 441 442 @Test phonebookAccessPermission()443 public void phonebookAccessPermission() { 444 // Skip the test if bluetooth or companion device are not present 445 // or if PBAP is not enabled. 446 assumeTrue(mHasBluetooth && mHasCompanionDevice 447 && TestUtils.isProfileEnabled(BluetoothProfile.PBAP)); 448 449 // This should throw a SecurityException because no BLUETOOTH_PRIVILEGED permission 450 assertThrows(SecurityException.class, () -> mFakeDevice 451 .setPhonebookAccessPermission(ACCESS_ALLOWED)); 452 assertThrows(SecurityException.class, () -> mFakeDevice 453 .setPhonebookAccessPermission(ACCESS_UNKNOWN)); 454 assertThrows(SecurityException.class, () -> mFakeDevice 455 .setPhonebookAccessPermission(ACCESS_REJECTED)); 456 457 TestUtils.adoptPermissionAsShellUid(BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED); 458 459 // Should be able to set permissions after adopting the BLUETOOTH_PRIVILEGED permission 460 assertTrue(mFakeDevice.setPhonebookAccessPermission(ACCESS_UNKNOWN)); 461 assertEquals(ACCESS_UNKNOWN, mFakeDevice.getPhonebookAccessPermission()); 462 assertTrue(mFakeDevice.setPhonebookAccessPermission(ACCESS_ALLOWED)); 463 assertEquals(ACCESS_ALLOWED, mFakeDevice.getPhonebookAccessPermission()); 464 assertTrue(mFakeDevice.setPhonebookAccessPermission(ACCESS_REJECTED)); 465 assertEquals(ACCESS_REJECTED, mFakeDevice.getPhonebookAccessPermission()); 466 } 467 468 @Test simAccessPermission()469 public void simAccessPermission() { 470 // Skip the test if bluetooth or companion device are not present 471 // or if SAP is not enabled. 472 assumeTrue(mHasBluetooth && mHasCompanionDevice 473 && TestUtils.isProfileEnabled(BluetoothProfile.SAP)); 474 475 // This should throw a SecurityException because no BLUETOOTH_PRIVILEGED permission 476 assertThrows(SecurityException.class, () -> mFakeDevice 477 .setSimAccessPermission(ACCESS_ALLOWED)); 478 assertThrows(SecurityException.class, () -> mFakeDevice 479 .setSimAccessPermission(ACCESS_UNKNOWN)); 480 assertThrows(SecurityException.class, () -> mFakeDevice 481 .setSimAccessPermission(ACCESS_REJECTED)); 482 483 TestUtils.adoptPermissionAsShellUid(BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED); 484 485 // Should be able to set permissions after adopting the BLUETOOTH_PRIVILEGED permission 486 assertTrue(mFakeDevice.setSimAccessPermission(ACCESS_UNKNOWN)); 487 assertEquals(ACCESS_UNKNOWN, mFakeDevice.getSimAccessPermission()); 488 assertTrue(mFakeDevice.setSimAccessPermission(ACCESS_ALLOWED)); 489 assertEquals(ACCESS_ALLOWED, mFakeDevice.getSimAccessPermission()); 490 assertTrue(mFakeDevice.setSimAccessPermission(ACCESS_REJECTED)); 491 assertEquals(ACCESS_REJECTED, mFakeDevice.getSimAccessPermission()); 492 } 493 494 @Test isRequestAudioPolicyAsSinkSupported()495 public void isRequestAudioPolicyAsSinkSupported() { 496 // Skip the test if bluetooth or companion device are not present. 497 assumeTrue(mHasBluetooth && mHasCompanionDevice); 498 499 assertThrows(SecurityException.class, 500 () -> mFakeDevice.isRequestAudioPolicyAsSinkSupported()); 501 502 TestUtils.adoptPermissionAsShellUid(BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED); 503 504 assertEquals(BluetoothStatusCodes.FEATURE_NOT_CONFIGURED, 505 mFakeDevice.isRequestAudioPolicyAsSinkSupported()); 506 } 507 508 @Test setGetAudioPolicy()509 public void setGetAudioPolicy() { 510 // Skip the test if bluetooth or companion device are not present. 511 assumeTrue(mHasBluetooth && mHasCompanionDevice); 512 513 BluetoothSinkAudioPolicy demoAudioPolicy = new BluetoothSinkAudioPolicy.Builder().build(); 514 515 // This should throw a SecurityException because no BLUETOOTH_PRIVILEGED permission 516 assertThrows(SecurityException.class, 517 () -> mFakeDevice.requestAudioPolicyAsSink(demoAudioPolicy)); 518 assertThrows(SecurityException.class, () -> mFakeDevice.getRequestedAudioPolicyAsSink()); 519 520 TestUtils.adoptPermissionAsShellUid(BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED); 521 522 assertEquals(BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED, 523 mFakeDevice.requestAudioPolicyAsSink(demoAudioPolicy)); 524 assertNull(mFakeDevice.getRequestedAudioPolicyAsSink()); 525 526 BluetoothSinkAudioPolicy newPolicy = new BluetoothSinkAudioPolicy.Builder(demoAudioPolicy) 527 .setCallEstablishPolicy(BluetoothSinkAudioPolicy.POLICY_ALLOWED) 528 .setActiveDevicePolicyAfterConnection(BluetoothSinkAudioPolicy.POLICY_NOT_ALLOWED) 529 .setInBandRingtonePolicy(BluetoothSinkAudioPolicy.POLICY_ALLOWED) 530 .build(); 531 532 assertEquals(BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED, 533 mFakeDevice.requestAudioPolicyAsSink(newPolicy)); 534 assertNull(mFakeDevice.getRequestedAudioPolicyAsSink()); 535 536 assertEquals(BluetoothSinkAudioPolicy.POLICY_ALLOWED, newPolicy.getCallEstablishPolicy()); 537 assertEquals(BluetoothSinkAudioPolicy.POLICY_NOT_ALLOWED, 538 newPolicy.getActiveDevicePolicyAfterConnection()); 539 assertEquals(BluetoothSinkAudioPolicy.POLICY_ALLOWED, newPolicy.getInBandRingtonePolicy()); 540 } 541 convertPinToBytes(String pin)542 private byte[] convertPinToBytes(String pin) { 543 if (pin == null) { 544 return null; 545 } 546 byte[] pinBytes; 547 try { 548 pinBytes = pin.getBytes("UTF-8"); 549 } catch (UnsupportedEncodingException uee) { 550 return null; 551 } 552 return pinBytes; 553 } 554 555 @Test getPackageNameOfBondingApplication()556 public void getPackageNameOfBondingApplication() { 557 // Skip the test if bluetooth or companion device are not present. 558 assumeTrue(mHasBluetooth && mHasCompanionDevice); 559 560 mUiAutomation.dropShellPermissionIdentity(); 561 assertThrows(SecurityException.class, 562 () -> mFakeDevice.getPackageNameOfBondingApplication()); 563 mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT); 564 assertThrows(SecurityException.class, 565 () -> mFakeDevice.getPackageNameOfBondingApplication()); 566 567 mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_PRIVILEGED, BLUETOOTH_CONNECT); 568 // Since no application actually start bonding with this device, this should return null 569 assertNull(mFakeDevice.getPackageNameOfBondingApplication()); 570 571 mFakeDevice.createBond(); 572 assertEquals(mContext.getPackageName(), 573 mFakeDevice.getPackageNameOfBondingApplication()); 574 575 // Clean up create bond 576 // Either cancel the bonding process or remove bond 577 mFakeDevice.cancelBondProcess(); 578 mFakeDevice.removeBond(); 579 } 580 581 @RequiresFlagsEnabled(Flags.FLAG_METADATA_API_INACTIVE_AUDIO_DEVICE_UPON_CONNECTION) 582 @Test setActiveAudioDevicePolicy_getActiveAudioDevicePolicy()583 public void setActiveAudioDevicePolicy_getActiveAudioDevicePolicy() { 584 if (!mHasBluetooth || !mHasCompanionDevice) { 585 // Skip the test if bluetooth or companion device are not present. 586 return; 587 } 588 String deviceAddress = "00:11:22:AA:AA:AA"; 589 BluetoothDevice device = mAdapter.getRemoteDevice(deviceAddress); 590 591 // This should throw a SecurityException because no BLUETOOTH_CONNECT permission 592 mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_PRIVILEGED); 593 assertThrows( 594 SecurityException.class, 595 () -> 596 device.setActiveAudioDevicePolicy( 597 BluetoothDevice 598 .ACTIVE_AUDIO_DEVICE_POLICY_ALL_PROFILES_INACTIVE_UPON_CONNECTION)); 599 assertThrows(SecurityException.class, () -> device.getActiveAudioDevicePolicy()); 600 601 // This should throw a SecurityException because no BLUETOOTH_PRIVILEGED permission 602 mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT); 603 assertThrows( 604 SecurityException.class, 605 () -> 606 device.setActiveAudioDevicePolicy( 607 BluetoothDevice 608 .ACTIVE_AUDIO_DEVICE_POLICY_ALL_PROFILES_INACTIVE_UPON_CONNECTION)); 609 assertThrows(SecurityException.class, () -> device.getActiveAudioDevicePolicy()); 610 611 mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED); 612 613 assertEquals( 614 BluetoothDevice.ACTIVE_AUDIO_DEVICE_POLICY_DEFAULT, 615 device.getActiveAudioDevicePolicy()); 616 assertEquals( 617 BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED, 618 device.setActiveAudioDevicePolicy( 619 BluetoothDevice 620 .ACTIVE_AUDIO_DEVICE_POLICY_ALL_PROFILES_INACTIVE_UPON_CONNECTION)); 621 } 622 @RequiresFlagsEnabled(Flags.FLAG_BT_SOCKET_API_L2CAP_CID) 623 @Test getL2capChannel()624 public void getL2capChannel() throws IOException { 625 // Skip the test if bluetooth or companion device are not present. 626 assumeTrue(mHasBluetooth && mHasCompanionDevice); 627 628 BluetoothSocket l2capSocket = mFakeDevice.createInsecureL2capChannel(mFakePsm); 629 BluetoothSocket rfcommSocket = mFakeDevice 630 .createInsecureRfcommSocketToServiceRecord(mFakeUuid); 631 632 mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED); 633 634 // This should throw a BluetoothSocketException because it is not L2CAP socket 635 assertThrows("Unknown L2CAP socket", BluetoothSocketException.class, 636 () -> rfcommSocket.getL2capLocalChannelId()); 637 assertThrows("Unknown L2CAP socket", BluetoothSocketException.class, 638 () -> rfcommSocket.getL2capRemoteChannelId()); 639 640 // This should throw a BluetoothSocketException because L2CAP socket is not connected 641 assertThrows("Socket closed", BluetoothSocketException.class, 642 () -> l2capSocket.getL2capLocalChannelId()); 643 assertThrows("Socket closed", BluetoothSocketException.class, 644 () -> l2capSocket.getL2capRemoteChannelId()); 645 } 646 } 647