• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.ArrayList;
35 import java.util.List;
36 import java.util.Locale;
37 import java.util.regex.Pattern;
38 
39 /** Setting Helper class for Android Auto platform functional tests */
40 public class SettingHelperImpl extends AbstractStandardAppHelper implements IAutoSettingHelper {
41     private static final String LOG_TAG = SettingHelperImpl.class.getSimpleName();
42 
43     private static final String SCREEN_BRIGHTNESS = "screen_brightness";
44 
45     private ScrollUtility mScrollUtility;
46 
47     private HelperAccessor<IAutoUISettingsHelper> mSettingUIHelper =
48             new HelperAccessor<>(IAutoUISettingsHelper.class);
49     private ScrollActions mScrollAction;
50     private BySelector mBackwardButtonSelector;
51     private BySelector mForwardButtonSelector;
52     private BySelector mScrollableElementSelector;
53     private ScrollDirection mScrollDirection;
54     private final SeekUtility mSeekUtility;
55     private Context mContext;
56     private boolean mUseCommandToOpenSettings = true;
57 
SettingHelperImpl(Instrumentation instr)58     public SettingHelperImpl(Instrumentation instr) {
59         super(instr);
60         mContext = InstrumentationRegistry.getContext();
61         mUseCommandToOpenSettings =
62                 Boolean.parseBoolean(
63                         InstrumentationRegistry.getArguments()
64                                 .getString("use_command_to_open_settings", "true"));
65         mScrollUtility = ScrollUtility.getInstance(getSpectatioUiUtil());
66         mScrollAction =
67                 ScrollActions.valueOf(
68                         getActionFromConfig(AutomotiveConfigConstants.SETTINGS_SCROLL_ACTION));
69         mBackwardButtonSelector =
70                 getUiElementFromConfig(AutomotiveConfigConstants.SETTINGS_SCROLL_BACKWARD_BUTTON);
71         mForwardButtonSelector =
72                 getUiElementFromConfig(AutomotiveConfigConstants.SETTINGS_SCROLL_FORWARD_BUTTON);
73         mScrollableElementSelector =
74                 getUiElementFromConfig(AutomotiveConfigConstants.SETTINGS_SCROLL_ELEMENT);
75         mScrollDirection =
76                 ScrollDirection.valueOf(
77                         getActionFromConfig(AutomotiveConfigConstants.SETTINGS_SCROLL_DIRECTION));
78         mSeekUtility = SeekUtility.getInstance(getSpectatioUiUtil());
79     }
80 
81     /** {@inheritDoc} */
82     @Override
open()83     public void open() {
84         if (mUseCommandToOpenSettings) {
85             Log.i(LOG_TAG, "Using Command to open Settings.");
86             openFullSettings();
87         } else {
88             Log.i(LOG_TAG, "Using Intent to open Settings.");
89             openSettingsIntent();
90         }
91     }
92 
93     /** {@inheritDoc} */
94     @Override
getPackage()95     public String getPackage() {
96         return getPackageFromConfig(AutomotiveConfigConstants.SETTINGS_PACKAGE);
97     }
98 
99     @Override
dismissInitialDialogs()100     public void dismissInitialDialogs() {
101         // Nothing to dismiss
102     }
103 
104     /** {@inheritDoc} */
105     @Override
stopSettingsApplication()106     public void stopSettingsApplication() {
107         getSpectatioUiUtil()
108                 .executeShellCommand(
109                         getCommandFromConfig(AutomotiveConfigConstants.STOP_SETTING_APP_COMMAND));
110     }
111 
112     /** {@inheritDoc} */
113     @Override
getLauncherName()114     public String getLauncherName() {
115         return "Settings";
116     }
117 
118     /** {@inheritDoc} */
119     @Override
exit()120     public void exit() {
121         getSpectatioUiUtil().pressHome();
122         getSpectatioUiUtil().wait1Second();
123     }
124 
125     /** {@inheritDoc} */
126     @Override
openSetting(String setting)127     public void openSetting(String setting) {
128         executeWorkflow(setting);
129     }
130 
131     @Override
getPageTitleText()132     public String getPageTitleText() {
133         UiObject2 pageToolbarTitle = getPageTitle();
134         return pageToolbarTitle.getText();
135     }
136 
137     /** {@inheritDoc} */
138     @Override
openFullSettings()139     public void openFullSettings() {
140         getSpectatioUiUtil()
141                 .executeShellCommand(
142                         getCommandFromConfig(AutomotiveConfigConstants.OPEN_SETTINGS_COMMAND));
143     }
144 
openSettingsIntent()145     private void openSettingsIntent() {
146         // Launch the application as normal.
147         String pkg = getPackage();
148         Log.i(LOG_TAG, String.format("Sending command to launch app: %s", pkg));
149         mInstrumentation
150                 .getContext()
151                 .startActivityAsUser(
152                         getOpenAppIntent().addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
153                         UserHandle.CURRENT);
154     }
155 
156     /** {@inheritDoc} */
157     @Override
turnOnOffWifi(boolean onOff)158     public void turnOnOffWifi(boolean onOff) {
159         boolean isOn = isWifiOn();
160         if (isOn != onOff) {
161             BySelector enableOptionSelector =
162                     getUiElementFromConfig(AutomotiveConfigConstants.TOGGLE_WIFI);
163             UiObject2 enableOption = getSpectatioUiUtil().findUiObject(enableOptionSelector);
164             getSpectatioUiUtil()
165                     .validateUiObject(enableOption, AutomotiveConfigConstants.TOGGLE_WIFI);
166             getSpectatioUiUtil().clickAndWait(enableOption);
167         } else {
168             throw new RuntimeException("Wi-Fi enabled state is already " + (onOff ? "on" : "off"));
169         }
170     }
171 
172     /** {@inheritDoc} */
173     @Override
isWifiOn()174     public boolean isWifiOn() {
175         WifiManager wifi = (WifiManager) this.mContext.getSystemService(Context.WIFI_SERVICE);
176         return wifi.isWifiEnabled();
177     }
178 
179     /** {@inheritDoc} */
180     @Override
turnOnOffHotspot(boolean onOff)181     public void turnOnOffHotspot(boolean onOff) {
182         boolean isOn = isHotspotOn();
183         if (isOn != onOff) {
184             BySelector enableOptionSelector =
185                     getUiElementFromConfig(AutomotiveConfigConstants.TOGGLE_HOTSPOT);
186             UiObject2 enableOption = getSpectatioUiUtil().findUiObject(enableOptionSelector);
187             getSpectatioUiUtil()
188                     .validateUiObject(enableOption, AutomotiveConfigConstants.TOGGLE_HOTSPOT);
189             getSpectatioUiUtil().clickAndWait(enableOption);
190         } else {
191             throw new RuntimeException(
192                     "Hotspot enabled state is already " + (onOff ? "on" : "off"));
193         }
194     }
195 
196     /** {@inheritDoc} */
197     @Override
toggleHotspot()198     public void toggleHotspot() {
199         BySelector enableOptionSelector =
200                 getUiElementFromConfig(AutomotiveConfigConstants.TOGGLE_HOTSPOT);
201         UiObject2 enableOption = getSpectatioUiUtil().findUiObject(enableOptionSelector);
202         getSpectatioUiUtil()
203                 .validateUiObject(enableOption, AutomotiveConfigConstants.TOGGLE_HOTSPOT);
204         getSpectatioUiUtil().clickAndWait(enableOption);
205     }
206 
207     /** {@inheritDoc} */
208     @Override
isHotspotOn()209     public boolean isHotspotOn() {
210         return !(getSpectatioUiUtil().hasUiElement("Off"));
211     }
212 
213     /** {@inheritDoc} */
214     @Override
turnOnOffBluetooth(boolean onOff)215     public void turnOnOffBluetooth(boolean onOff) {
216         boolean isOn = isBluetoothOn();
217         if (isOn != onOff) {
218             BySelector enableOptionSelector =
219                     getUiElementFromConfig(AutomotiveConfigConstants.TOGGLE_BLUETOOTH);
220             UiObject2 enableOption = getSpectatioUiUtil().findUiObject(enableOptionSelector);
221             getSpectatioUiUtil()
222                     .validateUiObject(enableOption, AutomotiveConfigConstants.TOGGLE_BLUETOOTH);
223             getSpectatioUiUtil().clickAndWait(enableOption);
224         } else {
225             throw new RuntimeException(
226                     "Bluetooth enabled state is already " + (onOff ? "on" : "off"));
227         }
228     }
229 
230     /** {@inheritDoc} */
231     @Override
isBluetoothOn()232     public boolean isBluetoothOn() {
233         BluetoothAdapter ba = BluetoothAdapter.getDefaultAdapter();
234         return ba.isEnabled();
235     }
236 
237     /** {@inheritDoc} */
238     @Override
scrollBackward()239     public boolean scrollBackward() {
240         return mScrollUtility.scrollBackward(
241                 mScrollAction,
242                 mScrollDirection,
243                 mBackwardButtonSelector,
244                 mScrollableElementSelector,
245                 String.format("Scroll backward on the settings menu page"));
246     }
247 
248     /** {@inheritDoc} */
249     @Override
scrollForward()250     public boolean scrollForward() {
251         return mScrollUtility.scrollForward(
252                 mScrollAction,
253                 mScrollDirection,
254                 mForwardButtonSelector,
255                 mScrollableElementSelector,
256                 String.format("Scroll forward on the settings menu page"));
257     }
258 
259     /** {@inheritDoc} */
260     @Override
searchAndSelect(String item)261     public void searchAndSelect(String item) {
262         searchAndSelect(item, 0);
263     }
264 
265     /** {@inheritDoc} */
266     @Override
searchAndSelect(String item, int selectedIndex)267     public void searchAndSelect(String item, int selectedIndex) {
268         BySelector searchButtonSelector = getUiElementFromConfig(AutomotiveConfigConstants.SEARCH);
269         UiObject2 searchButton = getSpectatioUiUtil().findUiObject(searchButtonSelector);
270         getSpectatioUiUtil().validateUiObject(searchButton, AutomotiveConfigConstants.SEARCH);
271         getSpectatioUiUtil().clickAndWait(searchButton);
272         getSpectatioUiUtil().waitForIdle();
273 
274         BySelector searchBoxSelector = getUiElementFromConfig(AutomotiveConfigConstants.SEARCH_BOX);
275         UiObject2 searchBox = getSpectatioUiUtil().findUiObject(searchBoxSelector);
276         getSpectatioUiUtil().validateUiObject(searchBox, AutomotiveConfigConstants.SEARCH_BOX);
277         searchBox.setText(item);
278         getSpectatioUiUtil().wait5Seconds();
279 
280         BySelector searchResultsSelector =
281                 getUiElementFromConfig(AutomotiveConfigConstants.SEARCH_RESULTS);
282         UiObject2 searchResults = getSpectatioUiUtil().findUiObject(searchResultsSelector);
283 
284         getSpectatioUiUtil()
285                 .validateUiObject(searchResults, AutomotiveConfigConstants.SEARCH_RESULTS);
286         int numberOfResults = searchResults.getChildren().get(0).getChildren().size();
287         if (numberOfResults == 0) {
288             throw new RuntimeException("No results found");
289         }
290         getSpectatioUiUtil()
291                 .clickAndWait(searchResults.getChildren().get(0).getChildren().get(selectedIndex));
292         getSpectatioUiUtil().waitForIdle();
293         getSpectatioUiUtil().wait5Seconds();
294 
295         BySelector objectSelector = By.textContains(item);
296         UiObject2 object = getSpectatioUiUtil().findUiObject(objectSelector);
297         getSpectatioUiUtil().validateUiObject(object, AutomotiveConfigConstants.SEARCH_RESULTS);
298         getSpectatioUiUtil()
299                 .validateUiObject(
300                         object, String.format("Opened page does not contain searched item"));
301     }
302 
303     /** {@inheritDoc} */
304     @Override
isValidPageTitle(String item)305     public boolean isValidPageTitle(String item) {
306         UiObject2 pageTitle = getPageTitle();
307         return pageTitle.getText().contains(item);
308     }
309 
getPageTitle()310     private UiObject2 getPageTitle() {
311         getSpectatioUiUtil().wait5Seconds();
312         BySelector[] selectors =
313                 new BySelector[] {
314                     getUiElementFromConfig(AutomotiveConfigConstants.PAGE_TITLE),
315                     getUiElementFromConfig(AutomotiveConfigConstants.PERMISSIONS_PAGE_TITLE)
316                 };
317 
318         for (BySelector selector : selectors) {
319             List<UiObject2> pageTitles = getSpectatioUiUtil().findUiObjects(selector);
320             if (pageTitles != null && pageTitles.size() > 0) {
321                 return pageTitles.get(pageTitles.size() - 1);
322             }
323         }
324         throw new RuntimeException("Unable to find page title");
325     }
326 
327     @Override
getSettingsPageTitleText()328     public String getSettingsPageTitleText() {
329         getSpectatioUiUtil().wait5Seconds();
330         BySelector selector = getUiElementFromConfig(AutomotiveConfigConstants.PAGE_TITLE);
331         List<UiObject2> pageTitles = getSpectatioUiUtil().findUiObjects(selector);
332         List<String> pageTitlesText = new ArrayList<String>();
333         for (UiObject2 pageTitle : pageTitles) {
334             pageTitlesText.add(pageTitle.getText());
335         }
336         pageTitlesText.remove("Settings");
337         return pageTitlesText.get(0);
338     }
339 
340     /** {@inheritDoc} */
341     @Override
goBackToSettingsScreen()342     public void goBackToSettingsScreen() {
343         // count is used to avoid infinite loop in case someone invokes
344         // after exiting settings application
345         int count = 5;
346         BySelector titleText =
347                 getUiElementFromConfig(AutomotiveConfigConstants.SETTINGS_TITLE_TEXT);
348         while (count > 0
349                 && isAppInForeground()
350                 && getSpectatioUiUtil().findUiObjects(titleText) == null) {
351             pressSettingsBackNavIcon();
352             getSpectatioUiUtil().wait5Seconds(); // to avoid stale object error
353             count--;
354         }
355     }
356 
357     /** {@inheritDoc} */
358     @Override
pressSettingsBackNavIcon()359     public void pressSettingsBackNavIcon() {
360         UiObject2 navIcon =
361                 getSpectatioUiUtil()
362                         .findUiObject(
363                                 getUiElementFromConfig(
364                                         AutomotiveConfigConstants.SETTINGS_BACK_NAV_ICON));
365         if (navIcon == null) {
366             // if there is no nav button, use device back for confirmation dialog case
367             getSpectatioUiUtil().pressBack();
368             return;
369         }
370         getSpectatioUiUtil().clickAndWait(navIcon);
371     }
372 
373     /** {@inheritDoc} */
374     @Override
openMenuWith(String... menuOptions)375     public void openMenuWith(String... menuOptions) {
376         // Scroll and Find Subsettings
377         for (String menu : menuOptions) {
378             Pattern menuPattern = Pattern.compile(menu, Pattern.CASE_INSENSITIVE);
379             BySelector selector = By.text(menuPattern);
380 
381             ScrollActions scrollAction =
382                     ScrollActions.valueOf(
383                             getActionFromConfig(
384                                     AutomotiveConfigConstants.SETTINGS_SUB_SETTING_SCROLL_ACTION));
385 
386             BySelector forwardButtonSelector =
387                     getUiElementFromConfig(
388                             AutomotiveConfigConstants.SETTINGS_SUB_SETTING_SCROLL_FORWARD_BUTTON);
389             BySelector backwardButtonSelector =
390                     getUiElementFromConfig(
391                             AutomotiveConfigConstants.SETTINGS_SUB_SETTING_SCROLL_BACKWARD_BUTTON);
392 
393             BySelector scrollableElementSelector =
394                     getUiElementFromConfig(
395                             AutomotiveConfigConstants.SETTINGS_SUB_SETTING_SCROLL_ELEMENT);
396             ScrollDirection scrollDirection =
397                     ScrollDirection.valueOf(
398                             getActionFromConfig(
399                                     AutomotiveConfigConstants
400                                             .SETTINGS_SUB_SETTING_SCROLL_DIRECTION));
401 
402             UiObject2 object =
403                     mScrollUtility.scrollAndFindUiObject(
404                             scrollAction,
405                             scrollDirection,
406                             forwardButtonSelector,
407                             backwardButtonSelector,
408                             scrollableElementSelector,
409                             selector,
410                             String.format("Scroll on setting to find subssetting %s", selector));
411 
412             getSpectatioUiUtil()
413                     .validateUiObject(
414                             object,
415                             String.format("Unable to find UI Element %s.", selector.toString()));
416             getSpectatioUiUtil().clickAndWait(object);
417             getSpectatioUiUtil().waitForIdle();
418         }
419     }
420 
421     /** {@inheritDoc} */
422     @Override
getValue(String setting)423     public int getValue(String setting) {
424         String cmd = String.format("settings get system %s", setting);
425         String value = getSpectatioUiUtil().executeShellCommand(cmd);
426         return Integer.parseInt(value.replaceAll("\\s", ""));
427     }
428 
429     /** {@inheritDoc} */
430     @Override
setValue(String setting, int value)431     public void setValue(String setting, int value) {
432         String cmd = String.format(Locale.US, "settings put system %s %d", setting, value);
433         getSpectatioUiUtil().executeShellCommand(cmd);
434     }
435 
436     /** {@inheritDoc} */
437     @Override
checkMenuExists(String setting)438     public boolean checkMenuExists(String setting) {
439         return getSpectatioUiUtil().hasUiElement(setting);
440     }
441 
442     /** {@inheritDoc} */
443     @Override
scrollAndCheckMenuExists(String setting)444     public boolean scrollAndCheckMenuExists(String setting) {
445         return mSettingUIHelper.get().hasUIElement(setting);
446     }
447 
448     /**
449      * TODO - Keeping the below empty functions for now, to avoid the compilation error in Vendor it
450      * will be removed after vendor clean up (b/266450258)
451      */
452 
453     /** {@inheritDoc} */
454     @Override
findSettingMenu(String setting)455     public UiObject2 findSettingMenu(String setting) {
456         UiObject2 menuObject = null;
457         return menuObject;
458     }
459 
460     @Override
findSettingMenuAndClick(String setting)461     public void findSettingMenuAndClick(String setting) {}
462 
463     @Override
setBrightness(float targetPercentage)464     public int setBrightness(float targetPercentage) {
465         mSeekUtility.registerSeekBar(
466                 SCREEN_BRIGHTNESS,
467                 AutomotiveConfigConstants.BRIGHTNESS_SEEKBAR,
468                 SeekUtility.SeekLayout.HORIZONTAL,
469                 () -> getValue(SCREEN_BRIGHTNESS));
470         return mSeekUtility.seek(SCREEN_BRIGHTNESS, targetPercentage);
471     }
472 
473     /**
474      * Checks whether a setting menu is enabled or not. When not enabled, the menu item cannot be
475      * clicked.
476      */
477     @Override
isSettingMenuEnabled(String menu)478     public boolean isSettingMenuEnabled(String menu) {
479         boolean isSettingMenuEnabled = false;
480         return isSettingMenuEnabled;
481     }
482 
getMenu(String menu, int index)483     private UiObject2 getMenu(String menu, int index) {
484         UiObject2 menuButton = null;
485         return menuButton;
486     }
487 
488     /** {@inheritDoc} */
489     @Override
isRecentAppDisplayedInLocationSettings(String app)490     public boolean isRecentAppDisplayedInLocationSettings(String app) {
491         UiObject2 recentApp = getSpectatioUiUtil().findUiObject("Maps");
492         getSpectatioUiUtil()
493                 .validateUiObject(recentApp, String.format("Recently accessed app - %s", app));
494         UiObject2 recentAppsTime = recentApp.getParent();
495         if (recentAppsTime.getChildren().size() < 2) {
496             throw new RuntimeException("TimeStamp not displayed for Recently accessed app");
497         }
498         BySelector recentAppTimeStampSelector =
499                 getUiElementFromConfig(AutomotiveConfigConstants.RECENT_APPS_TIMESTAMP);
500         UiObject2 timestampObject =
501                 getSpectatioUiUtil()
502                         .findUiObjectInGivenElement(recentAppsTime, recentAppTimeStampSelector);
503         getSpectatioUiUtil().validateUiObject(timestampObject, String.format("timestamp object"));
504         String timestamp = timestampObject.getText();
505         String recentAppTimeStampTxt =
506                 getActionFromConfig(AutomotiveConfigConstants.RECENT_APPS_TIMESTAMP_TEXT);
507         return timestamp.contains(recentAppTimeStampTxt);
508     }
509 }
510