• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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