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 # Turn bluetooth on in both machines 81 logging.info('Enabling Bluetooth logs') 82 self.enable_bt_logs() 83 logging.info('Enabling Bluetooth on both devices') 84 self.discoverer.mbs.btEnable() 85 self.target.mbs.btEnable() 86 self.disable_android_auto_popup_on_hu() 87 logging.info('Setting devices to be discoverable') 88 self.target.mbs.btBecomeDiscoverable(DISCOVERABLE_TIME) 89 self.target.mbs.btStartAutoAcceptIncomingPairRequest() 90 target_address = self.target.mbs.btGetAddress() 91 logging.info('Scanning for discoverable devices') 92 # Discovery of target device is tried 5 times. 93 discovered_devices = self.discoverer.mbs.btDiscoverAndGetResults() 94 self.discoverer.mbs.btPairDevice(target_address) 95 logging.info('Allowing time for contacts to sync') 96 time.sleep(constants.SYNC_WAIT_TIME) 97 self.press_allow_on_phone() 98 paired_devices = self.discoverer.mbs.btGetPairedDevices() 99 _, paired_addresses = self.get_info_from_devices(paired_devices) 100 asserts.assert_true( 101 target_address in paired_addresses, 102 'Failed to pair the target device %s over Bluetooth.' % 103 target_address) 104 time.sleep(constants.DEFAULT_WAIT_TIME_FIVE_SECS) 105 self.handle_assistant_pop_up() 106 107 def unpair(self): 108 # unpair Discoverer device from Target 109 logging.info("Unpair Discoverer device from Target") 110 discoverer_address = self.discoverer.mbs.btGetAddress() 111 logging.info(f"Discoverer device address: {discoverer_address}") 112 target_paired_devices = self.target.mbs.btGetPairedDevices() 113 _, target_paired_addresses = self.get_info_from_devices(target_paired_devices) 114 logging.info(f"Paired devices to Target: {target_paired_devices}") 115 if discoverer_address in target_paired_addresses: 116 logging.info(f"Forget Discoverer device <{discoverer_address}> on Target device") 117 self.target.mbs.btUnpairDevice(discoverer_address) 118 else: 119 logging.error("Discoverer device not founded on Target device") 120 # unpair Target device from Discoverer 121 logging.info("Unpair Target device from Discoverer") 122 target_address = self.target.mbs.btGetAddress() 123 logging.info(f"Target device address: {target_address}") 124 discoverer_paired_devices = self.discoverer.mbs.btGetPairedDevices() 125 _, discoverer_paired_addresses = self.get_info_from_devices( 126 discoverer_paired_devices) 127 logging.info(f"Paired devices to Discoverer: {discoverer_paired_devices}") 128 if target_address in discoverer_paired_addresses: 129 logging.info(f"Forget Target device <{target_address}> on Discoverer device") 130 self.discoverer.mbs.btUnpairDevice(target_address) 131 else: 132 logging.error("Target device not founded on Discoverer device") 133 134 def press_allow_on_phone(self): 135 """ Repeatedly presses "Allow" on prompts until no more prompts appear""" 136 logging.info('Attempting to press ALLOW') 137 while (self.target.mbs.hasUIElementWithText(ALLOW_TEXT)): 138 self.target.mbs.clickUIElementWithText(ALLOW_TEXT) 139 logging.info('ALLOW pressed!') 140 time.sleep(TIME_FOR_PROMPT_TO_LOAD) 141 142 def bt_disable(self): 143 """Disable Bluetooth on a device.""" 144 self.discoverer.mbs.btUnpairDevice(self.target_adrr) 145 self.discoverer.mbs.btDisable() 146 self.target.mbs.btDisable() 147 148 def click_on_use_bluetooth_toggle(self): 149 logging.info('Click on Use Bluetooth toggle on HU') 150 self.discoverer.mbs.clickOnBluetoothToggle() 151 152 def enable_bt_logs(self): 153 logging.info('Enable bluetooth logs') 154 self.media_utils.execute_shell_on_hu_device(constants.BLUETOOTH_TAG) 155 self.media_utils.execute_shell_on_hu_device(constants.BLUETOOTH_NOOPERABLE) 156 self.media_utils.execute_shell_on_hu_device(constants.BLUETOOTH_BTSNOOP_DEFAULT_MODE)