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