1#!/usr/bin/env python3
2#
3# Copyright (C) 2017 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 scan filters with different screen states.
18"""
19
20import concurrent
21import json
22import pprint
23import time
24
25from queue import Empty
26from acts import utils
27from acts.test_decorators import test_tracker_info
28from acts_contrib.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest
29from acts_contrib.test_utils.bt.bt_constants import adv_succ
30from acts_contrib.test_utils.bt.bt_constants import ble_advertise_settings_modes
31from acts_contrib.test_utils.bt.bt_constants import ble_scan_settings_modes
32from acts_contrib.test_utils.bt.bt_constants import bt_default_timeout
33from acts_contrib.test_utils.bt.bt_constants import scan_result
34from acts_contrib.test_utils.bt.bt_test_utils import generate_ble_advertise_objects
35from acts_contrib.test_utils.bt.bt_test_utils import generate_ble_scan_objects
36from acts_contrib.test_utils.bt.bt_test_utils import reset_bluetooth
37
38
39class BleScanScreenStateTest(BluetoothBaseTest):
40    advertise_callback = -1
41    max_concurrent_scans = 27
42    scan_callback = -1
43    shorter_scan_timeout = 4
44
45    def setup_class(self):
46        super(BluetoothBaseTest, self).setup_class()
47        self.scn_ad = self.android_devices[0]
48        self.adv_ad = self.android_devices[1]
49
50        utils.set_location_service(self.scn_ad, True)
51        utils.set_location_service(self.adv_ad, True)
52        return True
53
54    def _setup_generic_advertisement(self):
55        self.adv_ad.droid.bleSetAdvertiseSettingsAdvertiseMode(
56            ble_advertise_settings_modes['low_latency'])
57        self.advertise_callback, advertise_data, advertise_settings = (
58            generate_ble_advertise_objects(self.adv_ad.droid))
59        self.adv_ad.droid.bleStartBleAdvertising(
60            self.advertise_callback, advertise_data, advertise_settings)
61        try:
62            self.adv_ad.ed.pop_event(adv_succ.format(self.advertise_callback))
63        except Empty:
64            self.log.error("Failed to start advertisement.")
65            return False
66        return True
67
68    def _setup_scan_with_no_filters(self):
69        filter_list, scan_settings, self.scan_callback = \
70            generate_ble_scan_objects(self.scn_ad.droid)
71        self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings,
72                                          self.scan_callback)
73
74    def _scan_found_results(self):
75        try:
76            self.scn_ad.ed.pop_event(
77                scan_result.format(self.scan_callback), bt_default_timeout)
78            self.log.info("Found an advertisement.")
79        except Empty:
80            self.log.info("Did not find an advertisement.")
81            return False
82        return True
83
84    @BluetoothBaseTest.bt_test_wrap
85    @test_tracker_info(uuid='9b695819-e5a8-48b3-87a0-f90422998bf9')
86    def test_scan_no_filters_screen_on(self):
87        """Test LE scanning is successful with no filters and screen on.
88
89        Test LE scanning is successful with no filters and screen on. Scan
90        results should be found.
91
92        Steps:
93        1. Setup advertisement
94        2. Turn on screen
95        3. Start scanner without filters
96        4. Verify scan results are found
97        5. Teardown advertisement and scanner
98
99        Expected Result:
100        Scan results should be found.
101
102        Returns:
103          Pass if True
104          Fail if False
105
106        TAGS: LE, Advertising, Filtering, Scanning, Screen
107        Priority: 2
108        """
109        # Step 1
110        if not self._setup_generic_advertisement():
111            return False
112
113        # Step 2
114        self.scn_ad.droid.wakeUpNow()
115
116        # Step 3
117        self._setup_scan_with_no_filters()
118
119        # Step 4
120        if not self._scan_found_results():
121            return False
122
123        # Step 5
124        self.adv_ad.droid.bleStopBleAdvertising(self.advertise_callback)
125        self.scn_ad.droid.bleStopBleScan(self.scan_callback)
126        return True
127
128    @BluetoothBaseTest.bt_test_wrap
129    @test_tracker_info(uuid='38fb6959-f07b-4501-814b-81a498e3efc4')
130    def test_scan_no_filters_screen_off(self):
131        """Test LE scanning is successful with no filters and screen off.
132
133        Test LE scanning is successful with no filters and screen off. No scan
134        results should be found.
135
136        Steps:
137        1. Setup advertisement
138        2. Turn off screen
139        3. Start scanner without filters
140        4. Verify no scan results are found
141        5. Teardown advertisement and scanner
142
143        Expected Result:
144        No scan results should be found.
145
146        Returns:
147          Pass if True
148          Fail if False
149
150        TAGS: LE, Advertising, Filtering, Scanning, Screen
151        Priority: 1
152        """
153        # Step 1
154        if not self._setup_generic_advertisement():
155            return False
156
157        # Step 2
158        self.scn_ad.droid.goToSleepNow()
159        # Give the device time to go to sleep
160        time.sleep(2)
161
162        # Step 3
163        self._setup_scan_with_no_filters()
164
165        # Step 4
166        if self._scan_found_results():
167            return False
168
169        # Step 5
170        self.adv_ad.droid.bleStopBleAdvertising(self.advertise_callback)
171        self.scn_ad.droid.bleStopBleScan(self.scan_callback)
172        return True
173
174    @BluetoothBaseTest.bt_test_wrap
175    @test_tracker_info(uuid='7186ef2f-096a-462e-afde-b0e3d4ecdd83')
176    def test_scan_filters_works_with_screen_off(self):
177        """Test LE scanning is successful with filters and screen off.
178
179        Test LE scanning is successful with no filters and screen off. No scan
180        results should be found.
181
182        Steps:
183        1. Setup advertisement
184        2. Turn off screen
185        3. Start scanner with filters
186        4. Verify scan results are found
187        5. Teardown advertisement and scanner
188
189        Expected Result:
190        Scan results should be found.
191
192        Returns:
193          Pass if True
194          Fail if False
195
196        TAGS: LE, Advertising, Filtering, Scanning, Screen
197        Priority: 1
198        """
199        # Step 1
200        adv_device_name = self.adv_ad.droid.bluetoothGetLocalName()
201        print(adv_device_name)
202        self.adv_ad.droid.bleSetAdvertiseDataIncludeDeviceName(True)
203        if not self._setup_generic_advertisement():
204            return False
205
206        # Step 2
207        self.scn_ad.droid.goToSleepNow()
208
209        # Step 3
210        self.scn_ad.droid.bleSetScanFilterDeviceName(adv_device_name)
211        filter_list, scan_settings, self.scan_callback = generate_ble_scan_objects(
212            self.scn_ad.droid)
213        self.scn_ad.droid.bleBuildScanFilter(filter_list)
214        self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings,
215                                          self.scan_callback)
216
217        # Step 4
218        if not self._scan_found_results():
219            return False
220
221        # Step 5
222        self.adv_ad.droid.bleStopBleAdvertising(self.advertise_callback)
223        self.scn_ad.droid.bleStopBleScan(self.scan_callback)
224        return True
225
226    @BluetoothBaseTest.bt_test_wrap
227    @test_tracker_info(uuid='02cd6dca-149e-439b-8427-a2edc7864265')
228    def test_scan_no_filters_screen_off_then_turn_on(self):
229        """Test start LE scan with no filters while screen is off then turn on.
230
231        Test that a scan without filters will not return results while the
232        screen is off but will return results when the screen turns on.
233
234        Steps:
235        1. Setup advertisement
236        2. Turn off screen
237        3. Start scanner without filters
238        4. Verify no scan results are found
239        5. Turn screen on
240        6. Verify scan results are found
241        7. Teardown advertisement and scanner
242
243        Expected Result:
244        Scan results should only come in when the screen is on.
245
246        Returns:
247          Pass if True
248          Fail if False
249
250        TAGS: LE, Advertising, Filtering, Scanning, Screen
251        Priority: 2
252        """
253        # Step 1
254        if not self._setup_generic_advertisement():
255            return False
256
257        # Step 2
258        self.scn_ad.droid.goToSleepNow()
259        # Give the device time to go to sleep
260        time.sleep(2)
261
262        # Step 3
263        self._setup_scan_with_no_filters()
264
265        # Step 4
266        if self._scan_found_results():
267            return False
268
269        # Step 5
270        self.scn_ad.droid.wakeUpNow()
271
272        # Step 6
273        if not self._scan_found_results():
274            return False
275
276        # Step 7
277        self.adv_ad.droid.bleStopBleAdvertising(self.advertise_callback)
278        self.scn_ad.droid.bleStopBleScan(self.scan_callback)
279        return True
280
281    @BluetoothBaseTest.bt_test_wrap
282    @test_tracker_info(uuid='eb9fc373-f5e8-4a55-9750-02b7a11893d1')
283    def test_scan_no_filters_screen_on_then_turn_off(self):
284        """Test start LE scan with no filters while screen is on then turn off.
285
286        Test that a scan without filters will not return results while the
287        screen is off but will return results when the screen turns on.
288
289        Steps:
290        1. Setup advertisement
291        2. Turn off screen
292        3. Start scanner without filters
293        4. Verify no scan results are found
294        5. Turn screen on
295        6. Verify scan results are found
296        7. Teardown advertisement and scanner
297
298        Expected Result:
299        Scan results should only come in when the screen is on.
300
301        Returns:
302          Pass if True
303          Fail if False
304
305        TAGS: LE, Advertising, Filtering, Scanning, Screen
306        Priority: 2
307        """
308        # Step 1
309        if not self._setup_generic_advertisement():
310            return False
311
312        # Step 2
313        self.scn_ad.droid.wakeUpNow()
314
315        # Step 3
316        self._setup_scan_with_no_filters()
317
318        # Step 4
319        if not self._scan_found_results():
320            return False
321
322        # Step 5
323        self.scn_ad.droid.goToSleepNow()
324        # Give the device time to go to sleep
325        time.sleep(2)
326        self.scn_ad.ed.clear_all_events()
327
328        # Step 6
329        if self._scan_found_results():
330            return False
331
332        # Step 7
333        self.adv_ad.droid.bleStopBleAdvertising(self.advertise_callback)
334        self.scn_ad.droid.bleStopBleScan(self.scan_callback)
335        return True
336
337    @BluetoothBaseTest.bt_test_wrap
338    @test_tracker_info(uuid='41d90e11-b0a8-4eed-bff1-c19678920762')
339    def test_scan_no_filters_screen_toggling(self):
340        """Test start LE scan with no filters and test screen toggling.
341
342        Test that a scan without filters will not return results while the
343        screen is off and return results while the screen is on.
344
345        Steps:
346        1. Setup advertisement
347        2. Turn off screen
348        3. Start scanner without filters
349        4. Verify no scan results are found
350        5. Turn screen on
351        6. Verify scan results are found
352        7. Repeat steps 1-6 10 times
353        7. Teardown advertisement and scanner
354
355        Expected Result:
356        Scan results should only come in when the screen is on.
357
358        Returns:
359          Pass if True
360          Fail if False
361
362        TAGS: LE, Advertising, Filtering, Scanning, Screen
363        Priority: 3
364        """
365        iterations = 10
366        # Step 1
367        if not self._setup_generic_advertisement():
368            return False
369
370        for i in range(iterations):
371            self.log.info("Starting iteration {}".format(i + 1))
372            # Step 2
373            self.scn_ad.droid.goToSleepNow()
374            # Give the device time to go to sleep
375            time.sleep(2)
376            self.scn_ad.ed.clear_all_events()
377
378            # Step 3
379            self._setup_scan_with_no_filters()
380
381            # Step 4
382            if self._scan_found_results():
383                return False
384
385            # Step 5
386            self.scn_ad.droid.wakeUpNow()
387
388            # Step 6
389            if not self._scan_found_results():
390                return False
391
392        # Step 7
393        self.adv_ad.droid.bleStopBleAdvertising(self.advertise_callback)
394        self.scn_ad.droid.bleStopBleScan(self.scan_callback)
395        return True
396
397    @BluetoothBaseTest.bt_test_wrap
398    @test_tracker_info(uuid='7a2fe7ef-b15f-4e93-a2f0-40e2f7d9cbcb')
399    def test_opportunistic_scan_no_filters_screen_off_then_on(self):
400        """Test opportunistic scanning does not find results with screen off.
401
402        Test LE scanning is successful with no filters and screen off. No scan
403        results should be found.
404
405        Steps:
406        1. Setup advertisement
407        2. Turn off screen
408        3. Start opportunistic scan without filters
409        4. Start scan without filters
410        5. Verify no scan results are found on either scan instance
411        6. Wake up phone
412        7. Verify scan results on each scan instance
413        8. Teardown advertisement and scanner
414
415        Expected Result:
416        No scan results should be found.
417
418        Returns:
419          Pass if True
420          Fail if False
421
422        TAGS: LE, Advertising, Filtering, Scanning, Screen
423        Priority: 1
424        """
425        # Step 1
426        if not self._setup_generic_advertisement():
427            return False
428
429        # Step 2
430        self.scn_ad.droid.goToSleepNow()
431        # Give the device time to go to sleep
432        time.sleep(2)
433
434        # Step 3
435        self.scn_ad.droid.bleSetScanSettingsScanMode(ble_scan_settings_modes[
436            'opportunistic'])
437        filter_list, scan_settings, scan_callback = generate_ble_scan_objects(
438            self.scn_ad.droid)
439        self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings,
440                                          scan_callback)
441
442        # Step 4
443        filter_list2, scan_settings2, scan_callback2 = generate_ble_scan_objects(
444            self.scn_ad.droid)
445        self.scn_ad.droid.bleStartBleScan(filter_list2, scan_settings2,
446                                          scan_callback2)
447
448        # Step 5
449        try:
450            self.scn_ad.ed.pop_event(
451                scan_result.format(scan_callback), self.shorter_scan_timeout)
452            self.log.error("Found an advertisement on opportunistic scan.")
453            return False
454        except Empty:
455            self.log.info("Did not find an advertisement.")
456        try:
457            self.scn_ad.ed.pop_event(
458                scan_result.format(scan_callback2), self.shorter_scan_timeout)
459            self.log.error("Found an advertisement on scan instance.")
460            return False
461        except Empty:
462            self.log.info("Did not find an advertisement.")
463
464        # Step 6
465        self.scn_ad.droid.wakeUpNow()
466
467        # Step 7
468        try:
469            self.scn_ad.ed.pop_event(
470                scan_result.format(scan_callback), self.shorter_scan_timeout)
471            self.log.info("Found an advertisement on opportunistic scan.")
472        except Empty:
473            self.log.error(
474                "Did not find an advertisement on opportunistic scan.")
475            return False
476        try:
477            self.scn_ad.ed.pop_event(
478                scan_result.format(scan_callback2), self.shorter_scan_timeout)
479            self.log.info("Found an advertisement on scan instance.")
480        except Empty:
481            self.log.info("Did not find an advertisement.")
482            return False
483
484        # Step 8
485        self.adv_ad.droid.bleStopBleAdvertising(self.advertise_callback)
486        self.scn_ad.droid.bleStopBleScan(scan_callback)
487        self.scn_ad.droid.bleStopBleScan(scan_callback2)
488        return True
489
490    @BluetoothBaseTest.bt_test_wrap
491    @test_tracker_info(uuid='406f1a2e-160f-4fb2-8a87-6403996df36e')
492    def test_max_scan_no_filters_screen_off_then_turn_on(self):
493        """Test start max scans with no filters while screen is off then turn on
494
495        Test that max LE scan without filters will not return results while the
496        screen is off but will return results when the screen turns on.
497
498        Steps:
499        1. Setup advertisement
500        2. Turn off screen
501        3. Start scanner without filters and verify no scan results
502        4. Turn screen on
503        5. Verify scan results are found on each scan callback
504        6. Teardown advertisement and all scanner
505
506        Expected Result:
507        Scan results should only come in when the screen is on.
508
509        Returns:
510          Pass if True
511          Fail if False
512
513        TAGS: LE, Advertising, Filtering, Scanning, Screen
514        Priority: 2
515        """
516        # Step 1
517        if not self._setup_generic_advertisement():
518            return False
519
520        # Step 2
521        self.scn_ad.droid.goToSleepNow()
522        # Give the device time to go to sleep
523        time.sleep(2)
524
525        # Step 3
526        scan_callback_list = []
527        for _ in range(self.max_concurrent_scans):
528            filter_list, scan_settings, scan_callback = \
529                generate_ble_scan_objects(self.scn_ad.droid)
530            self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings,
531                                              scan_callback)
532            scan_callback_list.append(scan_callback)
533            try:
534                self.scn_ad.ed.pop_event(
535                    scan_result.format(self.scan_callback),
536                    self.shorter_scan_timeout)
537                self.log.info("Found an advertisement.")
538                return False
539            except Empty:
540                self.log.info("Did not find an advertisement.")
541
542        # Step 4
543        self.scn_ad.droid.wakeUpNow()
544
545        # Step 5
546        for callback in scan_callback_list:
547            try:
548                self.scn_ad.ed.pop_event(
549                    scan_result.format(callback), self.shorter_scan_timeout)
550                self.log.info("Found an advertisement.")
551            except Empty:
552                self.log.info("Did not find an advertisement.")
553                return False
554
555        # Step 7
556        self.adv_ad.droid.bleStopBleAdvertising(self.advertise_callback)
557        for callback in scan_callback_list:
558            self.scn_ad.droid.bleStopBleScan(callback)
559        return True
560