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 BySelector enableOptionSelector = 190 getUiElementFromConfig(AutomotiveConfigConstants.TOGGLE_HOTSPOT); 191 UiObject2 enableOption = getSpectatioUiUtil().findUiObject(enableOptionSelector); 192 getSpectatioUiUtil() 193 .validateUiObject(enableOption, AutomotiveConfigConstants.TOGGLE_HOTSPOT); 194 return enableOption.isChecked(); 195 } 196 197 /** {@inheritDoc} */ 198 @Override turnOnOffBluetooth(boolean onOff)199 public void turnOnOffBluetooth(boolean onOff) { 200 boolean isOn = isBluetoothOn(); 201 if (isOn != onOff) { 202 BySelector enableOptionSelector = 203 getUiElementFromConfig(AutomotiveConfigConstants.TOGGLE_BLUETOOTH); 204 UiObject2 enableOption = getSpectatioUiUtil().findUiObject(enableOptionSelector); 205 getSpectatioUiUtil() 206 .validateUiObject(enableOption, AutomotiveConfigConstants.TOGGLE_BLUETOOTH); 207 getSpectatioUiUtil().clickAndWait(enableOption); 208 } else { 209 throw new RuntimeException( 210 "Bluetooth enabled state is already " + (onOff ? "on" : "off")); 211 } 212 } 213 214 /** {@inheritDoc} */ 215 @Override isBluetoothOn()216 public boolean isBluetoothOn() { 217 BluetoothAdapter ba = BluetoothAdapter.getDefaultAdapter(); 218 return ba.isEnabled(); 219 } 220 221 /** {@inheritDoc} */ 222 @Override searchAndSelect(String item)223 public void searchAndSelect(String item) { 224 searchAndSelect(item, 0); 225 } 226 227 /** {@inheritDoc} */ 228 @Override searchAndSelect(String item, int selectedIndex)229 public void searchAndSelect(String item, int selectedIndex) { 230 BySelector searchButtonSelector = getUiElementFromConfig(AutomotiveConfigConstants.SEARCH); 231 UiObject2 searchButton = getSpectatioUiUtil().findUiObject(searchButtonSelector); 232 getSpectatioUiUtil().validateUiObject(searchButton, AutomotiveConfigConstants.SEARCH); 233 getSpectatioUiUtil().clickAndWait(searchButton); 234 getSpectatioUiUtil().waitForIdle(); 235 236 BySelector searchBoxSelector = getUiElementFromConfig(AutomotiveConfigConstants.SEARCH_BOX); 237 UiObject2 searchBox = getSpectatioUiUtil().findUiObject(searchBoxSelector); 238 getSpectatioUiUtil().validateUiObject(searchBox, AutomotiveConfigConstants.SEARCH_BOX); 239 searchBox.setText(item); 240 getSpectatioUiUtil().wait5Seconds(); 241 242 BySelector searchResultsSelector = 243 getUiElementFromConfig(AutomotiveConfigConstants.SEARCH_RESULTS); 244 UiObject2 searchResults = getSpectatioUiUtil().findUiObject(searchResultsSelector); 245 246 getSpectatioUiUtil() 247 .validateUiObject(searchResults, AutomotiveConfigConstants.SEARCH_RESULTS); 248 int numberOfResults = searchResults.getChildren().get(0).getChildren().size(); 249 if (numberOfResults == 0) { 250 throw new RuntimeException("No results found"); 251 } 252 getSpectatioUiUtil() 253 .clickAndWait(searchResults.getChildren().get(0).getChildren().get(selectedIndex)); 254 getSpectatioUiUtil().waitForIdle(); 255 getSpectatioUiUtil().wait5Seconds(); 256 257 BySelector objectSelector = By.textContains(item); 258 UiObject2 object = getSpectatioUiUtil().findUiObject(objectSelector); 259 getSpectatioUiUtil().validateUiObject(object, AutomotiveConfigConstants.SEARCH_RESULTS); 260 getSpectatioUiUtil() 261 .validateUiObject( 262 object, String.format("Opened page does not contain searched item")); 263 } 264 265 /** {@inheritDoc} */ 266 @Override isValidPageTitle(String item)267 public boolean isValidPageTitle(String item) { 268 UiObject2 pageTitle = getPageTitle(); 269 return pageTitle.getText().contains(item); 270 } 271 getPageTitle()272 private UiObject2 getPageTitle() { 273 getSpectatioUiUtil().wait5Seconds(); 274 BySelector[] selectors = 275 new BySelector[] { 276 getUiElementFromConfig(AutomotiveConfigConstants.PAGE_TITLE), 277 getUiElementFromConfig(AutomotiveConfigConstants.PERMISSIONS_PAGE_TITLE) 278 }; 279 280 for (BySelector selector : selectors) { 281 List<UiObject2> pageTitles = getSpectatioUiUtil().findUiObjects(selector); 282 if (pageTitles != null && pageTitles.size() > 0) { 283 return pageTitles.get(pageTitles.size() - 1); 284 } 285 } 286 throw new RuntimeException("Unable to find page title"); 287 } 288 289 /** {@inheritDoc} */ 290 @Override goBackToSettingsScreen()291 public void goBackToSettingsScreen() { 292 // count is used to avoid infinite loop in case someone invokes 293 // after exiting settings application 294 int count = 5; 295 BySelector titleText = 296 getUiElementFromConfig(AutomotiveConfigConstants.SETTINGS_TITLE_TEXT); 297 while (count > 0 298 && isAppInForeground() 299 && getSpectatioUiUtil().findUiObjects(titleText) == null) { 300 getSpectatioUiUtil().pressBack(); 301 getSpectatioUiUtil().wait5Seconds(); // to avoid stale object error 302 count--; 303 } 304 } 305 306 /** {@inheritDoc} */ 307 @Override openMenuWith(String... menuOptions)308 public void openMenuWith(String... menuOptions) { 309 // Scroll and Find Subsettings 310 for (String menu : menuOptions) { 311 Pattern menuPattern = Pattern.compile(menu, Pattern.CASE_INSENSITIVE); 312 BySelector selector = By.text(menuPattern); 313 314 ScrollActions scrollAction = 315 ScrollActions.valueOf( 316 getActionFromConfig( 317 AutomotiveConfigConstants.SETTINGS_SUB_SETTING_SCROLL_ACTION)); 318 319 BySelector forwardButtonSelector = 320 getUiElementFromConfig( 321 AutomotiveConfigConstants.SETTINGS_SUB_SETTING_SCROLL_FORWARD_BUTTON); 322 BySelector backwardButtonSelector = 323 getUiElementFromConfig( 324 AutomotiveConfigConstants.SETTINGS_SUB_SETTING_SCROLL_BACKWARD_BUTTON); 325 326 BySelector scrollableElementSelector = 327 getUiElementFromConfig( 328 AutomotiveConfigConstants.SETTINGS_SUB_SETTING_SCROLL_ELEMENT); 329 ScrollDirection scrollDirection = 330 ScrollDirection.valueOf( 331 getActionFromConfig( 332 AutomotiveConfigConstants 333 .SETTINGS_SUB_SETTING_SCROLL_DIRECTION)); 334 335 UiObject2 object = 336 mScrollUtility.scrollAndFindUiObject( 337 scrollAction, 338 scrollDirection, 339 forwardButtonSelector, 340 backwardButtonSelector, 341 scrollableElementSelector, 342 selector, 343 String.format("Scroll on setting to find subssetting %s", selector)); 344 345 getSpectatioUiUtil() 346 .validateUiObject( 347 object, 348 String.format("Unable to find UI Element %s.", selector.toString())); 349 getSpectatioUiUtil().clickAndWait(object); 350 getSpectatioUiUtil().waitForIdle(); 351 } 352 } 353 354 /** {@inheritDoc} */ 355 @Override getValue(String setting)356 public int getValue(String setting) { 357 String cmd = String.format("settings get system %s", setting); 358 String value = getSpectatioUiUtil().executeShellCommand(cmd); 359 return Integer.parseInt(value.replaceAll("\\s", "")); 360 } 361 362 /** {@inheritDoc} */ 363 @Override setValue(String setting, int value)364 public void setValue(String setting, int value) { 365 String cmd = String.format(Locale.US, "settings put system %s %d", setting, value); 366 getSpectatioUiUtil().executeShellCommand(cmd); 367 } 368 369 /** {@inheritDoc} */ 370 @Override checkMenuExists(String setting)371 public boolean checkMenuExists(String setting) { 372 return getSpectatioUiUtil().hasUiElement(setting); 373 } 374 375 /** 376 * TODO - Keeping the below empty functions for now, to avoid the compilation error in Vendor it 377 * will be removed after vendor clean up (b/266450258) 378 */ 379 380 /** {@inheritDoc} */ 381 @Override findSettingMenu(String setting)382 public UiObject2 findSettingMenu(String setting) { 383 UiObject2 menuObject = null; 384 return menuObject; 385 } 386 387 @Override findSettingMenuAndClick(String setting)388 public void findSettingMenuAndClick(String setting) {} 389 390 @Override setBrightness(float targetPercentage)391 public int setBrightness(float targetPercentage) { 392 mSeekUtility.registerSeekBar( 393 SCREEN_BRIGHTNESS, 394 AutomotiveConfigConstants.BRIGHTNESS_SEEKBAR, 395 SeekUtility.SeekLayout.HORIZONTAL, 396 () -> getValue(SCREEN_BRIGHTNESS)); 397 return mSeekUtility.seek(SCREEN_BRIGHTNESS, targetPercentage); 398 } 399 400 /** 401 * Checks whether a setting menu is enabled or not. When not enabled, the menu item cannot be 402 * clicked. 403 */ 404 @Override isSettingMenuEnabled(String menu)405 public boolean isSettingMenuEnabled(String menu) { 406 boolean isSettingMenuEnabled = false; 407 return isSettingMenuEnabled; 408 } 409 getMenu(String menu, int index)410 private UiObject2 getMenu(String menu, int index) { 411 UiObject2 menuButton = null; 412 return menuButton; 413 } 414 415 /** {@inheritDoc} */ 416 @Override isRecentAppDisplayedInLocationSettings(String app)417 public boolean isRecentAppDisplayedInLocationSettings(String app) { 418 UiObject2 recentApp = getSpectatioUiUtil().findUiObject("Maps"); 419 getSpectatioUiUtil() 420 .validateUiObject(recentApp, String.format("Recently accessed app - %s", app)); 421 UiObject2 recentAppsTime = recentApp.getParent(); 422 if (recentAppsTime.getChildren().size() < 2) { 423 throw new RuntimeException("TimeStamp not displayed for Recently accessed app"); 424 } 425 BySelector recentAppTimeStampSelector = 426 getUiElementFromConfig(AutomotiveConfigConstants.RECENT_APPS_TIMESTAMP); 427 UiObject2 timestampObject = 428 getSpectatioUiUtil() 429 .findUiObjectInGivenElement(recentAppsTime, recentAppTimeStampSelector); 430 getSpectatioUiUtil().validateUiObject(timestampObject, String.format("timestamp object")); 431 String timestamp = timestampObject.getText(); 432 String recentAppTimeStampTxt = 433 getActionFromConfig(AutomotiveConfigConstants.RECENT_APPS_TIMESTAMP_TEXT); 434 return timestamp.contains(recentAppTimeStampTxt); 435 } 436 } 437