1# Copyright (C) 2024 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"""Test utils for UWB.""" 15 16import time 17from lib.ranging_decorator import RangingTechnology 18from mobly import asserts 19from mobly.controllers import android_device 20 21WAIT_TIME_SEC = 3 22 23 24def initialize_uwb_country_code(ad: android_device.AndroidDevice): 25 """Sets UWB country code to US if the device does not have it set. 26 27 Note: This intentionally relies on an unstable API (shell command) since we 28 don't want to expose an API that allows users to circumvent the UWB 29 regulatory requirements. 30 31 Args: 32 ad: android device object. 33 handler: callback handler. 34 """ 35 if not ad.ranging.isTechnologySupported(RangingTechnology.UWB) and \ 36 ad.ranging.isTechnologyEnabled(RangingTechnology.UWB): 37 return 38 39 try: 40 ad.adb.shell(["cmd", "uwb", "force-country-code", "enabled", "US"]) 41 except Exception as e: 42 ad.log.warning("Unable to force uwb country code") 43 44 #For Wear OS, this call will not enable uwb. So ignore verification whether the stack was enabled. 45 time.sleep(1) 46 47 48def request_hw_idle_vote(ad: android_device.AndroidDevice, enabled : bool): 49 if ad.uwb.isUwbHwIdleTurnOffEnabled(): 50 ad.uwb.requestUwbHwEnabled(enabled) 51 52def _is_technology_state( 53 ad: android_device.AndroidDevice, 54 technology: RangingTechnology, 55 state: bool, 56 timeout_s=WAIT_TIME_SEC, 57) -> bool: 58 """Checks if the provided technology becomes enabled/disabled 59 60 Args: 61 62 ad: android device object. 63 technology: to check for enablement. 64 state: bool, True for on, False for off. 65 timeout_s: how long to wait for enablement before failing, in seconds. 66 """ 67 start_time = time.time() 68 while state != ad.ranging.isTechnologyEnabled(technology): 69 if time.time() - start_time > timeout_s: 70 return False 71 return True 72 73 74def is_technology_enabled( 75 ad: android_device.AndroidDevice, 76 technology: RangingTechnology, 77 timeout_s=WAIT_TIME_SEC, 78) -> bool: 79 """Checks if the provided technology becomes enabled 80 81 Args: 82 83 ad: android device object. 84 technology: to check for enablement. 85 timeout_s: how long to wait for enablement before failing, in seconds. 86 """ 87 return _is_technology_state(ad, technology, True, timeout_s) 88 89 90def set_airplane_mode(ad: android_device.AndroidDevice, state: bool): 91 """Sets the airplane mode to the given state. 92 93 Args: 94 ad: android device object. 95 state: True for Airplane mode enabled, False for disabled. 96 """ 97 ad.ranging.setAirplaneMode(state) 98 start_time = time.time() 99 while get_airplane_mode(ad) != state: 100 time.sleep(0.5) 101 if time.time() - start_time > WAIT_TIME_SEC: 102 asserts.fail(f"Failed to set airplane mode to: {state}") 103 104 105def get_airplane_mode(ad: android_device.AndroidDevice) -> bool: 106 """Gets the current airplane mode setting. 107 108 Args: 109 ad: android device object. 110 111 Returns: 112 True if airplane mode On, False for Off. 113 """ 114 state = ad.adb.shell(["settings", "get", "global", "airplane_mode_on"]) 115 return bool(int(state.decode().strip())) 116 117def set_uwb_state_and_verify( 118 ad: android_device.AndroidDevice, 119 state: bool 120): 121 """Sets UWB state to on or off and verifies it. 122 123 Args: 124 ad: android device object. 125 state: bool, True for UWB on, False for off. 126 """ 127 failure_msg = "enabled" if state else "disabled" 128 ad.uwb.setUwbEnabled(state) 129 asserts.assert_true(_is_technology_state(ad, RangingTechnology.UWB, state, timeout_s=10), 130 "Uwb is not %s" % failure_msg) 131 132def set_bt_state_and_verify( 133 ad: android_device.AndroidDevice, 134 state: bool 135): 136 """Sets BT state to on or off and verifies it. 137 138 Args: 139 ad: android device object. 140 state: bool, True for BT on, False for off. 141 """ 142 failure_msg = "enabled" if state else "disabled" 143 if state and not ad.bluetooth.isBluetoothOn(): 144 ad.bluetooth.enableBluetooth() 145 time.sleep(3) 146 elif not state and ad.bluetooth.isBluetoothOn() : 147 ad.bluetooth.disableBluetooth() 148 time.sleep(3) 149 asserts.assert_equal(ad.bluetooth.isBluetoothOn(), state, 'Bluetooth state change failed') 150 # Check for BLE RSSI or BLE CS availability 151 asserts.assert_true(_is_technology_state(ad, RangingTechnology.BLE_RSSI, state, timeout_s=60), 152 "BT is not %s in ranging API" % failure_msg) 153 ad.bluetooth.reset() 154 155def reset_wifi_state( 156 ad: android_device.AndroidDevice 157): 158 """Reset Wifi state to off and then on before each test. 159 160 Args: 161 ad: android device object. 162 """ 163 ad.ranging.setWifiEnabled(False) 164 time.sleep(2) 165 asserts.assert_false(ad.ranging.isWifiEnabled(), 'Wifi did not stop') 166 ad.ranging.setWifiEnabled(True) 167 time.sleep(2) 168 asserts.assert_true(ad.ranging.isWifiEnabled(), 'Wifi did not stop') 169 # Check for WIFI RTT availability 170 asserts.assert_true(_is_technology_state(ad, RangingTechnology.WIFI_RTT, True, timeout_s=60), 171 "Wifi RTT is not enabled in ranging API") 172 173def set_wifi_state_and_verify( 174 ad: android_device.AndroidDevice, 175 state: bool 176): 177 """Sets Wifi state to on or off and verifies it. 178 179 Args: 180 ad: android device object. 181 state: bool, True for BT on, False for off. 182 """ 183 failure_msg = "enabled" if state else "disabled" 184 ad.ranging.setWifiEnabled(state) 185 time.sleep(1) 186 asserts.assert_equal(ad.ranging.isWifiEnabled(), state, 'Wifi state change failed') 187 # Check for WIFI RTT availability 188 asserts.assert_true(_is_technology_state(ad, RangingTechnology.WIFI_RTT, state, timeout_s=60), 189 "Wifi RTT is not %s in ranging API" % failure_msg) 190 191 192def set_screen_rotation_landscape( 193 ad: android_device.AndroidDevice, isLandscape: bool 194): 195 """Sets screen orientation to landscape or portrait mode. 196 197 Args: 198 ad: android device object. 199 isLandscape: True for landscape mode, False for potrait. 200 """ 201 ad.adb.shell(["settings", "put", "system", "accelerometer_rotation", "0"]) 202 ad.adb.shell([ 203 "settings", 204 "put", 205 "system", 206 "user_rotation", 207 "1" if isLandscape else "0", 208 ]) 209 210 211def set_snippet_foreground_state( 212 ad: android_device.AndroidDevice, isForeground: bool 213): 214 """Sets the snippet app's foreground/background state. 215 216 Args: 217 ad: android device object. 218 isForeground: True to move snippet to foreground, False for background. 219 """ 220 ad.adb.shell([ 221 "cmd", 222 "uwb", 223 "simulate-app-state-change", 224 "com.google.snippet.ranging", 225 "foreground" if isForeground else "background", 226 ]) 227 228 229def set_screen_state( 230 ad: android_device.AndroidDevice, on: bool 231): 232 """Sets the device screen state on/off. 233 234 Args: 235 ad: android device object. 236 on: True for screen on, False for screen off. 237 """ 238 ad.adb.shell([ 239 "svc", "power", "stayon", "true" if on else "false", 240 ]) 241