1#!/usr/bin/env python3
2#
3# Copyright (C) 2018 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"""This script shows simple examples of how to get started with bluetooth
17   low energy testing in acts.
18"""
19
20import pprint
21import random
22import time
23
24from acts.controllers import android_device
25from acts.test_utils.fuchsia.bt_test_utils import le_scan_for_device_by_name
26from acts.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest
27from acts.test_utils.bt.bt_constants import ble_advertise_settings_modes
28from acts.test_utils.bt.bt_constants import adv_succ
29from acts.test_utils.bt.bt_constants import ble_scan_settings_modes
30from acts.test_utils.bt.bt_constants import scan_result
31from acts.test_utils.bt.bt_test_utils import cleanup_scanners_and_advertisers
32from acts.test_utils.bt.bt_test_utils import reset_bluetooth
33
34
35class BleFuchsiaAndroidTest(BluetoothBaseTest):
36    default_timeout = 10
37    active_adv_callback_list = []
38    droid = None
39
40    def setup_class(self):
41        super().setup_class()
42
43        # Android device under test
44        self.ad = self.android_devices[0]
45        # Fuchsia device under test
46        self.fd = self.fuchsia_devices[0]
47        self.log.info("There are: {} fuchsia and {} android devices.".format(
48            len(self.fuchsia_devices), len(self.android_devices)))
49
50    def _start_generic_advertisement_include_device_name(self):
51        self.ad.droid.bleSetAdvertiseDataIncludeDeviceName(True)
52        self.ad.droid.bleSetAdvertiseSettingsAdvertiseMode(
53            ble_advertise_settings_modes['low_latency'])
54        advertise_data = self.ad.droid.bleBuildAdvertiseData()
55        advertise_settings = self.ad.droid.bleBuildAdvertiseSettings()
56        advertise_callback = self.ad.droid.bleGenBleAdvertiseCallback()
57        self.ad.droid.bleStartBleAdvertising(advertise_callback,
58                                             advertise_data,
59                                             advertise_settings)
60        self.ad.ed.pop_event(adv_succ.format(advertise_callback),
61                             self.default_timeout)
62        self.active_adv_callback_list.append(advertise_callback)
63        return advertise_callback
64
65    # Basic test for android device as advertiser and fuchsia device as scanner
66    # Returns True if scan result has an entry corresponding to sample_android_name
67    @BluetoothBaseTest.bt_test_wrap
68    def test_fuchsia_scan_android_adv(self):
69        sample_android_name = "Pixel1234"
70        self.ad.droid.bluetoothSetLocalName(sample_android_name)
71        adv_callback = self._start_generic_advertisement_include_device_name()
72        droid_name = self.ad.droid.bluetoothGetLocalName()
73        self.log.info("Android device name: {}".format(droid_name))
74        res = True
75        if not le_scan_for_device_by_name(
76                self.fd, self.log, sample_android_name, self.default_timeout):
77            res = False
78
79        #Print clients to validate results are saved
80        self.fd.print_clients()
81
82        #Stop android advertising
83        self.ad.droid.bleStopBleAdvertising(adv_callback)
84
85        return res
86
87    # Test for fuchsia device attempting to connect to android device (peripheral)
88    # Also tests the list_services and discconect to a peripheral
89    @BluetoothBaseTest.bt_test_wrap
90    def test_fuchsia_connect_android_periph(self):
91        sample_android_name = "Pixel1234"
92        self.ad.droid.bluetoothStartPairingHelper()
93        self.ad.droid.bluetoothSetLocalName(sample_android_name)
94        adv_callback = self._start_generic_advertisement_include_device_name()
95        droid_name = self.ad.droid.bluetoothGetLocalName()
96        self.log.info("Android device name: {}".format(droid_name))
97
98        scan_result = le_scan_for_device_by_name(self.fd, self.log,
99                                                 sample_android_name,
100                                                 self.default_timeout)
101        if not scan_result:
102            return False
103
104        name, did, connectable = scan_result["name"], scan_result[
105            "id"], scan_result["connectable"]
106
107        connect = self.fd.gattc_lib.bleConnectToPeripheral(did)
108        self.log.info("Connecting returned status: {}".format(connect))
109
110        services = self.fd.gattc_lib.listServices(did)
111        self.log.info("Listing services returned: {}".format(services))
112
113        dconnect = self.fd.gattc_lib.bleDisconnectPeripheral(did)
114        self.log.info("Disconnect status: {}".format(dconnect))
115
116        #Print clients to validate results are saved
117        self.fd.print_clients()
118
119        #Stop android advertising + cleanup sl4f
120        self.ad.droid.bleStopBleAdvertising(adv_callback)
121
122        return True
123
124    # Currently, this test doesn't work. The android device does not scan
125    # TODO(): Debug android scan
126    @BluetoothBaseTest.bt_test_wrap
127    def test_fuchsia_adv_android_scan(self):
128        #Initialize advertising on fuchsia device with name and interval
129        fuchsia_name = "testADV123"
130        adv_data = {"name": fuchsia_name}
131        interval = 1000
132
133        #Start advertising
134        self.fd.ble_lib.bleStartBleAdvertising(adv_data, interval)
135
136        # Initialize scan on android device which scan settings + callback
137        filter_list = self.ad.droid.bleGenFilterList()
138        self.ad.droid.bleSetScanFilterDeviceName(fuchsia_name)
139        self.ad.droid.bleSetScanSettingsScanMode(
140            ble_scan_settings_modes['low_latency'])
141        scan_settings = self.ad.droid.bleBuildScanSetting()
142        scan_callback = self.ad.droid.bleGenScanCallback()
143        self.ad.droid.bleBuildScanFilter(filter_list)
144        self.ad.droid.bleStartBleScan(filter_list, scan_settings,
145                                      scan_callback)
146        event_name = scan_result.format(scan_callback)
147        try:
148            event = self.ad.ed.pop_event(event_name, self.default_timeout)
149            self.log.info("Found scan result: {}".format(
150                pprint.pformat(event)))
151        except Exception:
152            self.log.error("Didn't find any scan results.")
153            return False
154        finally:
155            self.fd.ble_lib.bleStopBleAdvertising()
156            self.ad.droid.bleStopBleScan(scan_callback)
157        # TODO(): Validate result
158        return True
159