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 = {
131            "name": fuchsia_name,
132            "appearance": None,
133            "service_data": None,
134            "tx_power_level": None,
135            "service_uuids": None,
136            "manufacturer_data": None,
137            "uris": None,
138        }
139        scan_response = None
140        connectable = True
141        interval = 1000
142
143        #Start advertising
144        self.fd.ble_lib.bleStartBleAdvertising(adv_data, scan_response,
145                                               interval, connectable)
146
147        # Initialize scan on android device which scan settings + callback
148        filter_list = self.ad.droid.bleGenFilterList()
149        self.ad.droid.bleSetScanFilterDeviceName(fuchsia_name)
150        self.ad.droid.bleSetScanSettingsScanMode(
151            ble_scan_settings_modes['low_latency'])
152        scan_settings = self.ad.droid.bleBuildScanSetting()
153        scan_callback = self.ad.droid.bleGenScanCallback()
154        self.ad.droid.bleBuildScanFilter(filter_list)
155        self.ad.droid.bleStartBleScan(filter_list, scan_settings,
156                                      scan_callback)
157        event_name = scan_result.format(scan_callback)
158        try:
159            event = self.ad.ed.pop_event(event_name, self.default_timeout)
160            self.log.info("Found scan result: {}".format(
161                pprint.pformat(event)))
162        except Exception:
163            self.log.error("Didn't find any scan results.")
164            return False
165        finally:
166            self.fd.ble_lib.bleStopBleAdvertising()
167            self.ad.droid.bleStopBleScan(scan_callback)
168        # TODO(): Validate result
169        return True
170