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