xref: /aosp_15_r20/platform_testing/tests/automotive/mobly_tests/utilities/bt_utils.py (revision dd0948b35e70be4c0246aabd6c72554a5eb8b22a)
1#  Copyright (C) 2023 The Android Open Source Project
2#
3#  Licensed under the Apache License, Version 2.0 (the "License");
4#  you may not use this file except in compliance with the License.
5#  You may obtain a copy of the License at
6#
7#       http://www.apache.org/licenses/LICENSE-2.0
8#
9#  Unless required by applicable law or agreed to in writing, software
10#  distributed under the License is distributed on an "AS IS" BASIS,
11#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12#  See the License for the specific language governing permissions and
13#  limitations under the License.
14
15import logging
16import pprint
17import time
18
19from utilities import constants
20from mobly import asserts
21from mobly.controllers import android_device
22from utilities.media_utils import MediaUtils
23
24# Number of seconds for the target to stay discoverable on Bluetooth.
25DISCOVERABLE_TIME = 60
26TIME_FOR_PROMPT_TO_LOAD = 2
27ALLOW_TEXT = "Allow"
28
29
30class BTUtils:
31    """A utility that provides access to Bluetooth connectivity controls."""
32
33    def __init__(self, discoverer, target):
34        self.discoverer = discoverer
35        self.target = target
36        self.target_adrr = None
37        self.media_utils = MediaUtils(self.target, self.discoverer)
38
39    # Disable Android Auto pop-up on HU
40    def disable_android_auto_popup_on_hu(self):
41        logging.info('Disable Android Auto pop-up on HU with adb')
42        self.media_utils.execute_shell_on_hu_device(constants.DISABLE_ANDROID_AUTO_POP_UP)
43
44    # Skip Assistant pop-up
45    # TODO @vitalidim remove this function after b/314386661 resolved
46    def handle_assistant_pop_up(self):
47        logging.info('Checking for Assistant pop-up on HU')
48        if self.discoverer.mbs.isAssistantImprovementPopUpPresent():
49            logging.info('Assistant pop-up is present on HU')
50            logging.info('Click on <CONTINUE> button on HU')
51            self.discoverer.mbs.skipImprovementCallingAndTextingPopUp()
52            asserts.assert_false(self.discoverer.mbs.isAssistantImprovementPopUpPresent(),
53                                 'Assistant pop-up should be closed')
54        else:
55            logging.info('Assistant pop-up is not present on HU')
56
57    def get_info_from_devices(self, discovered_devices):
58        discovered_names = [device['Name'] for device in discovered_devices]
59        discovered_addresses = [device['Address'] for device in discovered_devices]
60        return discovered_names, discovered_addresses
61
62    def discover_secondary_from_primary(self):
63        target_name = self.target.mbs.btGetName()
64        self.target.log.info('Become discoverable with name "%s" for %ds.',
65                             target_name, DISCOVERABLE_TIME)
66        self.target.mbs.btBecomeDiscoverable(DISCOVERABLE_TIME)
67        self.discoverer.log.info('Looking for Bluetooth devices.')
68        discovered_devices = self.discoverer.mbs.btDiscoverAndGetResults()
69        self.discoverer.log.debug('Found Bluetooth devices: %s',
70                                  pprint.pformat(discovered_devices, indent=2))
71        discovered_names, _ = self.get_info_from_devices(discovered_devices)
72        logging.info('Verifying the target is discovered by the discoverer.')
73        asserts.assert_true(
74            target_name in discovered_names,
75            'Failed to discover the target device %s over Bluetooth.' %
76            target_name)
77
78    def pair_primary_to_secondary(self):
79        """Enable discovery on the target so the discoverer can find it."""
80        self.check_device_pairing_state()
81        # Turn bluetooth on in both machines
82        logging.info('Enabling Bluetooth logs')
83        self.enable_bt_logs()
84        logging.info('Enabling Bluetooth on both devices')
85        self.discoverer.mbs.btEnable()
86        self.wakeup_target_device_screen()
87        self.target.mbs.btEnable()
88        self.disable_android_auto_popup_on_hu()
89        logging.info('Setting devices to be discoverable')
90        self.target.mbs.btBecomeDiscoverable(DISCOVERABLE_TIME)
91        self.target.mbs.btStartAutoAcceptIncomingPairRequest()
92        target_address = self.target.mbs.btGetAddress()
93        logging.info('Scanning for discoverable devices')
94        # Discovery of target device is tried 5 times.
95        discovered_devices = self.discoverer.mbs.btDiscoverAndGetResults()
96        self.discoverer.mbs.btPairDevice(target_address)
97        logging.info('Allowing time for contacts to sync')
98        time.sleep(constants.SYNC_WAIT_TIME)
99        self.press_allow_on_phone()
100        paired_devices = self.discoverer.mbs.btGetPairedDevices()
101        _, paired_addresses = self.get_info_from_devices(paired_devices)
102        asserts.assert_true(
103            target_address in paired_addresses,
104            'Failed to pair the target device %s over Bluetooth.' %
105            target_address)
106        time.sleep(constants.DEFAULT_WAIT_TIME_FIVE_SECS)
107        self.handle_assistant_pop_up()
108        logging.info("BT pairing completed.")
109
110    def unpair(self):
111        # unpair Discoverer device from Target
112        logging.info("Unpair Discoverer device from Target")
113        discoverer_address = self.discoverer.mbs.btGetAddress()
114        logging.info(f"Discoverer device address: {discoverer_address}")
115        target_paired_devices = self.target.mbs.btGetPairedDevices()
116        _, target_paired_addresses = self.get_info_from_devices(target_paired_devices)
117        logging.info(f"Paired devices to Target: {target_paired_devices}")
118        if discoverer_address in target_paired_addresses:
119            logging.info(f"Forget Discoverer device <{discoverer_address}> on Target device")
120            self.target.mbs.btUnpairDevice(discoverer_address)
121        else:
122            logging.error("Discoverer device not founded on Target device")
123        # unpair Target device from Discoverer
124        logging.info("Unpair Target device from Discoverer")
125        target_address = self.target.mbs.btGetAddress()
126        logging.info(f"Target device address: {target_address}")
127        discoverer_paired_devices = self.discoverer.mbs.btGetPairedDevices()
128        _, discoverer_paired_addresses = self.get_info_from_devices(
129            discoverer_paired_devices)
130        logging.info(f"Paired devices to Discoverer: {discoverer_paired_devices}")
131        if target_address in discoverer_paired_addresses:
132            logging.info(f"Forget Target device <{target_address}> on Discoverer device")
133            self.discoverer.mbs.btUnpairDevice(target_address)
134        else:
135            logging.error("Target device not founded on Discoverer device")
136
137    def press_allow_on_phone(self):
138        """ Repeatedly presses "Allow" on prompts until no more prompts appear"""
139        logging.info('Attempting to press ALLOW')
140        while (self.target.mbs.hasUIElementWithText(ALLOW_TEXT)):
141            self.target.mbs.clickUIElementWithText(ALLOW_TEXT)
142            logging.info('ALLOW pressed!')
143            time.sleep(TIME_FOR_PROMPT_TO_LOAD)
144
145    def bt_disable(self):
146        """Disable Bluetooth on a device."""
147        self.discoverer.mbs.btUnpairDevice(self.target_adrr)
148        self.discoverer.mbs.btDisable()
149        self.target.mbs.btDisable()
150
151    def click_on_use_bluetooth_toggle(self):
152        logging.info('Click on Use Bluetooth toggle on HU')
153        self.discoverer.mbs.clickOnBluetoothToggle()
154
155    def enable_bt_logs(self):
156        logging.info('Enable bluetooth logs')
157        self.media_utils.execute_shell_on_hu_device(constants.BLUETOOTH_TAG)
158        self.media_utils.execute_shell_on_hu_device(constants.BLUETOOTH_NOOPERABLE)
159        self.media_utils.execute_shell_on_hu_device(constants.BLUETOOTH_BTSNOOP_DEFAULT_MODE)
160
161    def check_device_pairing_state(self):
162        logging.info('Checking the bt pairing status')
163        if  self.discoverer.mbs.btGetPairedDevices() :
164            logging.info('Device is still paired, unpair the device')
165            self.unpair()
166
167    def is_target_device_screen_on(self):
168        logging.info('Checking the target screen state')
169        return 'Awake' in self.media_utils.execute_shell_on_device(constants.DUMPSYS_POWER).decode('utf8')
170
171    def wakeup_target_device_screen(self):
172        if not self.is_target_device_screen_on():
173          logging.info('Target screen is off, waking it up')
174          self.media_utils.execute_shell_on_device(constants.KEYCODE_WAKEUP)
175