1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.platform.helpers; 18 19 import android.app.Instrumentation; 20 import android.bluetooth.BluetoothAdapter; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.net.wifi.WifiManager; 24 import android.os.UserHandle; 25 import android.platform.helpers.ScrollUtility.ScrollActions; 26 import android.platform.helpers.ScrollUtility.ScrollDirection; 27 import android.util.Log; 28 29 import androidx.test.InstrumentationRegistry; 30 import androidx.test.uiautomator.By; 31 import androidx.test.uiautomator.BySelector; 32 import androidx.test.uiautomator.UiObject2; 33 34 import java.util.List; 35 import java.util.Locale; 36 import java.util.regex.Pattern; 37 38 /** Setting Helper class for Android Auto platform functional tests */ 39 public class SettingHelperImpl extends AbstractStandardAppHelper implements IAutoSettingHelper { 40 private static final String LOG_TAG = SettingHelperImpl.class.getSimpleName(); 41 42 private static final String SCREEN_BRIGHTNESS = "screen_brightness"; 43 44 private final ScrollUtility mScrollUtility; 45 private final SeekUtility mSeekUtility; 46 private Context mContext; 47 private boolean mUseCommandToOpenSettings = true; 48 SettingHelperImpl(Instrumentation instr)49 public SettingHelperImpl(Instrumentation instr) { 50 super(instr); 51 mContext = InstrumentationRegistry.getContext(); 52 mUseCommandToOpenSettings = 53 Boolean.parseBoolean( 54 InstrumentationRegistry.getArguments() 55 .getString("use_command_to_open_settings", "true")); 56 mScrollUtility = ScrollUtility.getInstance(getSpectatioUiUtil()); 57 mSeekUtility = SeekUtility.getInstance(getSpectatioUiUtil()); 58 } 59 60 /** {@inheritDoc} */ 61 @Override open()62 public void open() { 63 if (mUseCommandToOpenSettings) { 64 Log.i(LOG_TAG, "Using Command to open Settings."); 65 openFullSettings(); 66 } else { 67 Log.i(LOG_TAG, "Using Intent to open Settings."); 68 openSettingsIntent(); 69 } 70 } 71 72 /** {@inheritDoc} */ 73 @Override getPackage()74 public String getPackage() { 75 return getPackageFromConfig(AutomotiveConfigConstants.SETTINGS_PACKAGE); 76 } 77 78 @Override dismissInitialDialogs()79 public void dismissInitialDialogs() { 80 // Nothing to dismiss 81 } 82 83 /** {@inheritDoc} */ 84 @Override stopSettingsApplication()85 public void stopSettingsApplication() { 86 getSpectatioUiUtil() 87 .executeShellCommand( 88 getCommandFromConfig(AutomotiveConfigConstants.STOP_SETTING_APP_COMMAND)); 89 } 90 91 /** {@inheritDoc} */ 92 @Override getLauncherName()93 public String getLauncherName() { 94 return "Settings"; 95 } 96 97 /** {@inheritDoc} */ 98 @Override exit()99 public void exit() { 100 getSpectatioUiUtil().pressHome(); 101 getSpectatioUiUtil().wait1Second(); 102 } 103 104 /** {@inheritDoc} */ 105 @Override openSetting(String setting)106 public void openSetting(String setting) { 107 executeWorkflow(setting); 108 } 109 110 @Override getPageTitleText()111 public String getPageTitleText() { 112 UiObject2 pageToolbarTitle = getPageTitle(); 113 return pageToolbarTitle.getText(); 114 } 115 116 /** {@inheritDoc} */ 117 @Override openFullSettings()118 public void openFullSettings() { 119 getSpectatioUiUtil() 120 .executeShellCommand( 121 getCommandFromConfig(AutomotiveConfigConstants.OPEN_SETTINGS_COMMAND)); 122 } 123 openSettingsIntent()124 private void openSettingsIntent() { 125 // Launch the application as normal. 126 String pkg = getPackage(); 127 Log.i(LOG_TAG, String.format("Sending command to launch app: %s", pkg)); 128 mInstrumentation 129 .getContext() 130 .startActivityAsUser( 131 getOpenAppIntent().addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 132 UserHandle.CURRENT); 133 } 134 135 /** {@inheritDoc} */ 136 @Override turnOnOffWifi(boolean onOff)137 public void turnOnOffWifi(boolean onOff) { 138 boolean isOn = isWifiOn(); 139 if (isOn != onOff) { 140 BySelector enableOptionSelector = 141 getUiElementFromConfig(AutomotiveConfigConstants.TOGGLE_WIFI); 142 UiObject2 enableOption = getSpectatioUiUtil().findUiObject(enableOptionSelector); 143 getSpectatioUiUtil() 144 .validateUiObject(enableOption, AutomotiveConfigConstants.TOGGLE_WIFI); 145 getSpectatioUiUtil().clickAndWait(enableOption); 146 } else { 147 throw new RuntimeException("Wi-Fi enabled state is already " + (onOff ? "on" : "off")); 148 } 149 } 150 151 /** {@inheritDoc} */ 152 @Override isWifiOn()153 public boolean isWifiOn() { 154 WifiManager wifi = (WifiManager) this.mContext.getSystemService(Context.WIFI_SERVICE); 155 return wifi.isWifiEnabled(); 156 } 157 158 /** {@inheritDoc} */ 159 @Override turnOnOffHotspot(boolean onOff)160 public void turnOnOffHotspot(boolean onOff) { 161 boolean isOn = isHotspotOn(); 162 if (isOn != onOff) { 163 BySelector enableOptionSelector = 164 getUiElementFromConfig(AutomotiveConfigConstants.TOGGLE_HOTSPOT); 165 UiObject2 enableOption = getSpectatioUiUtil().findUiObject(enableOptionSelector); 166 getSpectatioUiUtil() 167 .validateUiObject(enableOption, AutomotiveConfigConstants.TOGGLE_HOTSPOT); 168 getSpectatioUiUtil().clickAndWait(enableOption); 169 } else { 170 throw new RuntimeException( 171 "Hotspot enabled state is already " + (onOff ? "on" : "off")); 172 } 173 } 174 175 /** {@inheritDoc} */ 176 @Override toggleHotspot()177 public void toggleHotspot() { 178 BySelector enableOptionSelector = 179 getUiElementFromConfig(AutomotiveConfigConstants.TOGGLE_HOTSPOT); 180 UiObject2 enableOption = getSpectatioUiUtil().findUiObject(enableOptionSelector); 181 getSpectatioUiUtil() 182 .validateUiObject(enableOption, AutomotiveConfigConstants.TOGGLE_HOTSPOT); 183 getSpectatioUiUtil().clickAndWait(enableOption); 184 } 185 186 /** {@inheritDoc} */ 187 @Override isHotspotOn()188 public boolean isHotspotOn() { 189 return !(getSpectatioUiUtil().hasUiElement("Off")); 190 } 191 192 /** {@inheritDoc} */ 193 @Override turnOnOffBluetooth(boolean onOff)194 public void turnOnOffBluetooth(boolean onOff) { 195 boolean isOn = isBluetoothOn(); 196 if (isOn != onOff) { 197 BySelector enableOptionSelector = 198 getUiElementFromConfig(AutomotiveConfigConstants.TOGGLE_BLUETOOTH); 199 UiObject2 enableOption = getSpectatioUiUtil().findUiObject(enableOptionSelector); 200 getSpectatioUiUtil() 201 .validateUiObject(enableOption, AutomotiveConfigConstants.TOGGLE_BLUETOOTH); 202 getSpectatioUiUtil().clickAndWait(enableOption); 203 } else { 204 throw new RuntimeException( 205 "Bluetooth enabled state is already " + (onOff ? "on" : "off")); 206 } 207 } 208 209 /** {@inheritDoc} */ 210 @Override isBluetoothOn()211 public boolean isBluetoothOn() { 212 BluetoothAdapter ba = BluetoothAdapter.getDefaultAdapter(); 213 return ba.isEnabled(); 214 } 215 216 /** {@inheritDoc} */ 217 @Override searchAndSelect(String item)218 public void searchAndSelect(String item) { 219 searchAndSelect(item, 0); 220 } 221 222 /** {@inheritDoc} */ 223 @Override searchAndSelect(String item, int selectedIndex)224 public void searchAndSelect(String item, int selectedIndex) { 225 BySelector searchButtonSelector = getUiElementFromConfig(AutomotiveConfigConstants.SEARCH); 226 UiObject2 searchButton = getSpectatioUiUtil().findUiObject(searchButtonSelector); 227 getSpectatioUiUtil().validateUiObject(searchButton, AutomotiveConfigConstants.SEARCH); 228 getSpectatioUiUtil().clickAndWait(searchButton); 229 getSpectatioUiUtil().waitForIdle(); 230 231 BySelector searchBoxSelector = getUiElementFromConfig(AutomotiveConfigConstants.SEARCH_BOX); 232 UiObject2 searchBox = getSpectatioUiUtil().findUiObject(searchBoxSelector); 233 getSpectatioUiUtil().validateUiObject(searchBox, AutomotiveConfigConstants.SEARCH_BOX); 234 searchBox.setText(item); 235 getSpectatioUiUtil().wait5Seconds(); 236 237 BySelector searchResultsSelector = 238 getUiElementFromConfig(AutomotiveConfigConstants.SEARCH_RESULTS); 239 UiObject2 searchResults = getSpectatioUiUtil().findUiObject(searchResultsSelector); 240 241 getSpectatioUiUtil() 242 .validateUiObject(searchResults, AutomotiveConfigConstants.SEARCH_RESULTS); 243 int numberOfResults = searchResults.getChildren().get(0).getChildren().size(); 244 if (numberOfResults == 0) { 245 throw new RuntimeException("No results found"); 246 } 247 getSpectatioUiUtil() 248 .clickAndWait(searchResults.getChildren().get(0).getChildren().get(selectedIndex)); 249 getSpectatioUiUtil().waitForIdle(); 250 getSpectatioUiUtil().wait5Seconds(); 251 252 BySelector objectSelector = By.textContains(item); 253 UiObject2 object = getSpectatioUiUtil().findUiObject(objectSelector); 254 getSpectatioUiUtil().validateUiObject(object, AutomotiveConfigConstants.SEARCH_RESULTS); 255 getSpectatioUiUtil() 256 .validateUiObject( 257 object, String.format("Opened page does not contain searched item")); 258 } 259 260 /** {@inheritDoc} */ 261 @Override isValidPageTitle(String item)262 public boolean isValidPageTitle(String item) { 263 UiObject2 pageTitle = getPageTitle(); 264 return pageTitle.getText().contains(item); 265 } 266 getPageTitle()267 private UiObject2 getPageTitle() { 268 getSpectatioUiUtil().wait5Seconds(); 269 BySelector[] selectors = 270 new BySelector[] { 271 getUiElementFromConfig(AutomotiveConfigConstants.PAGE_TITLE), 272 getUiElementFromConfig(AutomotiveConfigConstants.PERMISSIONS_PAGE_TITLE) 273 }; 274 275 for (BySelector selector : selectors) { 276 List<UiObject2> pageTitles = getSpectatioUiUtil().findUiObjects(selector); 277 if (pageTitles != null && pageTitles.size() > 0) { 278 return pageTitles.get(pageTitles.size() - 1); 279 } 280 } 281 throw new RuntimeException("Unable to find page title"); 282 } 283 284 /** {@inheritDoc} */ 285 @Override goBackToSettingsScreen()286 public void goBackToSettingsScreen() { 287 // count is used to avoid infinite loop in case someone invokes 288 // after exiting settings application 289 int count = 5; 290 BySelector titleText = 291 getUiElementFromConfig(AutomotiveConfigConstants.SETTINGS_TITLE_TEXT); 292 while (count > 0 293 && isAppInForeground() 294 && getSpectatioUiUtil().findUiObjects(titleText) == null) { 295 getSpectatioUiUtil().pressBack(); 296 getSpectatioUiUtil().wait5Seconds(); // to avoid stale object error 297 count--; 298 } 299 } 300 301 /** {@inheritDoc} */ 302 @Override openMenuWith(String... menuOptions)303 public void openMenuWith(String... menuOptions) { 304 // Scroll and Find Subsettings 305 for (String menu : menuOptions) { 306 Pattern menuPattern = Pattern.compile(menu, Pattern.CASE_INSENSITIVE); 307 BySelector selector = By.text(menuPattern); 308 309 ScrollActions scrollAction = 310 ScrollActions.valueOf( 311 getActionFromConfig( 312 AutomotiveConfigConstants.SETTINGS_SUB_SETTING_SCROLL_ACTION)); 313 314 BySelector forwardButtonSelector = 315 getUiElementFromConfig( 316 AutomotiveConfigConstants.SETTINGS_SUB_SETTING_SCROLL_FORWARD_BUTTON); 317 BySelector backwardButtonSelector = 318 getUiElementFromConfig( 319 AutomotiveConfigConstants.SETTINGS_SUB_SETTING_SCROLL_BACKWARD_BUTTON); 320 321 BySelector scrollableElementSelector = 322 getUiElementFromConfig( 323 AutomotiveConfigConstants.SETTINGS_SUB_SETTING_SCROLL_ELEMENT); 324 ScrollDirection scrollDirection = 325 ScrollDirection.valueOf( 326 getActionFromConfig( 327 AutomotiveConfigConstants 328 .SETTINGS_SUB_SETTING_SCROLL_DIRECTION)); 329 330 UiObject2 object = 331 mScrollUtility.scrollAndFindUiObject( 332 scrollAction, 333 scrollDirection, 334 forwardButtonSelector, 335 backwardButtonSelector, 336 scrollableElementSelector, 337 selector, 338 String.format("Scroll on setting to find subssetting %s", selector)); 339 340 getSpectatioUiUtil() 341 .validateUiObject( 342 object, 343 String.format("Unable to find UI Element %s.", selector.toString())); 344 getSpectatioUiUtil().clickAndWait(object); 345 getSpectatioUiUtil().waitForIdle(); 346 } 347 } 348 349 /** {@inheritDoc} */ 350 @Override getValue(String setting)351 public int getValue(String setting) { 352 String cmd = String.format("settings get system %s", setting); 353 String value = getSpectatioUiUtil().executeShellCommand(cmd); 354 return Integer.parseInt(value.replaceAll("\\s", "")); 355 } 356 357 /** {@inheritDoc} */ 358 @Override setValue(String setting, int value)359 public void setValue(String setting, int value) { 360 String cmd = String.format(Locale.US, "settings put system %s %d", setting, value); 361 getSpectatioUiUtil().executeShellCommand(cmd); 362 } 363 364 /** {@inheritDoc} */ 365 @Override checkMenuExists(String setting)366 public boolean checkMenuExists(String setting) { 367 return getSpectatioUiUtil().hasUiElement(setting); 368 } 369 370 /** 371 * TODO - Keeping the below empty functions for now, to avoid the compilation error in Vendor it 372 * will be removed after vendor clean up (b/266450258) 373 */ 374 375 /** {@inheritDoc} */ 376 @Override findSettingMenu(String setting)377 public UiObject2 findSettingMenu(String setting) { 378 UiObject2 menuObject = null; 379 return menuObject; 380 } 381 382 @Override findSettingMenuAndClick(String setting)383 public void findSettingMenuAndClick(String setting) {} 384 385 @Override setBrightness(float targetPercentage)386 public int setBrightness(float targetPercentage) { 387 mSeekUtility.registerSeekBar( 388 SCREEN_BRIGHTNESS, 389 AutomotiveConfigConstants.BRIGHTNESS_SEEKBAR, 390 SeekUtility.SeekLayout.HORIZONTAL, 391 () -> getValue(SCREEN_BRIGHTNESS)); 392 return mSeekUtility.seek(SCREEN_BRIGHTNESS, targetPercentage); 393 } 394 395 /** 396 * Checks whether a setting menu is enabled or not. When not enabled, the menu item cannot be 397 * clicked. 398 */ 399 @Override isSettingMenuEnabled(String menu)400 public boolean isSettingMenuEnabled(String menu) { 401 boolean isSettingMenuEnabled = false; 402 return isSettingMenuEnabled; 403 } 404 getMenu(String menu, int index)405 private UiObject2 getMenu(String menu, int index) { 406 UiObject2 menuButton = null; 407 return menuButton; 408 } 409 410 /** {@inheritDoc} */ 411 @Override isRecentAppDisplayedInLocationSettings(String app)412 public boolean isRecentAppDisplayedInLocationSettings(String app) { 413 UiObject2 recentApp = getSpectatioUiUtil().findUiObject("Maps"); 414 getSpectatioUiUtil() 415 .validateUiObject(recentApp, String.format("Recently accessed app - %s", app)); 416 UiObject2 recentAppsTime = recentApp.getParent(); 417 if (recentAppsTime.getChildren().size() < 2) { 418 throw new RuntimeException("TimeStamp not displayed for Recently accessed app"); 419 } 420 BySelector recentAppTimeStampSelector = 421 getUiElementFromConfig(AutomotiveConfigConstants.RECENT_APPS_TIMESTAMP); 422 UiObject2 timestampObject = 423 getSpectatioUiUtil() 424 .findUiObjectInGivenElement(recentAppsTime, recentAppTimeStampSelector); 425 getSpectatioUiUtil().validateUiObject(timestampObject, String.format("timestamp object")); 426 String timestamp = timestampObject.getText(); 427 String recentAppTimeStampTxt = 428 getActionFromConfig(AutomotiveConfigConstants.RECENT_APPS_TIMESTAMP_TEXT); 429 return timestamp.contains(recentAppTimeStampTxt); 430 } 431 } 432