1 #/usr/bin/env python3.4 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 """ 17 This test script exercises background scan test scenarios. 18 """ 19 20 from queue import Empty 21 22 from acts.test_decorators import test_tracker_info 23 from acts.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest 24 from acts.test_utils.bt.bt_test_utils import bluetooth_off 25 from acts.test_utils.bt.bt_test_utils import bluetooth_on 26 from acts.test_utils.bt.bt_test_utils import cleanup_scanners_and_advertisers 27 from acts.test_utils.bt.bt_test_utils import generate_ble_advertise_objects 28 from acts.test_utils.bt.bt_test_utils import generate_ble_scan_objects 29 from acts.test_utils.bt.bt_constants import bluetooth_le_off 30 from acts.test_utils.bt.bt_constants import bluetooth_le_on 31 from acts.test_utils.bt.bt_constants import bt_adapter_states 32 from acts.test_utils.bt.bt_constants import scan_result 33 34 import time 35 36 37 class BleBackgroundScanTest(BluetoothBaseTest): 38 default_timeout = 10 39 max_scan_instances = 28 40 report_delay = 2000 41 scan_callbacks = [] 42 adv_callbacks = [] 43 active_scan_callback_list = [] 44 active_adv_callback_list = [] 45 46 def __init__(self, controllers): 47 BluetoothBaseTest.__init__(self, controllers) 48 self.scn_ad = self.android_devices[0] 49 self.adv_ad = self.android_devices[1] 50 51 def setup_test(self): 52 if (self.scn_ad.droid.bluetoothGetLeState() == 53 bt_adapter_states['off']): 54 self.scn_ad.droid.bluetoothEnableBLE() 55 self.scn_ad.ed.pop_event(bluetooth_le_on) 56 for a in self.android_devices: 57 a.ed.clear_all_events() 58 return True 59 60 def teardown_test(self): 61 cleanup_scanners_and_advertisers( 62 self.scn_ad, self.active_adv_callback_list, self.adv_ad, 63 self.active_adv_callback_list) 64 self.active_adv_callback_list = [] 65 self.active_scan_callback_list = [] 66 67 def _setup_generic_advertisement(self): 68 adv_callback, adv_data, adv_settings = generate_ble_advertise_objects( 69 self.adv_ad.droid) 70 self.adv_ad.droid.bleStartBleAdvertising(adv_callback, adv_data, 71 adv_settings) 72 self.active_adv_callback_list.append(adv_callback) 73 74 def _verify_no_events_found(self, event_name): 75 try: 76 self.scn_ad.ed.pop_event(event_name, self.default_timeout) 77 self.log.error("Found an event when none was expected.") 78 return False 79 except Empty: 80 self.log.info("No scan result found as expected.") 81 return True 82 83 @BluetoothBaseTest.bt_test_wrap 84 @test_tracker_info(uuid='4d13c3a8-1805-44ef-a92a-e385540767f1') 85 def test_background_scan(self): 86 """Test generic background scan. 87 88 Tests LE background scan. The goal is to find scan results even though 89 Bluetooth is turned off. 90 91 Steps: 92 1. Setup an advertisement on dut1 93 2. Enable LE on the Bluetooth Adapter on dut0 94 3. Toggle BT off on dut1 95 4. Start a LE scan on dut0 96 5. Find the advertisement from dut1 97 98 Expected Result: 99 Find a advertisement from the scan instance. 100 101 Returns: 102 Pass if True 103 Fail if False 104 105 TAGS: LE, Advertising, Scanning, Background Scanning 106 Priority: 0 107 """ 108 import time 109 self._setup_generic_advertisement() 110 self.scn_ad.droid.bluetoothToggleState(False) 111 try: 112 self.scn_ad.ed.pop_event(bluetooth_off, self.default_timeout) 113 except Empty: 114 self.log.error("Bluetooth Off event not found. Expected {}".format( 115 bluetooth_off)) 116 return False 117 self.scn_ad.droid.bluetoothDisableBLE() 118 try: 119 self.scn_ad.ed.pop_event(bluetooth_off, self.default_timeout) 120 except Empty: 121 self.log.error("Bluetooth Off event not found. Expected {}".format( 122 bluetooth_off)) 123 return False 124 self.scn_ad.droid.bluetoothEnableBLE() 125 try: 126 self.scn_ad.ed.pop_event(bluetooth_off, self.default_timeout * 2) 127 except Empty: 128 self.log.error("Bluetooth On event not found. Expected {}".format( 129 bluetooth_on)) 130 return False 131 filter_list, scan_settings, scan_callback = generate_ble_scan_objects( 132 self.scn_ad.droid) 133 self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings, 134 scan_callback) 135 expected_event = scan_result.format(scan_callback) 136 try: 137 self.scn_ad.ed.pop_event(expected_event, self.default_timeout) 138 except Empty: 139 self.log.error("Scan Result event not found. Expected {}".format( 140 expected_event)) 141 return False 142 return True 143 144 @BluetoothBaseTest.bt_test_wrap 145 @test_tracker_info(uuid='9c4577f8-5e06-4034-b977-285956734974') 146 def test_background_scan_ble_disabled(self): 147 """Test background LE scanning with LE disabled. 148 149 Tests LE background scan. The goal is to find scan results even though 150 Bluetooth is turned off. 151 152 Steps: 153 1. Setup an advertisement on dut1 154 2. Enable LE on the Bluetooth Adapter on dut0 155 3. Toggle BT off on dut1 156 4. Start a LE scan on dut0 157 5. Find the advertisement from dut1 158 159 Expected Result: 160 Find a advertisement from the scan instance. 161 162 Returns: 163 Pass if True 164 Fail if False 165 166 TAGS: LE, Advertising, Scanning, Background Scanning 167 Priority: 0 168 """ 169 self._setup_generic_advertisement() 170 self.scn_ad.droid.bluetoothEnableBLE() 171 self.scn_ad.droid.bluetoothToggleState(False) 172 try: 173 self.scn_ad.ed.pop_event(bluetooth_off, self.default_timeout) 174 except Empty: 175 self.log.error("Bluetooth Off event not found. Expected {}".format( 176 bluetooth_off)) 177 return False 178 filter_list, scan_settings, scan_callback = generate_ble_scan_objects( 179 self.scn_ad.droid) 180 try: 181 self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings, 182 scan_callback) 183 expected_event = scan_result.format(scan_callback) 184 try: 185 self.scn_ad.ed.pop_event(expected_event, self.default_timeout) 186 except Empty: 187 self.log.error("Scan Result event not found. Expected {}". 188 format(expected_event)) 189 return False 190 self.log.info("Was able to start background scan even though ble " 191 "was disabled.") 192 return False 193 except Exception: 194 self.log.info( 195 "Was not able to start a background scan as expected.") 196 return True 197 198 @BluetoothBaseTest.bt_test_wrap 199 @test_tracker_info(uuid='0bdd1764-3dc6-4a82-b041-76e48ed0f424') 200 def test_airplane_mode_disables_ble(self): 201 """Try to start LE mode in Airplane Mode. 202 203 This test will enable airplane mode, then attempt to start LE scanning 204 mode. This should result in bluetooth still being turned off, LE 205 not enabled. 206 207 Steps: 208 1. Start LE only mode. 209 2. Bluetooth should be in LE ONLY mode 210 2. Turn on airplane mode. 211 3. Bluetooth should be OFF 212 4. Try to start LE only mode. 213 5. Bluetooth should stay in OFF mode (LE only start should fail) 214 6. Turn off airplane mode. 215 7. Bluetooth should be OFF. 216 217 Expected Result: 218 No unexpected bluetooth state changes. 219 220 Returns: 221 Pass if True 222 Fail if False 223 224 TAGS: LE, Airplane 225 Priority: 1 226 """ 227 ble_state_error_msg = "Bluetooth LE State not OK {}. Expected {} got {}" 228 # Enable BLE always available (effectively enabling BT in location) 229 self.scn_ad.adb.shell("settings put global ble_scan_always_enabled 1") 230 231 self.scn_ad.droid.bluetoothToggleState(False) 232 try: 233 self.scn_ad.ed.pop_event(bluetooth_off, self.default_timeout) 234 except Empty: 235 self.log.error("Bluetooth Off event not found. Expected {}".format( 236 bluetooth_off)) 237 return False 238 239 # Sleep because LE turns off after the bluetooth off event fires 240 time.sleep(self.default_timeout) 241 state = self.scn_ad.droid.bluetoothGetLeState() 242 if state != bt_adapter_states['off']: 243 self.log.error( 244 ble_state_error_msg.format("after BT Disable", 245 bt_adapter_states['off'], state)) 246 return False 247 248 # TODO: BleStateChangedOn got generated as we shut off bluetooth above? 249 self.scn_ad.ed.clear_all_events() 250 result = self.scn_ad.droid.bluetoothEnableBLE() 251 try: 252 self.scn_ad.ed.pop_event(bluetooth_le_on, self.default_timeout) 253 except Empty: 254 self.log.error("Bluetooth LE On event not found. Expected {}". 255 format(bluetooth_le_on)) 256 return False 257 state = self.scn_ad.droid.bluetoothGetLeState() 258 if state != bt_adapter_states['ble_on']: 259 self.log.error( 260 ble_state_error_msg.format("before Airplane Mode OFF", 261 bt_adapter_states['ble_on'], state)) 262 return False 263 264 self.scn_ad.droid.bluetoothListenForBleStateChange() 265 self.scn_ad.droid.connectivityToggleAirplaneMode(True) 266 try: 267 self.scn_ad.ed.pop_event(bluetooth_le_off, self.default_timeout) 268 except Empty: 269 self.log.error("Bluetooth LE Off event not found. Expected {}". 270 format(bluetooth_le_off)) 271 return False 272 state = self.scn_ad.droid.bluetoothGetLeState() 273 if state != bt_adapter_states['off']: 274 self.log.error( 275 ble_state_error_msg.format("after Airplane Mode ON", 276 bt_adapter_states['off'], state)) 277 return False 278 result = self.scn_ad.droid.bluetoothEnableBLE() 279 if result: 280 self.log.error( 281 "Bluetooth Enable command succeded when it should have failed (in airplane mode)" 282 ) 283 return False 284 state = self.scn_ad.droid.bluetoothGetLeState() 285 if state != bt_adapter_states['off']: 286 self.log.error( 287 "Bluetooth LE State not OK after attempted enable. Expected {} got {}". 288 format(bt_adapter_states['off'], state)) 289 return False 290 self.scn_ad.droid.connectivityToggleAirplaneMode(False) 291 # Sleep to let Airplane Mode disable propogate through the system 292 time.sleep(self.default_timeout) 293 state = self.scn_ad.droid.bluetoothGetLeState() 294 if state != bt_adapter_states['off']: 295 self.log.error( 296 ble_state_error_msg.format("after Airplane Mode OFF", 297 bt_adapter_states['off'], state)) 298 return False 299 return True 300