1#!/usr/bin/env python3 2# 3# Copyright (C) 2016 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); you may not 6# use this file except in compliance with the License. You may obtain a copy of 7# the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14# License for the specific language governing permissions and limitations under 15# the License. 16""" 17This test script exercises different GATT connection tests. 18""" 19 20import pprint 21from queue import Empty 22import time 23 24from acts.test_decorators import test_tracker_info 25from acts.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest 26from acts.test_utils.bt.bt_constants import ble_advertise_settings_modes 27from acts.test_utils.bt.bt_constants import ble_scan_settings_modes 28from acts.test_utils.bt.bt_constants import ble_scan_settings_match_nums 29from acts.test_utils.bt.bt_constants import bt_profile_constants 30from acts.test_utils.bt.bt_constants import gatt_characteristic 31from acts.test_utils.bt.bt_constants import gatt_descriptor 32from acts.test_utils.bt.bt_constants import gatt_service_types 33from acts.test_utils.bt.bt_constants import gatt_cb_err 34from acts.test_utils.bt.bt_constants import gatt_cb_strings 35from acts.test_utils.bt.bt_constants import gatt_connection_state 36from acts.test_utils.bt.bt_constants import gatt_mtu_size 37from acts.test_utils.bt.bt_constants import gatt_phy_mask 38from acts.test_utils.bt.bt_constants import gatt_transport 39from acts.test_utils.bt.bt_constants import scan_result 40from acts.test_utils.bt.bt_gatt_utils import GattTestUtilsError 41from acts.test_utils.bt.bt_gatt_utils import disconnect_gatt_connection 42from acts.test_utils.bt.bt_gatt_utils import wait_for_gatt_disconnect_event 43from acts.test_utils.bt.bt_gatt_utils import close_gatt_client 44from acts.test_utils.bt.bt_gatt_utils import log_gatt_server_uuids 45from acts.test_utils.bt.bt_gatt_utils import orchestrate_gatt_connection 46from acts.test_utils.bt.bt_gatt_utils import setup_gatt_connection 47from acts.test_utils.bt.bt_gatt_utils import setup_multiple_services 48from acts.test_utils.bt.bt_test_utils import get_mac_address_of_generic_advertisement 49from acts.test_utils.bt.bt_test_utils import clear_bonded_devices 50 51PHYSICAL_DISCONNECT_TIMEOUT = 5 52 53 54class GattConnectTest(BluetoothBaseTest): 55 adv_instances = [] 56 bluetooth_gatt_list = [] 57 gatt_server_list = [] 58 default_timeout = 10 59 default_discovery_timeout = 3 60 61 def setup_class(self): 62 super().setup_class() 63 self.cen_ad = self.android_devices[0] 64 self.per_ad = self.android_devices[1] 65 66 def setup_test(self): 67 super(BluetoothBaseTest, self).setup_test() 68 bluetooth_gatt_list = [] 69 self.gatt_server_list = [] 70 self.adv_instances = [] 71 # Ensure there is ample time for a physical disconnect in between 72 # testcases. 73 self.log.info( 74 "Waiting for {} seconds for physical GATT disconnections".format( 75 PHYSICAL_DISCONNECT_TIMEOUT)) 76 time.sleep(PHYSICAL_DISCONNECT_TIMEOUT) 77 78 def teardown_test(self): 79 for bluetooth_gatt in self.bluetooth_gatt_list: 80 self.cen_ad.droid.gattClientClose(bluetooth_gatt) 81 for gatt_server in self.gatt_server_list: 82 self.per_ad.droid.gattServerClose(gatt_server) 83 for adv in self.adv_instances: 84 self.per_ad.droid.bleStopBleAdvertising(adv) 85 return True 86 87 def _orchestrate_gatt_disconnection(self, bluetooth_gatt, gatt_callback): 88 self.log.info("Disconnecting from peripheral device.") 89 try: 90 disconnect_gatt_connection(self.cen_ad, bluetooth_gatt, 91 gatt_callback) 92 close_gatt_client(self.cen_ad, bluetooth_gatt) 93 if bluetooth_gatt in self.bluetooth_gatt_list: 94 self.bluetooth_gatt_list.remove(bluetooth_gatt) 95 except GattTestUtilsError as err: 96 self.log.error(err) 97 return False 98 return True 99 100 def _find_service_added_event(self, gatt_server_cb, uuid): 101 expected_event = gatt_cb_strings['serv_added'].format(gatt_server_cb) 102 try: 103 event = self.per_ad.ed.pop_event(expected_event, 104 self.default_timeout) 105 except Empty: 106 self.log.error( 107 gatt_cb_strings['serv_added_err'].format(expected_event)) 108 return False 109 if event['data']['serviceUuid'].lower() != uuid.lower(): 110 self.log.error("Uuid mismatch. Found: {}, Expected {}.".format( 111 event['data']['serviceUuid'], uuid)) 112 return False 113 return True 114 115 def _verify_mtu_changed_on_client_and_server( 116 self, expected_mtu, gatt_callback, gatt_server_callback): 117 expected_event = gatt_cb_strings['mtu_changed'].format(gatt_callback) 118 try: 119 mtu_event = self.cen_ad.ed.pop_event(expected_event, 120 self.default_timeout) 121 mtu_size_found = mtu_event['data']['MTU'] 122 if mtu_size_found != expected_mtu: 123 self.log.error("MTU size found: {}, expected: {}".format( 124 mtu_size_found, expected_mtu)) 125 return False 126 except Empty: 127 self.log.error( 128 gatt_cb_err['mtu_changed_err'].format(expected_event)) 129 return False 130 131 expected_event = gatt_cb_strings['mtu_serv_changed'].format( 132 gatt_server_callback) 133 try: 134 mtu_event = self.per_ad.ed.pop_event(expected_event, 135 self.default_timeout) 136 mtu_size_found = mtu_event['data']['MTU'] 137 if mtu_size_found != expected_mtu: 138 self.log.error("MTU size found: {}, expected: {}".format( 139 mtu_size_found, expected_mtu)) 140 return False 141 except Empty: 142 self.log.error( 143 gatt_cb_err['mtu_serv_changed_err'].format(expected_event)) 144 return False 145 return True 146 147 @BluetoothBaseTest.bt_test_wrap 148 @test_tracker_info(uuid='8a3530a3-c8bb-466b-9710-99e694c38618') 149 def test_gatt_connect(self): 150 """Test GATT connection over LE. 151 152 Test establishing a gatt connection between a GATT server and GATT 153 client. 154 155 Steps: 156 1. Start a generic advertisement. 157 2. Start a generic scanner. 158 3. Find the advertisement and extract the mac address. 159 4. Stop the first scanner. 160 5. Create a GATT connection between the scanner and advertiser. 161 6. Disconnect the GATT connection. 162 163 Expected Result: 164 Verify that a connection was established and then disconnected 165 successfully. 166 167 Returns: 168 Pass if True 169 Fail if False 170 171 TAGS: LE, Advertising, Filtering, Scanning, GATT 172 Priority: 0 173 """ 174 gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback() 175 gatt_server = self.per_ad.droid.gattServerOpenGattServer( 176 gatt_server_cb) 177 self.gatt_server_list.append(gatt_server) 178 try: 179 bluetooth_gatt, gatt_callback, adv_callback = ( 180 orchestrate_gatt_connection(self.cen_ad, self.per_ad)) 181 self.bluetooth_gatt_list.append(bluetooth_gatt) 182 except GattTestUtilsError as err: 183 self.log.error(err) 184 return False 185 self.adv_instances.append(adv_callback) 186 return self._orchestrate_gatt_disconnection(bluetooth_gatt, 187 gatt_callback) 188 189 @BluetoothBaseTest.bt_test_wrap 190 @test_tracker_info(uuid='a839b505-03ac-4783-be7e-1d43129a1948') 191 def test_gatt_connect_stop_advertising(self): 192 """Test GATT connection over LE then stop advertising 193 194 A test case that verifies the GATT connection doesn't 195 disconnect when LE advertisement is stopped. 196 197 Steps: 198 1. Start a generic advertisement. 199 2. Start a generic scanner. 200 3. Find the advertisement and extract the mac address. 201 4. Stop the first scanner. 202 5. Create a GATT connection between the scanner and advertiser. 203 6. Stop the advertiser. 204 7. Verify no connection state changed happened. 205 8. Disconnect the GATT connection. 206 207 Expected Result: 208 Verify that a connection was established and not disconnected 209 when advertisement stops. 210 211 Returns: 212 Pass if True 213 Fail if False 214 215 TAGS: LE, Advertising, Filtering, Scanning, GATT 216 Priority: 0 217 """ 218 gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback() 219 gatt_server = self.per_ad.droid.gattServerOpenGattServer( 220 gatt_server_cb) 221 self.gatt_server_list.append(gatt_server) 222 try: 223 bluetooth_gatt, gatt_callback, adv_callback = ( 224 orchestrate_gatt_connection(self.cen_ad, self.per_ad)) 225 self.bluetooth_gatt_list.append(bluetooth_gatt) 226 except GattTestUtilsError as err: 227 self.log.error(err) 228 return False 229 self.per_ad.droid.bleStopBleAdvertising(adv_callback) 230 try: 231 event = self.cen_ad.ed.pop_event( 232 gatt_cb_strings['gatt_conn_change'].format( 233 gatt_callback, self.default_timeout)) 234 self.log.error( 235 "Connection event found when not expected: {}".format(event)) 236 return False 237 except Empty: 238 self.log.info("No connection state change as expected") 239 try: 240 self._orchestrate_gatt_disconnection(bluetooth_gatt, gatt_callback) 241 except Exception as err: 242 self.log.info("Failed to orchestrate disconnect: {}".format(err)) 243 return False 244 return True 245 246 @BluetoothBaseTest.bt_test_wrap 247 @test_tracker_info(uuid='b82f91a8-54bb-4779-a117-73dc7fdb28cc') 248 def test_gatt_connect_autoconnect(self): 249 """Test GATT connection over LE. 250 251 Test re-establishing a gatt connection using autoconnect 252 set to True in order to test connection whitelist. 253 254 Steps: 255 1. Start a generic advertisement. 256 2. Start a generic scanner. 257 3. Find the advertisement and extract the mac address. 258 4. Stop the first scanner. 259 5. Create a GATT connection between the scanner and advertiser. 260 6. Disconnect the GATT connection. 261 7. Create a GATT connection with autoconnect set to True 262 8. Disconnect the GATT connection. 263 264 Expected Result: 265 Verify that a connection was re-established and then disconnected 266 successfully. 267 268 Returns: 269 Pass if True 270 Fail if False 271 272 TAGS: LE, Advertising, Filtering, Scanning, GATT 273 Priority: 0 274 """ 275 gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback() 276 gatt_server = self.per_ad.droid.gattServerOpenGattServer( 277 gatt_server_cb) 278 self.gatt_server_list.append(gatt_server) 279 autoconnect = False 280 mac_address, adv_callback, scan_callback = ( 281 get_mac_address_of_generic_advertisement(self.cen_ad, self.per_ad)) 282 self.adv_instances.append(adv_callback) 283 try: 284 bluetooth_gatt, gatt_callback = setup_gatt_connection( 285 self.cen_ad, mac_address, autoconnect) 286 self.cen_ad.droid.bleStopBleScan(scan_callback) 287 self.bluetooth_gatt_list.append(bluetooth_gatt) 288 except GattTestUtilsError as err: 289 self.log.error(err) 290 return False 291 try: 292 disconnect_gatt_connection(self.cen_ad, bluetooth_gatt, 293 gatt_callback) 294 close_gatt_client(self.cen_ad, bluetooth_gatt) 295 if bluetooth_gatt in self.bluetooth_gatt_list: 296 self.bluetooth_gatt_list.remove(bluetooth_gatt) 297 except GattTestUtilsError as err: 298 self.log.error(err) 299 return False 300 autoconnect = True 301 bluetooth_gatt = self.cen_ad.droid.gattClientConnectGatt( 302 gatt_callback, mac_address, autoconnect, gatt_transport['auto'], 303 False, gatt_phy_mask['1m_mask']) 304 self.bluetooth_gatt_list.append(bluetooth_gatt) 305 expected_event = gatt_cb_strings['gatt_conn_change'].format( 306 gatt_callback) 307 try: 308 event = self.cen_ad.ed.pop_event(expected_event, 309 self.default_timeout) 310 except Empty: 311 self.log.error( 312 gatt_cb_err['gatt_conn_changed_err'].format(expected_event)) 313 test_result = False 314 return self._orchestrate_gatt_disconnection(bluetooth_gatt, 315 gatt_callback) 316 317 @BluetoothBaseTest.bt_test_wrap 318 @test_tracker_info(uuid='e506fa50-7cd9-4bd8-938a-6b85dcfe6bc6') 319 def test_gatt_connect_opportunistic(self): 320 """Test opportunistic GATT connection over LE. 321 322 Test establishing a gatt connection between a GATT server and GATT 323 client in opportunistic mode. 324 325 Steps: 326 1. Start a generic advertisement. 327 2. Start a generic scanner. 328 3. Find the advertisement and extract the mac address. 329 4. Stop the first scanner. 330 5. Create GATT connection 1 between the scanner and advertiser normally 331 6. Create GATT connection 2 between the scanner and advertiser using 332 opportunistic mode 333 7. Disconnect GATT connection 1 334 335 Expected Result: 336 Verify GATT connection 2 automatically disconnects when GATT connection 337 1 disconnect 338 339 Returns: 340 Pass if True 341 Fail if False 342 343 TAGS: LE, Advertising, Filtering, Scanning, GATT 344 Priority: 0 345 """ 346 gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback() 347 gatt_server = self.per_ad.droid.gattServerOpenGattServer( 348 gatt_server_cb) 349 self.gatt_server_list.append(gatt_server) 350 mac_address, adv_callback, scan_callback = ( 351 get_mac_address_of_generic_advertisement(self.cen_ad, self.per_ad)) 352 # Make GATT connection 1 353 try: 354 bluetooth_gatt_1, gatt_callback_1 = setup_gatt_connection( 355 self.cen_ad, 356 mac_address, 357 False, 358 transport=gatt_transport['auto'], 359 opportunistic=False) 360 self.cen_ad.droid.bleStopBleScan(scan_callback) 361 self.adv_instances.append(adv_callback) 362 self.bluetooth_gatt_list.append(bluetooth_gatt_1) 363 except GattTestUtilsError as err: 364 self.log.error(err) 365 return False 366 # Make GATT connection 2 367 try: 368 bluetooth_gatt_2, gatt_callback_2 = setup_gatt_connection( 369 self.cen_ad, 370 mac_address, 371 False, 372 transport=gatt_transport['auto'], 373 opportunistic=True) 374 self.bluetooth_gatt_list.append(bluetooth_gatt_2) 375 except GattTestUtilsError as err: 376 self.log.error(err) 377 return False 378 # Disconnect GATT connection 1 379 try: 380 disconnect_gatt_connection(self.cen_ad, bluetooth_gatt_1, 381 gatt_callback_1) 382 close_gatt_client(self.cen_ad, bluetooth_gatt_1) 383 if bluetooth_gatt_1 in self.bluetooth_gatt_list: 384 self.bluetooth_gatt_list.remove(bluetooth_gatt_1) 385 except GattTestUtilsError as err: 386 self.log.error(err) 387 return False 388 # Confirm that GATT connection 2 also disconnects 389 wait_for_gatt_disconnect_event(self.cen_ad, gatt_callback_2) 390 close_gatt_client(self.cen_ad, bluetooth_gatt_2) 391 if bluetooth_gatt_2 in self.bluetooth_gatt_list: 392 self.bluetooth_gatt_list.remove(bluetooth_gatt_2) 393 return True 394 395 @BluetoothBaseTest.bt_test_wrap 396 @test_tracker_info(uuid='1e01838e-c4de-4720-9adf-9e0419378226') 397 def test_gatt_request_min_mtu(self): 398 """Test GATT connection over LE and exercise MTU sizes. 399 400 Test establishing a gatt connection between a GATT server and GATT 401 client. Request an MTU size that matches the correct minimum size. 402 403 Steps: 404 1. Start a generic advertisement. 405 2. Start a generic scanner. 406 3. Find the advertisement and extract the mac address. 407 4. Stop the first scanner. 408 5. Create a GATT connection between the scanner and advertiser. 409 6. From the scanner (client) request MTU size change to the 410 minimum value. 411 7. Find the MTU changed event on the client. 412 8. Disconnect the GATT connection. 413 414 Expected Result: 415 Verify that a connection was established and the MTU value found 416 matches the expected MTU value. 417 418 Returns: 419 Pass if True 420 Fail if False 421 422 TAGS: LE, Advertising, Filtering, Scanning, GATT, MTU 423 Priority: 0 424 """ 425 gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback() 426 gatt_server = self.per_ad.droid.gattServerOpenGattServer( 427 gatt_server_cb) 428 self.gatt_server_list.append(gatt_server) 429 try: 430 bluetooth_gatt, gatt_callback, adv_callback = ( 431 orchestrate_gatt_connection(self.cen_ad, self.per_ad)) 432 self.bluetooth_gatt_list.append(bluetooth_gatt) 433 except GattTestUtilsError as err: 434 self.log.error(err) 435 return False 436 self.adv_instances.append(adv_callback) 437 expected_mtu = gatt_mtu_size['min'] 438 self.cen_ad.droid.gattClientRequestMtu(bluetooth_gatt, expected_mtu) 439 if not self._verify_mtu_changed_on_client_and_server( 440 expected_mtu, gatt_callback, gatt_server_cb): 441 return False 442 return self._orchestrate_gatt_disconnection(bluetooth_gatt, 443 gatt_callback) 444 445 @BluetoothBaseTest.bt_test_wrap 446 @test_tracker_info(uuid='c1fa3a2d-fb47-47db-bdd1-458928cd6a5f') 447 def test_gatt_request_max_mtu(self): 448 """Test GATT connection over LE and exercise MTU sizes. 449 450 Test establishing a gatt connection between a GATT server and GATT 451 client. Request an MTU size that matches the correct maximum size. 452 453 Steps: 454 1. Start a generic advertisement. 455 2. Start a generic scanner. 456 3. Find the advertisement and extract the mac address. 457 4. Stop the first scanner. 458 5. Create a GATT connection between the scanner and advertiser. 459 6. From the scanner (client) request MTU size change to the 460 maximum value. 461 7. Find the MTU changed event on the client. 462 8. Disconnect the GATT connection. 463 464 Expected Result: 465 Verify that a connection was established and the MTU value found 466 matches the expected MTU value. 467 468 Returns: 469 Pass if True 470 Fail if False 471 472 TAGS: LE, Advertising, Filtering, Scanning, GATT, MTU 473 Priority: 0 474 """ 475 gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback() 476 gatt_server = self.per_ad.droid.gattServerOpenGattServer( 477 gatt_server_cb) 478 self.gatt_server_list.append(gatt_server) 479 try: 480 bluetooth_gatt, gatt_callback, adv_callback = ( 481 orchestrate_gatt_connection(self.cen_ad, self.per_ad)) 482 self.bluetooth_gatt_list.append(bluetooth_gatt) 483 except GattTestUtilsError as err: 484 self.log.error(err) 485 return False 486 self.adv_instances.append(adv_callback) 487 expected_mtu = gatt_mtu_size['max'] 488 self.cen_ad.droid.gattClientRequestMtu(bluetooth_gatt, expected_mtu) 489 if not self._verify_mtu_changed_on_client_and_server( 490 expected_mtu, gatt_callback, gatt_server_cb): 491 return False 492 return self._orchestrate_gatt_disconnection(bluetooth_gatt, 493 gatt_callback) 494 495 @BluetoothBaseTest.bt_test_wrap 496 @test_tracker_info(uuid='4416d483-dec3-46cb-8038-4d82620f873a') 497 def test_gatt_request_out_of_bounds_mtu(self): 498 """Test GATT connection over LE and exercise an out of bound MTU size. 499 500 Test establishing a gatt connection between a GATT server and GATT 501 client. Request an MTU size that is the MIN value minus 1. 502 503 Steps: 504 1. Start a generic advertisement. 505 2. Start a generic scanner. 506 3. Find the advertisement and extract the mac address. 507 4. Stop the first scanner. 508 5. Create a GATT connection between the scanner and advertiser. 509 6. From the scanner (client) request MTU size change to the 510 minimum value minus one. 511 7. Find the MTU changed event on the client. 512 8. Disconnect the GATT connection. 513 514 Expected Result: 515 Verify that an MTU changed event was not discovered and that 516 it didn't cause an exception when requesting an out of bounds 517 MTU. 518 519 Returns: 520 Pass if True 521 Fail if False 522 523 TAGS: LE, Advertising, Filtering, Scanning, GATT, MTU 524 Priority: 0 525 """ 526 gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback() 527 gatt_server = self.per_ad.droid.gattServerOpenGattServer( 528 gatt_server_cb) 529 self.gatt_server_list.append(gatt_server) 530 try: 531 bluetooth_gatt, gatt_callback, adv_callback = ( 532 orchestrate_gatt_connection(self.cen_ad, self.per_ad)) 533 self.bluetooth_gatt_list.append(bluetooth_gatt) 534 except GattTestUtilsError as err: 535 self.log.error(err) 536 return False 537 self.adv_instances.append(adv_callback) 538 unexpected_mtu = gatt_mtu_size['min'] - 1 539 self.cen_ad.droid.gattClientRequestMtu(bluetooth_gatt, unexpected_mtu) 540 if self._verify_mtu_changed_on_client_and_server( 541 unexpected_mtu, gatt_callback, gatt_server_cb): 542 return False 543 return self._orchestrate_gatt_disconnection(bluetooth_gatt, 544 gatt_callback) 545 546 @BluetoothBaseTest.bt_test_wrap 547 @test_tracker_info(uuid='31ffb9ca-cc75-43fb-9802-c19f1c5856b6') 548 def test_gatt_connect_trigger_on_read_rssi(self): 549 """Test GATT connection over LE read RSSI. 550 551 Test establishing a gatt connection between a GATT server and GATT 552 client then read the RSSI. 553 554 Steps: 555 1. Start a generic advertisement. 556 2. Start a generic scanner. 557 3. Find the advertisement and extract the mac address. 558 4. Stop the first scanner. 559 5. Create a GATT connection between the scanner and advertiser. 560 6. From the scanner, request to read the RSSI of the advertiser. 561 7. Disconnect the GATT connection. 562 563 Expected Result: 564 Verify that a connection was established and then disconnected 565 successfully. Verify that the RSSI was ready correctly. 566 567 Returns: 568 Pass if True 569 Fail if False 570 571 TAGS: LE, Advertising, Filtering, Scanning, GATT, RSSI 572 Priority: 1 573 """ 574 gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback() 575 gatt_server = self.per_ad.droid.gattServerOpenGattServer( 576 gatt_server_cb) 577 self.gatt_server_list.append(gatt_server) 578 try: 579 bluetooth_gatt, gatt_callback, adv_callback = ( 580 orchestrate_gatt_connection(self.cen_ad, self.per_ad)) 581 self.bluetooth_gatt_list.append(bluetooth_gatt) 582 except GattTestUtilsError as err: 583 self.log.error(err) 584 return False 585 self.adv_instances.append(adv_callback) 586 expected_event = gatt_cb_strings['rd_remote_rssi'].format( 587 gatt_callback) 588 if self.cen_ad.droid.gattClientReadRSSI(bluetooth_gatt): 589 try: 590 self.cen_ad.ed.pop_event(expected_event, self.default_timeout) 591 except Empty: 592 self.log.error( 593 gatt_cb_err['rd_remote_rssi_err'].format(expected_event)) 594 return self._orchestrate_gatt_disconnection(bluetooth_gatt, 595 gatt_callback) 596 597 @BluetoothBaseTest.bt_test_wrap 598 @test_tracker_info(uuid='dee9ef28-b872-428a-821b-cc62f27ba936') 599 def test_gatt_connect_trigger_on_services_discovered(self): 600 """Test GATT connection and discover services of peripheral. 601 602 Test establishing a gatt connection between a GATT server and GATT 603 client the discover all services from the connected device. 604 605 Steps: 606 1. Start a generic advertisement. 607 2. Start a generic scanner. 608 3. Find the advertisement and extract the mac address. 609 4. Stop the first scanner. 610 5. Create a GATT connection between the scanner and advertiser. 611 6. From the scanner (central device), discover services. 612 7. Disconnect the GATT connection. 613 614 Expected Result: 615 Verify that a connection was established and then disconnected 616 successfully. Verify that the service were discovered. 617 618 Returns: 619 Pass if True 620 Fail if False 621 622 TAGS: LE, Advertising, Filtering, Scanning, GATT, Services 623 Priority: 1 624 """ 625 gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback() 626 gatt_server = self.per_ad.droid.gattServerOpenGattServer( 627 gatt_server_cb) 628 self.gatt_server_list.append(gatt_server) 629 try: 630 bluetooth_gatt, gatt_callback, adv_callback = ( 631 orchestrate_gatt_connection(self.cen_ad, self.per_ad)) 632 self.bluetooth_gatt_list.append(bluetooth_gatt) 633 except GattTestUtilsError as err: 634 self.log.error(err) 635 return False 636 self.adv_instances.append(adv_callback) 637 if self.cen_ad.droid.gattClientDiscoverServices(bluetooth_gatt): 638 expected_event = gatt_cb_strings['gatt_serv_disc'].format( 639 gatt_callback) 640 try: 641 event = self.cen_ad.ed.pop_event(expected_event, 642 self.default_timeout) 643 except Empty: 644 self.log.error( 645 gatt_cb_err['gatt_serv_disc'].format(expected_event)) 646 return False 647 return self._orchestrate_gatt_disconnection(bluetooth_gatt, 648 gatt_callback) 649 650 @BluetoothBaseTest.bt_test_wrap 651 @test_tracker_info(uuid='01883bdd-0cf8-48fb-bf15-467bbd4f065b') 652 def test_gatt_connect_trigger_on_services_discovered_iterate_attributes( 653 self): 654 """Test GATT connection and iterate peripherals attributes. 655 656 Test establishing a gatt connection between a GATT server and GATT 657 client and iterate over all the characteristics and descriptors of the 658 discovered services. 659 660 Steps: 661 1. Start a generic advertisement. 662 2. Start a generic scanner. 663 3. Find the advertisement and extract the mac address. 664 4. Stop the first scanner. 665 5. Create a GATT connection between the scanner and advertiser. 666 6. From the scanner (central device), discover services. 667 7. Iterate over all the characteristics and descriptors of the 668 discovered features. 669 8. Disconnect the GATT connection. 670 671 Expected Result: 672 Verify that a connection was established and then disconnected 673 successfully. Verify that the services, characteristics, and descriptors 674 were discovered. 675 676 Returns: 677 Pass if True 678 Fail if False 679 680 TAGS: LE, Advertising, Filtering, Scanning, GATT, Services 681 Characteristics, Descriptors 682 Priority: 1 683 """ 684 gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback() 685 gatt_server = self.per_ad.droid.gattServerOpenGattServer( 686 gatt_server_cb) 687 self.gatt_server_list.append(gatt_server) 688 try: 689 bluetooth_gatt, gatt_callback, adv_callback = ( 690 orchestrate_gatt_connection(self.cen_ad, self.per_ad)) 691 self.bluetooth_gatt_list.append(bluetooth_gatt) 692 except GattTestUtilsError as err: 693 self.log.error(err) 694 return False 695 self.adv_instances.append(adv_callback) 696 if self.cen_ad.droid.gattClientDiscoverServices(bluetooth_gatt): 697 expected_event = gatt_cb_strings['gatt_serv_disc'].format( 698 gatt_callback) 699 try: 700 event = self.cen_ad.ed.pop_event(expected_event, 701 self.default_timeout) 702 discovered_services_index = event['data']['ServicesIndex'] 703 except Empty: 704 self.log.error( 705 gatt_cb_err['gatt_serv_disc'].format(expected_event)) 706 return False 707 log_gatt_server_uuids(self.cen_ad, discovered_services_index) 708 return self._orchestrate_gatt_disconnection(bluetooth_gatt, 709 gatt_callback) 710 711 @BluetoothBaseTest.bt_test_wrap 712 @test_tracker_info(uuid='d4277bee-da99-4f48-8a4d-f81b5389da18') 713 def test_gatt_connect_with_service_uuid_variations(self): 714 """Test GATT connection with multiple service uuids. 715 716 Test establishing a gatt connection between a GATT server and GATT 717 client with multiple service uuid variations. 718 719 Steps: 720 1. Start a generic advertisement. 721 2. Start a generic scanner. 722 3. Find the advertisement and extract the mac address. 723 4. Stop the first scanner. 724 5. Create a GATT connection between the scanner and advertiser. 725 6. From the scanner (central device), discover services. 726 7. Verify that all the service uuid variations are found. 727 8. Disconnect the GATT connection. 728 729 Expected Result: 730 Verify that a connection was established and then disconnected 731 successfully. Verify that the service uuid variations are found. 732 733 Returns: 734 Pass if True 735 Fail if False 736 737 TAGS: LE, Advertising, Filtering, Scanning, GATT, Services 738 Priority: 2 739 """ 740 try: 741 gatt_server_cb, gatt_server = setup_multiple_services(self.per_ad) 742 self.gatt_server_list.append(gatt_server) 743 except GattTestUtilsError as err: 744 self.log.error(err) 745 return False 746 try: 747 bluetooth_gatt, gatt_callback, adv_callback = ( 748 orchestrate_gatt_connection(self.cen_ad, self.per_ad)) 749 self.bluetooth_gatt_list.append(bluetooth_gatt) 750 except GattTestUtilsError as err: 751 self.log.error(err) 752 return False 753 self.adv_instances.append(adv_callback) 754 if self.cen_ad.droid.gattClientDiscoverServices(bluetooth_gatt): 755 expected_event = gatt_cb_strings['gatt_serv_disc'].format( 756 gatt_callback) 757 try: 758 event = self.cen_ad.ed.pop_event(expected_event, 759 self.default_timeout) 760 except Empty: 761 self.log.error( 762 gatt_cb_err['gatt_serv_disc'].format(expected_event)) 763 return False 764 discovered_services_index = event['data']['ServicesIndex'] 765 log_gatt_server_uuids(self.cen_ad, discovered_services_index) 766 767 return self._orchestrate_gatt_disconnection(bluetooth_gatt, 768 gatt_callback) 769 770 @BluetoothBaseTest.bt_test_wrap 771 @test_tracker_info(uuid='7d3442c5-f71f-44ae-bd35-f2569f01b3b8') 772 def test_gatt_connect_in_quick_succession(self): 773 """Test GATT connections multiple times. 774 775 Test establishing a gatt connection between a GATT server and GATT 776 client with multiple iterations. 777 778 Steps: 779 1. Start a generic advertisement. 780 2. Start a generic scanner. 781 3. Find the advertisement and extract the mac address. 782 4. Stop the first scanner. 783 5. Create a GATT connection between the scanner and advertiser. 784 6. Disconnect the GATT connection. 785 7. Repeat steps 5 and 6 twenty times. 786 787 Expected Result: 788 Verify that a connection was established and then disconnected 789 successfully twenty times. 790 791 Returns: 792 Pass if True 793 Fail if False 794 795 TAGS: LE, Advertising, Filtering, Scanning, GATT, Stress 796 Priority: 1 797 """ 798 gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback() 799 gatt_server = self.per_ad.droid.gattServerOpenGattServer( 800 gatt_server_cb) 801 self.gatt_server_list.append(gatt_server) 802 mac_address, adv_callback, scan_callback = get_mac_address_of_generic_advertisement( 803 self.cen_ad, self.per_ad) 804 autoconnect = False 805 for i in range(1000): 806 self.log.info("Starting connection iteration {}".format(i + 1)) 807 try: 808 bluetooth_gatt, gatt_callback = setup_gatt_connection( 809 self.cen_ad, mac_address, autoconnect) 810 self.cen_ad.droid.bleStopBleScan(scan_callback) 811 except GattTestUtilsError as err: 812 self.log.error(err) 813 return False 814 test_result = self._orchestrate_gatt_disconnection( 815 bluetooth_gatt, gatt_callback) 816 if not test_result: 817 self.log.info("Failed to disconnect from peripheral device.") 818 return False 819 self.adv_instances.append(adv_callback) 820 return True 821 822 @BluetoothBaseTest.bt_test_wrap 823 @test_tracker_info(uuid='148469d9-7ab0-4c08-b2e9-7e49e88da1fc') 824 def test_gatt_connect_mitm_attack(self): 825 """Test GATT connection with permission write encrypted mitm. 826 827 Test establishing a gatt connection between a GATT server and GATT 828 client while the GATT server's characteristic includes the property 829 write value and the permission write encrypted mitm value. This will 830 prompt LE pairing and then the devices will create a bond. 831 832 Steps: 833 1. Create a GATT server and server callback on the peripheral device. 834 2. Create a unique service and characteristic uuid on the peripheral. 835 3. Create a characteristic on the peripheral with these properties: 836 gatt_characteristic['property_write'], 837 gatt_characteristic['permission_write_encrypted_mitm'] 838 4. Create a GATT service on the peripheral. 839 5. Add the characteristic to the GATT service. 840 6. Create a GATT connection between your central and peripheral device. 841 7. From the central device, discover the peripheral's services. 842 8. Iterate the services found until you find the unique characteristic 843 created in step 3. 844 9. Once found, write a random but valid value to the characteristic. 845 10. Start pairing helpers on both devices immediately after attempting 846 to write to the characteristic. 847 11. Within 10 seconds of writing the characteristic, there should be 848 a prompt to bond the device from the peripheral. The helpers will 849 handle the UI interaction automatically. (see 850 BluetoothConnectionFacade.java bluetoothStartPairingHelper). 851 12. Verify that the two devices are bonded. 852 853 Expected Result: 854 Verify that a connection was established and the devices are bonded. 855 856 Returns: 857 Pass if True 858 Fail if False 859 860 TAGS: LE, Advertising, Filtering, Scanning, GATT, Characteristic, MITM 861 Priority: 1 862 """ 863 gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback() 864 gatt_server = self.per_ad.droid.gattServerOpenGattServer( 865 gatt_server_cb) 866 self.gatt_server_list.append(gatt_server) 867 service_uuid = "3846D7A0-69C8-11E4-BA00-0002A5D5C51B" 868 test_uuid = "aa7edd5a-4d1d-4f0e-883a-d145616a1630" 869 bonded = False 870 characteristic = self.per_ad.droid.gattServerCreateBluetoothGattCharacteristic( 871 test_uuid, gatt_characteristic['property_write'], 872 gatt_characteristic['permission_write_encrypted_mitm']) 873 gatt_service = self.per_ad.droid.gattServerCreateService( 874 service_uuid, gatt_service_types['primary']) 875 self.per_ad.droid.gattServerAddCharacteristicToService( 876 gatt_service, characteristic) 877 self.per_ad.droid.gattServerAddService(gatt_server, gatt_service) 878 result = self._find_service_added_event(gatt_server_cb, service_uuid) 879 if not result: 880 return False 881 bluetooth_gatt, gatt_callback, adv_callback = ( 882 orchestrate_gatt_connection(self.cen_ad, self.per_ad)) 883 self.bluetooth_gatt_list.append(bluetooth_gatt) 884 self.adv_instances.append(adv_callback) 885 if self.cen_ad.droid.gattClientDiscoverServices(bluetooth_gatt): 886 expected_event = gatt_cb_strings['gatt_serv_disc'].format( 887 gatt_callback) 888 try: 889 event = self.cen_ad.ed.pop_event(expected_event, 890 self.default_timeout) 891 except Empty: 892 self.log.error( 893 gatt_cb_err['gatt_serv_disc'].format(expected_event)) 894 return False 895 discovered_services_index = event['data']['ServicesIndex'] 896 else: 897 self.log.info("Failed to discover services.") 898 return False 899 test_value = [1, 2, 3, 4, 5, 6, 7] 900 services_count = self.cen_ad.droid.gattClientGetDiscoveredServicesCount( 901 discovered_services_index) 902 for i in range(services_count): 903 characteristic_uuids = ( 904 self.cen_ad.droid.gattClientGetDiscoveredCharacteristicUuids( 905 discovered_services_index, i)) 906 for characteristic_uuid in characteristic_uuids: 907 if characteristic_uuid == test_uuid: 908 self.cen_ad.droid.bluetoothStartPairingHelper() 909 self.per_ad.droid.bluetoothStartPairingHelper() 910 self.cen_ad.droid.gattClientCharacteristicSetValue( 911 bluetooth_gatt, discovered_services_index, i, 912 characteristic_uuid, test_value) 913 self.cen_ad.droid.gattClientWriteCharacteristic( 914 bluetooth_gatt, discovered_services_index, i, 915 characteristic_uuid) 916 start_time = time.time() + self.default_timeout 917 target_name = self.per_ad.droid.bluetoothGetLocalName() 918 while time.time() < start_time and bonded == False: 919 bonded_devices = \ 920 self.cen_ad.droid.bluetoothGetBondedDevices() 921 for device in bonded_devices: 922 if ('name' in device.keys() 923 and device['name'] == target_name): 924 bonded = True 925 break 926 bonded = False 927 target_name = self.cen_ad.droid.bluetoothGetLocalName() 928 while time.time() < start_time and bonded == False: 929 bonded_devices = \ 930 self.per_ad.droid.bluetoothGetBondedDevices() 931 for device in bonded_devices: 932 if ('name' in device.keys() 933 and device['name'] == target_name): 934 bonded = True 935 break 936 937 # Dual mode devices will establish connection over the classic transport, 938 # in order to establish bond over both transports, and do SDP. Starting 939 # disconnection before all this is finished is not safe, might lead to 940 # race conditions, i.e. bond over classic tranport shows up after LE 941 # bond is already removed. 942 time.sleep(4) 943 944 for ad in [self.cen_ad, self.per_ad]: 945 if not clear_bonded_devices(ad): 946 return False 947 948 # Necessary sleep time for entries to update unbonded state 949 time.sleep(2) 950 951 for ad in [self.cen_ad, self.per_ad]: 952 bonded_devices = ad.droid.bluetoothGetBondedDevices() 953 if len(bonded_devices) > 0: 954 self.log.error( 955 "Failed to unbond devices: {}".format(bonded_devices)) 956 return False 957 return self._orchestrate_gatt_disconnection(bluetooth_gatt, 958 gatt_callback) 959 960 @BluetoothBaseTest.bt_test_wrap 961 @test_tracker_info(uuid='cc3fc361-7bf1-4ee2-9e46-4a27c88ce6a8') 962 def test_gatt_connect_get_connected_devices(self): 963 """Test GATT connections show up in getConnectedDevices 964 965 Test establishing a gatt connection between a GATT server and GATT 966 client. Verify that active connections show up using 967 BluetoothManager.getConnectedDevices API. 968 969 Steps: 970 1. Start a generic advertisement. 971 2. Start a generic scanner. 972 3. Find the advertisement and extract the mac address. 973 4. Stop the first scanner. 974 5. Create a GATT connection between the scanner and advertiser. 975 7. Verify the GATT Client has an open connection to the GATT Server. 976 8. Verify the GATT Server has an open connection to the GATT Client. 977 9. Disconnect the GATT connection. 978 979 Expected Result: 980 Verify that a connection was established, connected devices are found 981 on both the central and peripheral devices, and then disconnected 982 successfully. 983 984 Returns: 985 Pass if True 986 Fail if False 987 988 TAGS: LE, Advertising, Scanning, GATT 989 Priority: 2 990 """ 991 gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback() 992 gatt_server = self.per_ad.droid.gattServerOpenGattServer( 993 gatt_server_cb) 994 self.gatt_server_list.append(gatt_server) 995 try: 996 bluetooth_gatt, gatt_callback, adv_callback = ( 997 orchestrate_gatt_connection(self.cen_ad, self.per_ad)) 998 self.bluetooth_gatt_list.append(bluetooth_gatt) 999 except GattTestUtilsError as err: 1000 self.log.error(err) 1001 return False 1002 conn_cen_devices = self.cen_ad.droid.bluetoothGetConnectedLeDevices( 1003 bt_profile_constants['gatt']) 1004 conn_per_devices = self.per_ad.droid.bluetoothGetConnectedLeDevices( 1005 bt_profile_constants['gatt_server']) 1006 target_name = self.per_ad.droid.bluetoothGetLocalName() 1007 error_message = ("Connected device {} not found in list of connected " 1008 "devices {}") 1009 if not any(d['name'] == target_name for d in conn_cen_devices): 1010 self.log.error(error_message.format(target_name, conn_cen_devices)) 1011 return False 1012 # For the GATT server only check the size of the list since 1013 # it may or may not include the device name. 1014 target_name = self.cen_ad.droid.bluetoothGetLocalName() 1015 if not conn_per_devices: 1016 self.log.error(error_message.format(target_name, conn_per_devices)) 1017 return False 1018 self.adv_instances.append(adv_callback) 1019 return self._orchestrate_gatt_disconnection(bluetooth_gatt, 1020 gatt_callback) 1021 1022 @BluetoothBaseTest.bt_test_wrap 1023 @test_tracker_info(uuid='a0a37ca6-9fa8-4d35-9fdb-0e25b4b8a363') 1024 def test_gatt_connect_second_adv_after_canceling_first_adv(self): 1025 """Test GATT connection to peripherals second advertising address. 1026 1027 The the ability of cancelling GATT connections and trying to reconnect 1028 to the same device via a different address. 1029 1030 Steps: 1031 1. A starts advertising 1032 2. B starts scanning and finds A's mac address 1033 3. Stop advertisement from step 1. Start a new advertisement on A and 1034 find the new new mac address, B knows of both old and new address. 1035 4. B1 sends connect request to old address of A 1036 5. B1 cancel connect attempt after 10 seconds 1037 6. B1 sends connect request to new address of A 1038 7. Verify B1 establish connection to A in less than 10 seconds 1039 1040 Expected Result: 1041 Verify that a connection was established only on the second 1042 advertisement's mac address. 1043 1044 Returns: 1045 Pass if True 1046 Fail if False 1047 1048 TAGS: LE, Advertising, Scanning, GATT 1049 Priority: 3 1050 """ 1051 autoconnect = False 1052 transport = gatt_transport['auto'] 1053 opportunistic = False 1054 # Setup a basic Gatt server on the peripheral 1055 gatt_server_cb = self.per_ad.droid.gattServerCreateGattServerCallback() 1056 gatt_server = self.per_ad.droid.gattServerOpenGattServer( 1057 gatt_server_cb) 1058 1059 # Set advertisement settings to include local name in advertisement 1060 # and set the advertising mode to low_latency. 1061 self.per_ad.droid.bleSetAdvertiseSettingsIsConnectable(True) 1062 self.per_ad.droid.bleSetAdvertiseDataIncludeDeviceName(True) 1063 self.per_ad.droid.bleSetAdvertiseSettingsAdvertiseMode( 1064 ble_advertise_settings_modes['low_latency']) 1065 1066 # Setup necessary advertisement objects. 1067 advertise_data = self.per_ad.droid.bleBuildAdvertiseData() 1068 advertise_settings = self.per_ad.droid.bleBuildAdvertiseSettings() 1069 advertise_callback = self.per_ad.droid.bleGenBleAdvertiseCallback() 1070 1071 # Step 1: Start advertisement 1072 self.per_ad.droid.bleStartBleAdvertising( 1073 advertise_callback, advertise_data, advertise_settings) 1074 1075 # Setup scan settings for low_latency scanning and to include the local name 1076 # of the advertisement started in step 1. 1077 filter_list = self.cen_ad.droid.bleGenFilterList() 1078 self.cen_ad.droid.bleSetScanSettingsNumOfMatches( 1079 ble_scan_settings_match_nums['one']) 1080 self.cen_ad.droid.bleSetScanFilterDeviceName( 1081 self.per_ad.droid.bluetoothGetLocalName()) 1082 self.cen_ad.droid.bleBuildScanFilter(filter_list) 1083 self.cen_ad.droid.bleSetScanSettingsScanMode( 1084 ble_scan_settings_modes['low_latency']) 1085 1086 # Setup necessary scan objects. 1087 scan_settings = self.cen_ad.droid.bleBuildScanSetting() 1088 scan_callback = self.cen_ad.droid.bleGenScanCallback() 1089 1090 # Step 2: Start scanning on central Android device and find peripheral 1091 # address. 1092 self.cen_ad.droid.bleStartBleScan(filter_list, scan_settings, 1093 scan_callback) 1094 expected_event_name = scan_result.format(scan_callback) 1095 try: 1096 mac_address_pre_restart = self.cen_ad.ed.pop_event( 1097 expected_event_name, self.default_timeout)['data']['Result'][ 1098 'deviceInfo']['address'] 1099 self.log.info( 1100 "Peripheral advertisement found with mac address: {}".format( 1101 mac_address_pre_restart)) 1102 except Empty: 1103 self.log.info("Peripheral advertisement not found") 1104 test_result = False 1105 1106 # Step 3: Restart peripheral advertising such that a new mac address is 1107 # created. 1108 self.per_ad.droid.bleStopBleAdvertising(advertise_callback) 1109 self.per_ad.droid.bleStartBleAdvertising( 1110 advertise_callback, advertise_data, advertise_settings) 1111 1112 mac_address_post_restart = mac_address_pre_restart 1113 1114 while True: 1115 try: 1116 mac_address_post_restart = self.cen_ad.ed.pop_event( 1117 expected_event_name, self.default_timeout)['data']['Result'][ 1118 'deviceInfo']['address'] 1119 self.log.info( 1120 "Peripheral advertisement found with mac address: {}".format( 1121 mac_address_post_restart)) 1122 except Empty: 1123 self.log.info("Peripheral advertisement not found") 1124 test_result = False 1125 1126 if mac_address_pre_restart != mac_address_post_restart: 1127 break 1128 1129 self.cen_ad.droid.bleStopBleScan(scan_callback) 1130 1131 # Steps 4: Try to connect to the first mac address 1132 gatt_callback = self.cen_ad.droid.gattCreateGattCallback() 1133 self.log.info( 1134 "Gatt Connect to mac address {}.".format(mac_address_pre_restart)) 1135 bluetooth_gatt = self.cen_ad.droid.gattClientConnectGatt( 1136 gatt_callback, mac_address_pre_restart, autoconnect, transport, 1137 opportunistic, gatt_phy_mask['1m_mask']) 1138 self.bluetooth_gatt_list.append(bluetooth_gatt) 1139 expected_event = gatt_cb_strings['gatt_conn_change'].format( 1140 gatt_callback) 1141 try: 1142 event = self.cen_ad.ed.pop_event(expected_event, 1143 self.default_timeout) 1144 self.log.error( 1145 "Connection callback updated unexpectedly: {}".format(event)) 1146 return False 1147 except Empty: 1148 self.log.info("No connection update as expected.") 1149 1150 # Step 5: Cancel connection request. 1151 self.cen_ad.droid.gattClientDisconnect(bluetooth_gatt) 1152 close_gatt_client(self.cen_ad, bluetooth_gatt) 1153 if bluetooth_gatt in self.bluetooth_gatt_list: 1154 self.bluetooth_gatt_list.remove(bluetooth_gatt) 1155 1156 # Step 6: Connect to second mac address. 1157 gatt_callback = self.cen_ad.droid.gattCreateGattCallback() 1158 self.log.info( 1159 "Gatt Connect to mac address {}.".format(mac_address_post_restart)) 1160 bluetooth_gatt = self.cen_ad.droid.gattClientConnectGatt( 1161 gatt_callback, mac_address_post_restart, autoconnect, transport, 1162 opportunistic, gatt_phy_mask['1m_mask']) 1163 self.bluetooth_gatt_list.append(bluetooth_gatt) 1164 expected_event = gatt_cb_strings['gatt_conn_change'].format( 1165 gatt_callback) 1166 1167 # Step 7: Verify connection was setup successfully. 1168 try: 1169 event = self.cen_ad.ed.pop_event(expected_event, 1170 self.default_timeout) 1171 self.log.info( 1172 "Connection callback updated successfully: {}".format(event)) 1173 if event['data']['State'] != gatt_connection_state['connected']: 1174 self.log.error( 1175 "Could not establish a connection to the peripheral.") 1176 return False 1177 except Empty: 1178 self.log.error("No connection update was found.") 1179 return False 1180 1181 self.per_ad.droid.bleStopBleAdvertising(advertise_callback) 1182 1183 return self._orchestrate_gatt_disconnection(bluetooth_gatt, 1184 gatt_callback) 1185