1 /*
2  * Copyright (C) 2023 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.content.res.Resources;
21 import android.platform.helpers.ScrollUtility.ScrollActions;
22 import android.platform.helpers.ScrollUtility.ScrollDirection;
23 import android.platform.spectatio.exceptions.MissingUiElementException;
24 
25 import androidx.test.uiautomator.By;
26 import androidx.test.uiautomator.BySelector;
27 import androidx.test.uiautomator.UiObject2;
28 
29 import java.text.SimpleDateFormat;
30 import java.time.Month;
31 import java.util.Date;
32 import java.util.List;
33 
34 /** Helper class for functional tests of System settings */
35 public class SettingsSystemHelperImpl extends AbstractStandardAppHelper
36         implements IAutoSystemSettingsHelper {
37 
38     private ScrollUtility mScrollUtility;
39     private ScrollActions mScrollAction;
40     private BySelector mBackwardButtonSelector;
41     private BySelector mForwardButtonSelector;
42     private BySelector mScrollableElementSelector;
43     private ScrollDirection mScrollDirection;
44 
SettingsSystemHelperImpl(Instrumentation instr)45     public SettingsSystemHelperImpl(Instrumentation instr) {
46         super(instr);
47         mScrollUtility = ScrollUtility.getInstance(getSpectatioUiUtil());
48         mScrollAction =
49                 ScrollActions.valueOf(
50                         getActionFromConfig(
51                                 AutomotiveConfigConstants.SYSTEM_SETTINGS_SCROLL_ACTION));
52         mBackwardButtonSelector =
53                 getUiElementFromConfig(
54                         AutomotiveConfigConstants.SYSTEM_SETTINGS_SCROLL_BACKWARD_BUTTON);
55         mForwardButtonSelector =
56                 getUiElementFromConfig(
57                         AutomotiveConfigConstants.SYSTEM_SETTINGS_SCROLL_FORWARD_BUTTON);
58         mScrollableElementSelector =
59                 getUiElementFromConfig(AutomotiveConfigConstants.SYSTEM_SETTINGS_SCROLL_ELEMENT);
60         mScrollDirection =
61                 ScrollDirection.valueOf(
62                         getActionFromConfig(
63                                 AutomotiveConfigConstants.SYSTEM_SETTINGS_SCROLL_DIRECTION));
64         mScrollUtility.setScrollValues(
65                 Integer.valueOf(
66                         getActionFromConfig(
67                                 AutomotiveConfigConstants.SYSTEM_SETTINGS_SCROLL_MARGIN)),
68                 Integer.valueOf(
69                         getActionFromConfig(
70                                 AutomotiveConfigConstants.SYSTEM_SETTINGS_SCROLL_WAIT_TIME)));
71     }
72 
73     /** {@inheritDoc} */
74     @Override
getPackage()75     public String getPackage() {
76         return getPackageFromConfig(AutomotiveConfigConstants.SETTINGS_PACKAGE);
77     }
78 
79     @Override
dismissInitialDialogs()80     public void dismissInitialDialogs() {
81         // Nothing to dismiss
82     }
83 
84     /** {@inheritDoc} */
85     @Override
getLauncherName()86     public String getLauncherName() {
87         throw new UnsupportedOperationException("Operation not supported.");
88     }
89 
90     /** {@inheritDoc} */
91     @Override
setDisplayLanguage(String language)92     public void setDisplayLanguage(String language) {
93         openLanguageMenu();
94         BySelector languageSelector = By.clickable(true).hasDescendant(By.textStartsWith(language));
95         UiObject2 languageObject = getMenu(languageSelector);
96         getSpectatioUiUtil()
97                 .validateUiObject(
98                         languageObject,
99                         String.format("Unable to find UI Element for language selector"));
100         getSpectatioUiUtil().clickAndWait(languageObject);
101         String systemLanguage =
102                 Resources.getSystem().getConfiguration().getLocales().get(0).getDisplayLanguage();
103         if (!language.toLowerCase().contains(systemLanguage.toLowerCase())) {
104             throw new RuntimeException("System language is different from selected language");
105         }
106     }
107 
108     /** {@inheritDoc} */
109     @Override
getCurrentLanguage()110     public String getCurrentLanguage() {
111         UiObject2 object =
112                 getBtnByText(
113                         AutomotiveConfigConstants.LANGUAGES_MENU,
114                         AutomotiveConfigConstants.LANGUAGES_MENU_IN_SELECTED_LANGUAGE);
115         getSpectatioUiUtil()
116                 .validateUiObject(
117                         object, String.format("Unable to find UI Element for current language"));
118         String currentLanguage = getSummeryText(object);
119         return currentLanguage;
120     }
121 
122     /** {@inheritDoc} */
123     @Override
getDeviceModel()124     public String getDeviceModel() {
125         openAboutMenu();
126         UiObject2 object = getMenu(getUiElementFromConfig(AutomotiveConfigConstants.DEVICE_MODEL));
127         getSpectatioUiUtil()
128                 .validateUiObject(
129                         object, String.format("Unable to find UI Element for device model"));
130         String modelName = getSummeryText(object);
131         return modelName;
132     }
133 
134     /** {@inheritDoc} */
135     @Override
getAndroidVersion()136     public String getAndroidVersion() {
137         openAboutMenu();
138         UiObject2 object =
139                 getMenu(getUiElementFromConfig(AutomotiveConfigConstants.ANDROID_VERSION));
140         getSpectatioUiUtil()
141                 .validateUiObject(
142                         object, String.format("Unable to find UI Element for current language"));
143         String androidVersion = getSummeryText(object);
144         return androidVersion;
145     }
146 
147     /** {@inheritDoc} */
148     @Override
getAndroidSecurityPatchLevel()149     public Date getAndroidSecurityPatchLevel() {
150         openAboutMenu();
151         UiObject2 object =
152                 getMenu(
153                         getUiElementFromConfig(
154                                 AutomotiveConfigConstants.ANDROID_SECURITY_PATCH_LEVEL));
155         getSpectatioUiUtil()
156                 .validateUiObject(
157                         object,
158                         String.format(
159                                 "Unable to find UI Element for android security patch level"));
160         String androidSecurityPatchLevel = getSummeryText(object);
161         Date patchDate = parseDate(androidSecurityPatchLevel, "MMMM dd, yyyy");
162         if (patchDate == null) {
163             patchDate = parseDate(androidSecurityPatchLevel, "dd MMMM yyyy");
164         }
165         if (patchDate == null) {
166             throw new RuntimeException("Cannot find date from UI");
167         }
168         return formatDate(patchDate, "MMMM dd, yyyy"); // return locale independent date
169     }
170 
formatDate(Date date, String format)171     private Date formatDate(Date date, String format) {
172         SimpleDateFormat dateFormatter = new SimpleDateFormat(format);
173         String dateString = dateFormatter.format(date);
174         String[] arr = dateString.split(" ");
175         int year = Integer.valueOf(arr[2]);
176         int month = Month.valueOf(arr[0].toUpperCase()).getValue() - 1;
177         int day = Integer.valueOf(arr[1].substring(0, arr[1].length() - 1));
178         return new Date(year, month, day);
179     }
180 
parseDate(String date, String format)181     private Date parseDate(String date, String format) {
182         Date parsedDate = null;
183         try {
184             SimpleDateFormat dateFormatter = new SimpleDateFormat(format);
185             parsedDate = dateFormatter.parse(date);
186         } catch (Exception e) {
187             // do nothing
188         }
189         return parsedDate;
190     }
191 
192     /** {@inheritDoc} */
193     @Override
getKernelVersion()194     public String getKernelVersion() {
195         openAboutMenu();
196         UiObject2 object =
197                 getMenu(getUiElementFromConfig(AutomotiveConfigConstants.KERNEL_VERSION));
198         getSpectatioUiUtil()
199                 .validateUiObject(
200                         object, String.format("Unable to find UI Element for kernel version"));
201         String kernelVersion = getSummeryText(object);
202         return kernelVersion;
203     }
204 
205     /** {@inheritDoc} */
206     @Override
getBuildNumber()207     public String getBuildNumber() {
208         openAboutMenu();
209         UiObject2 object = getMenu(getUiElementFromConfig(AutomotiveConfigConstants.BUILD_NUMBER));
210         getSpectatioUiUtil()
211                 .validateUiObject(
212                         object, String.format("Unable to find UI Element for build number"));
213         String buildNumber = getSummeryText(object);
214         return buildNumber;
215     }
216 
217     /** {@inheritDoc} */
218     @Override
resetNetwork()219     public void resetNetwork() {
220         openResetOptionsMenu();
221         BySelector resetNetworkSelector =
222                 By.clickable(true)
223                         .hasDescendant(
224                                 getUiElementFromConfig(AutomotiveConfigConstants.RESET_NETWORK));
225         UiObject2 resetNetworkMenu = getMenu(resetNetworkSelector);
226         getSpectatioUiUtil()
227                 .validateUiObject(resetNetworkMenu, AutomotiveConfigConstants.RESET_NETWORK);
228         getSpectatioUiUtil().clickAndWait(resetNetworkMenu);
229         BySelector resetSettingsSelector =
230                 getUiElementFromConfig(AutomotiveConfigConstants.RESET_SETTINGS);
231 
232         UiObject2 resetSettingsButton1 = getMenu(resetSettingsSelector);
233         getSpectatioUiUtil()
234                 .validateUiObject(resetSettingsButton1, AutomotiveConfigConstants.RESET_SETTINGS);
235         getSpectatioUiUtil().clickAndWait(resetSettingsButton1);
236 
237         UiObject2 resetSettingsButton2 =
238                 getMenu(getUiElementFromConfig(AutomotiveConfigConstants.RESET_SETTINGS));
239         getSpectatioUiUtil()
240                 .validateUiObject(resetSettingsButton2, AutomotiveConfigConstants.RESET_SETTINGS);
241         getSpectatioUiUtil().clickAndWait(resetSettingsButton2);
242     }
243 
244     /** {@inheritDoc} */
245     @Override
resetAppPreferences()246     public void resetAppPreferences() {
247         openResetOptionsMenu();
248         BySelector selector =
249                 By.clickable(true)
250                         .hasDescendant(
251                                 getUiElementFromConfig(
252                                         AutomotiveConfigConstants.RESET_APP_PREFERENCES));
253         UiObject2 object = getMenu(selector);
254         getSpectatioUiUtil()
255                 .validateUiObject(object, AutomotiveConfigConstants.RESET_APP_PREFERENCES);
256         getSpectatioUiUtil().clickAndWait(object);
257         BySelector reset_apps_selector =
258                 getUiElementFromConfig(AutomotiveConfigConstants.RESET_APPS);
259 
260         UiObject2 reset_apps_button = getMenu(reset_apps_selector);
261         getSpectatioUiUtil()
262                 .validateUiObject(reset_apps_button, AutomotiveConfigConstants.RESET_APPS);
263         getSpectatioUiUtil().clickAndWait(reset_apps_button);
264     }
265 
266     /** {@inheritDoc} */
267     @Override
openLanguagesInputMenu()268     public void openLanguagesInputMenu() {
269         UiObject2 languagesInputMenu =
270                 getMenu(getUiElementFromConfig(AutomotiveConfigConstants.LANGUAGES_AND_INPUT_MENU));
271         getSpectatioUiUtil()
272                 .validateUiObject(
273                         languagesInputMenu,
274                         String.format("Unable to find UI Element for language input menu"));
275         getSpectatioUiUtil().clickAndWait(languagesInputMenu);
276     }
277 
getSummeryText(UiObject2 object)278     private String getSummeryText(UiObject2 object) {
279         UiObject2 parent = object.getParent();
280         if (parent.getChildren().size() < 2) {
281             BySelector swipeSelector =
282                     getUiElementFromConfig(
283                             AutomotiveConfigConstants.SYSTEM_SETTINGS_SCROLL_ELEMENT);
284             UiObject2 swipeObject = getSpectatioUiUtil().findUiObject(swipeSelector);
285             getSpectatioUiUtil()
286                     .validateUiObject(
287                             swipeObject, AutomotiveConfigConstants.SYSTEM_SETTINGS_SCROLL_ELEMENT);
288             getSpectatioUiUtil().swipeUp(swipeObject);
289         }
290         return object.getParent().getChildren().get(1).getText();
291     }
292 
openResetOptionsMenu()293     private void openResetOptionsMenu() {
294         UiObject2 resetOptionMenu =
295                 getMenu(getUiElementFromConfig(AutomotiveConfigConstants.RESET_OPTIONS_MENU));
296         getSpectatioUiUtil()
297                 .validateUiObject(
298                         resetOptionMenu, String.format("Unable to find UI Element for reset menu"));
299         getSpectatioUiUtil().clickAndWait(resetOptionMenu);
300     }
301 
openAboutMenu()302     private void openAboutMenu() {
303         getSpectatioUiUtil().wait1Second();
304         UiObject2 aboutMenu = getMenu(getUiElementFromConfig(AutomotiveConfigConstants.ABOUT_MENU));
305         getSpectatioUiUtil()
306                 .validateUiObject(
307                         aboutMenu, String.format("Unable to find UI Element for about menu"));
308         getSpectatioUiUtil().clickAndWait(aboutMenu);
309     }
310 
311     /** {@inheritDoc} */
312     @Override
openViewAll()313     public void openViewAll() {
314         getSpectatioUiUtil().wait1Second();
315         UiObject2 viewAll =
316                 getMenu(
317                         getUiElementFromConfig(
318                                 AutomotiveConfigConstants.LOCATION_SETTINGS_VIEW_ALL));
319         getSpectatioUiUtil()
320                 .validateUiObject(viewAll, String.format("Unable to find UI Element for view all"));
321         getSpectatioUiUtil().clickAndWait(viewAll);
322     }
323 
openLanguageMenu()324     private void openLanguageMenu() {
325         UiObject2 languageMenu =
326                 getBtnByText(
327                         AutomotiveConfigConstants.LANGUAGES_MENU,
328                         AutomotiveConfigConstants.LANGUAGES_MENU_IN_SELECTED_LANGUAGE);
329         getSpectatioUiUtil()
330                 .validateUiObject(
331                         languageMenu, String.format("Unable to find UI Element for language menu"));
332         getSpectatioUiUtil().clickAndWait(languageMenu);
333     }
334 
getBtnByText(String... texts)335     private UiObject2 getBtnByText(String... texts) {
336         for (String text : texts) {
337             BySelector btnSelector = By.text(text);
338             UiObject2 btn = getSpectatioUiUtil().findUiObject(btnSelector);
339             if (btn != null) {
340                 return btn;
341             }
342         }
343         throw new RuntimeException("Cannot find button");
344     }
345 
346     /** {@inheritDoc} */
347     @Override
openStorageMenu()348     public void openStorageMenu() {
349         UiObject2 aboutMenu =
350                 getMenu(
351                         getUiElementFromConfig(
352                                 AutomotiveConfigConstants.STORAGE_SYSTEM_SUB_SETTINGS));
353         getSpectatioUiUtil()
354                 .validateUiObject(
355                         aboutMenu, String.format("Unable to find UI Element for Storage menu"));
356         getSpectatioUiUtil().clickAndWait(aboutMenu);
357         getSpectatioUiUtil().wait5Seconds();
358     }
359 
360     /** {@inheritDoc} */
361     @Override
verifyUsageinGB(String option)362     public boolean verifyUsageinGB(String option) {
363         boolean isUsageinGB = false;
364         List<UiObject2> scrollElements =
365                 getSpectatioUiUtil()
366                         .findUiObjects(
367                                 getUiElementFromConfig(
368                                         AutomotiveConfigConstants
369                                                 .SETTINGS_UI_SUB_SETTING_SCROLL_ELEMENT));
370         for (UiObject2 element : scrollElements) {
371             UiObject2 foundObject =
372                     getSpectatioUiUtil()
373                             .findUiObjectInGivenElement(element, getUiElementFromConfig(option));
374             if (foundObject != null) {
375                 // there may be multiple matches the 'option' config on screen, such as 'System'
376                 String targetText = getSummeryText(foundObject);
377                 if (targetText != null && targetText.contains("GB")) {
378                     isUsageinGB = true;
379                 }
380             }
381         }
382         return isUsageinGB;
383     }
384 
getMenu(BySelector selector)385     private UiObject2 getMenu(BySelector selector) {
386         UiObject2 object =
387                 mScrollUtility.scrollAndFindUiObject(
388                         mScrollAction,
389                         mScrollDirection,
390                         mForwardButtonSelector,
391                         mBackwardButtonSelector,
392                         mScrollableElementSelector,
393                         selector,
394                         String.format("Scroll on system setting to find %s", selector));
395 
396         getSpectatioUiUtil()
397                 .validateUiObject(
398                         object,
399                         String.format("Unable to find UI Element %s.", selector.toString()));
400         return object;
401     }
402 
403     /** {@inheritDoc} */
404     @Override
hasDeveloperOptions()405     public boolean hasDeveloperOptions() throws MissingUiElementException {
406         getSpectatioUiUtil().wait1Second();
407         boolean hasDeveloperOptions =
408                 getSpectatioUiUtil()
409                         .scrollAndCheckIfUiElementExist(
410                                 mScrollableElementSelector, "Developer options", true);
411         return hasDeveloperOptions;
412     }
413 
414     /** {@inheritDoc} */
415     @Override
openDeveloperOptions()416     public void openDeveloperOptions() {
417         getSpectatioUiUtil().wait1Second();
418         UiObject2 developerOptions =
419                 getMenu(getUiElementFromConfig(AutomotiveConfigConstants.DEVELOPER_OPTIONS));
420         getSpectatioUiUtil()
421                 .validateUiObject(
422                         developerOptions,
423                         String.format("Unable to find UI Element for Developer Options"));
424         getSpectatioUiUtil().clickAndWait(developerOptions);
425     }
426 
427     /** {@inheritDoc} */
428     @Override
enterDeveloperMode()429     public void enterDeveloperMode() {
430         openAboutMenu();
431         getSpectatioUiUtil().wait1Second();
432         UiObject2 buildNumber =
433                 getMenu(getUiElementFromConfig(AutomotiveConfigConstants.BUILD_NUMBER));
434         getSpectatioUiUtil()
435                 .validateUiObject(
436                         buildNumber, String.format("Unable to find UI Element for build number"));
437         for (int i = 0; i <= 6; i++) {
438             getSpectatioUiUtil().clickAndWait(buildNumber);
439             getSpectatioUiUtil().wait1Second();
440         }
441         pressSettingsBackNavIcon();
442         getSpectatioUiUtil().waitForIdle();
443     }
444 
pressSettingsBackNavIcon()445     private void pressSettingsBackNavIcon() {
446         UiObject2 navIcon =
447                 getSpectatioUiUtil()
448                         .findUiObject(
449                                 getUiElementFromConfig(
450                                         AutomotiveConfigConstants.SETTINGS_BACK_NAV_ICON));
451         getSpectatioUiUtil()
452                 .validateUiObject(
453                         navIcon, "Could not press back; unable to find settings back nav icon");
454         getSpectatioUiUtil().clickAndWait(navIcon);
455     }
456 }
457