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 static junit.framework.Assert.assertTrue;
20 
21 import android.app.Instrumentation;
22 import android.content.ContentResolver;
23 import android.support.test.uiautomator.By;
24 import android.support.test.uiautomator.BySelector;
25 import android.support.test.uiautomator.UiObject;
26 import android.support.test.uiautomator.UiObject2;
27 import android.support.test.uiautomator.UiScrollable;
28 import android.support.test.uiautomator.UiSelector;
29 import android.text.format.DateFormat;
30 import java.time.format.TextStyle;
31 import java.time.LocalDate;
32 import java.time.Month;
33 import java.util.List;
34 import java.util.Locale;
35 
36 public class SettingsDateTimeHelperImpl extends AbstractAutoStandardAppHelper
37         implements IAutoDateTimeSettingsHelper {
38     private static final Locale LOCALE = Locale.ENGLISH;
39     private static final TextStyle TEXT_STYLE = TextStyle.SHORT;
40 
SettingsDateTimeHelperImpl(Instrumentation instr)41     public SettingsDateTimeHelperImpl(Instrumentation instr) {
42         super(instr);
43     }
44 
45     /** {@inheritDoc} */
46     @Override
getPackage()47     public String getPackage() {
48         return getApplicationConfig(AutoConfigConstants.SETTINGS_PACKAGE);
49     }
50 
51     /** {@inheritDoc} */
52     @Override
setDate(LocalDate date)53     public void setDate(LocalDate date) {
54         UiObject2 autoDateTimeSwitchWidget = getAutoDateTimeSwitchWidget();
55         UiObject2 autoDateTimeMenu =
56                 getMenu(
57                         getResourceFromConfig(
58                                 AutoConfigConstants.SETTINGS,
59                                 AutoConfigConstants.DATE_AND_TIME_SETTINGS,
60                                 AutoConfigConstants.SET_TIME_AUTOMATICALLY));
61         if (autoDateTimeSwitchWidget.isChecked()) {
62             clickAndWaitForWindowUpdate(
63                     getApplicationConfig(AutoConfigConstants.SETTINGS_PACKAGE), autoDateTimeMenu);
64         }
65         UiObject2 setDateMenu = getSetDateMenu();
66         assertTrue("set date menu is not clickable", setDateMenu.isEnabled()); // from UI
67         clickAndWaitForWindowUpdate(
68                 getApplicationConfig(AutoConfigConstants.SETTINGS_PACKAGE), setDateMenu);
69         assertTrue(
70                 "automatic date & time is not switched off",
71                 !isAutomaticOn("auto_time")); // from API
72         int year = date.getYear();
73         Month month = date.getMonth();
74         int day = date.getDayOfMonth();
75         String month_string = month.getDisplayName(TEXT_STYLE, LOCALE);
76         String day_string = "";
77         if (day < 10) {
78             day_string = "0" + String.valueOf(day);
79         } else {
80             day_string = "" + String.valueOf(day);
81         }
82         String year_string = "" + year;
83         setCalendar(1, day_string);
84         setCalendar(0, month_string);
85         setCalendar(2, year_string);
86         pressBack();
87     }
88 
setCalendar(int index, String s)89     private void setCalendar(int index, String s) {
90         UiSelector selector =
91                 new UiSelector()
92                         .className(
93                                 getResourceValue(
94                                         AutoConfigConstants.SETTINGS,
95                                         AutoConfigConstants.DATE_AND_TIME_SETTINGS,
96                                         AutoConfigConstants.NUMBER_PICKER_WIDGET))
97                         .index(index);
98         boolean scrollForwards = true;
99         if (index == 2) {
100             UiSelector yearSelector =
101                     selector.childSelector(
102                             new UiSelector()
103                                     .className(
104                                             getResourceValue(
105                                                     AutoConfigConstants.SETTINGS,
106                                                     AutoConfigConstants.DATE_AND_TIME_SETTINGS,
107                                                     AutoConfigConstants.EDIT_TEXT_WIDGET)));
108             String curYear = "";
109             try {
110                 curYear = new UiObject(yearSelector).getText();
111             } catch (Exception e) {
112                 throw new RuntimeException(e);
113             }
114             if (Integer.valueOf(curYear) > Integer.valueOf(s)) scrollForwards = false;
115         }
116         scrollToObjectInPicker(index, s, scrollForwards);
117     }
118 
119     /** {@inheritDoc} */
120     @Override
getDate()121     public LocalDate getDate() {
122         UiObject2 obj = getSetDateMenu();
123         if (obj == null) {
124             throw new RuntimeException("Unable to find set date menu.");
125         }
126         String uiDate = getMenuSummaryText(obj);
127         String[] arr = uiDate.split(" ");
128         if (arr.length != 3) {
129             throw new RuntimeException("Cannot find date from UI");
130         }
131         int year = Integer.valueOf(arr[2]);
132         int month = Month.valueOf(arr[0].toUpperCase()).getValue();
133         int day = Integer.valueOf(arr[1].substring(0, arr[1].length() - 1));
134         return LocalDate.of(year, month, day);
135     }
136 
137     /** {@inheritDoc} */
138     @Override
setTimeInTwelveHourFormat(int hour, int minute, boolean am)139     public void setTimeInTwelveHourFormat(int hour, int minute, boolean am) {
140         // check Automatic date & time switch is turned off
141         UiObject2 autoDateTimeSwitchWidget = getAutoDateTimeSwitchWidget();
142         UiObject2 autoDateTimeMenu =
143                 getMenu(
144                         getResourceFromConfig(
145                                 AutoConfigConstants.SETTINGS,
146                                 AutoConfigConstants.DATE_AND_TIME_SETTINGS,
147                                 AutoConfigConstants.SET_TIME_AUTOMATICALLY));
148         if (autoDateTimeSwitchWidget.isChecked()) {
149             clickAndWaitForWindowUpdate(
150                     getApplicationConfig(AutoConfigConstants.SETTINGS_PACKAGE), autoDateTimeMenu);
151         }
152         // check 24-hour format switch is turned off
153         if (isTwentyFourHourFormatEnabled()) {
154             toggleTwentyFourHourFormatSwitch();
155         }
156 
157         UiObject2 setTimeMenu = getSetTimeMenu();
158         assertTrue("set time menu is not clickable", setTimeMenu.isEnabled()); // from UI
159         clickAndWaitForWindowUpdate(
160                 getApplicationConfig(AutoConfigConstants.SETTINGS_PACKAGE), setTimeMenu);
161         assertTrue(
162                 "automatic date & time is not switched off",
163                 !isAutomaticOn("auto_time")); // from API
164         String minute_string = "" + minute;
165         String am_pm = "";
166         am_pm = am ? "AM" : "PM";
167         if (minute < 10) {
168             minute_string = "0" + minute;
169         }
170         setTime(2, minute_string);
171         setTime(0, String.valueOf(hour));
172         setTime(1, am_pm);
173         pressBack();
174     }
175 
176     /** {@inheritDoc} */
177     @Override
setTimeInTwentyFourHourFormat(int hour, int minute)178     public void setTimeInTwentyFourHourFormat(int hour, int minute) {
179         // check Automatic date & time switch is turned off
180         UiObject2 autoDateTimeSwitchWidget = getAutoDateTimeSwitchWidget();
181         UiObject2 autoDateTimeMenu =
182                 getMenu(
183                         getResourceFromConfig(
184                                 AutoConfigConstants.SETTINGS,
185                                 AutoConfigConstants.DATE_AND_TIME_SETTINGS,
186                                 AutoConfigConstants.SET_TIME_AUTOMATICALLY));
187         if (autoDateTimeSwitchWidget.isChecked()) {
188             clickAndWaitForWindowUpdate(
189                     getApplicationConfig(AutoConfigConstants.SETTINGS_PACKAGE), autoDateTimeMenu);
190         }
191         // check 24-hour format switch is turned on
192         if (!isTwentyFourHourFormatEnabled()) {
193             toggleTwentyFourHourFormatSwitch();
194         }
195 
196         UiObject2 setTimeMenu = getSetTimeMenu();
197         assertTrue("set time menu is not clickable", setTimeMenu.isEnabled()); // from UI
198         clickAndWaitForWindowUpdate(
199                 getApplicationConfig(AutoConfigConstants.SETTINGS_PACKAGE), setTimeMenu);
200         assertTrue(
201                 "automatic date & time is not switched off",
202                 !isAutomaticOn("auto_time")); // from API
203         String minute_string = "" + minute;
204         if (minute < 10) {
205             minute_string = "0" + minute;
206         }
207         String hour_string = "" + hour;
208         if (hour < 10) {
209             hour_string = "0" + hour;
210         }
211         setTime(2, minute_string);
212         setTime(0, hour_string);
213         pressBack();
214     }
215 
setTime(int index, String s)216     private void setTime(int index, String s) {
217         UiSelector selector =
218                 new UiSelector()
219                         .className(
220                                 getResourceValue(
221                                         AutoConfigConstants.SETTINGS,
222                                         AutoConfigConstants.DATE_AND_TIME_SETTINGS,
223                                         AutoConfigConstants.NUMBER_PICKER_WIDGET))
224                         .index(index);
225         boolean scrollForwards = true;
226         String curAM_PM;
227         if (index == 1) {
228             UiSelector am_pm_Selector =
229                     selector.childSelector(
230                             new UiSelector()
231                                     .className(
232                                             getResourceValue(
233                                                     AutoConfigConstants.SETTINGS,
234                                                     AutoConfigConstants.DATE_AND_TIME_SETTINGS,
235                                                     AutoConfigConstants.EDIT_TEXT_WIDGET)));
236             try {
237                 curAM_PM = new UiObject(am_pm_Selector).getText();
238             } catch (Exception e) {
239                 throw new RuntimeException(e);
240             }
241             if (curAM_PM.equals("PM")) scrollForwards = false;
242         }
243         scrollToObjectInPicker(index, s, scrollForwards);
244     }
245 
scrollToObjectInPicker(int index, String s, boolean scrollForwards)246     private void scrollToObjectInPicker(int index, String s, boolean scrollForwards) {
247         UiSelector selector =
248                 new UiSelector()
249                         .className(
250                                 getResourceValue(
251                                         AutoConfigConstants.SETTINGS,
252                                         AutoConfigConstants.DATE_AND_TIME_SETTINGS,
253                                         AutoConfigConstants.NUMBER_PICKER_WIDGET))
254                         .index(index);
255         UiScrollable scrollable = new UiScrollable(selector);
256         scrollable.setAsVerticalList();
257         UiObject2 obj =
258                 findUiObject(
259                         By.text(s)
260                                 .clazz(
261                                         getResourceValue(
262                                                 AutoConfigConstants.SETTINGS,
263                                                 AutoConfigConstants.DATE_AND_TIME_SETTINGS,
264                                                 AutoConfigConstants.EDIT_TEXT_WIDGET)));
265         while (obj == null) {
266             try {
267                 if (scrollForwards) {
268                     scrollable.scrollForward();
269                 } else {
270                     scrollable.scrollBackward();
271                 }
272             } catch (Exception e) {
273                 throw new RuntimeException(e);
274             }
275             obj =
276                     findUiObject(
277                             By.text(s)
278                                     .clazz(
279                                             getResourceValue(
280                                                     AutoConfigConstants.SETTINGS,
281                                                     AutoConfigConstants.DATE_AND_TIME_SETTINGS,
282                                                     AutoConfigConstants.EDIT_TEXT_WIDGET)));
283         }
284         if (obj == null) throw new RuntimeException("cannot find value in the picker");
285     }
286 
287     /** {@inheritDoc} */
288     @Override
getTime()289     public String getTime() {
290         UiObject2 obj = getSetTimeMenu();
291         if (obj == null) {
292             throw new RuntimeException("Unable to find time menu.");
293         }
294         String uiTime = getMenuSummaryText(obj);
295         return uiTime;
296     }
297 
298     /** {@inheritDoc} */
299     @Override
setTimeZone(String timezone)300     public void setTimeZone(String timezone) {
301         UiObject2 autoTimeZoneSwitchWidget = getAutoTimeZoneSwitchWidget();
302         UiObject2 autoTimeZoneMenu =
303                 getMenu(
304                         getResourceFromConfig(
305                                 AutoConfigConstants.SETTINGS,
306                                 AutoConfigConstants.DATE_AND_TIME_SETTINGS,
307                                 AutoConfigConstants.SET_TIME_ZONE_AUTOMATICALLY));
308         if (getAutoTimeZoneSwitchWidget().isChecked()) {
309             clickAndWaitForWindowUpdate(
310                     getApplicationConfig(AutoConfigConstants.SETTINGS_PACKAGE), autoTimeZoneMenu);
311         }
312         UiObject2 selectTimeZoneMenu = getSelectTimeZoneMenu();
313         assertTrue(
314                 "select time zone menu is not clickable",
315                 selectTimeZoneMenu.isEnabled()); // from UI
316         assertTrue(
317                 "automatic time zone is not switched off",
318                 !isAutomaticOn("auto_time_zone")); // from API
319         clickAndWaitForWindowUpdate(
320                 getApplicationConfig(AutoConfigConstants.SETTINGS_PACKAGE), selectTimeZoneMenu);
321         BySelector selector = By.clickable(true).hasDescendant(By.text(timezone));
322         UiObject2 object = scrollAndFindUiObject(selector, getScrollScreenIndex());
323         if (object == null) {
324             throw new RuntimeException(String.format("Unable to find timezone %s", timezone));
325         }
326         clickAndWaitForWindowUpdate(
327                 getApplicationConfig(AutoConfigConstants.SETTINGS_PACKAGE), object);
328     }
329 
330     /** {@inheritDoc} */
331     @Override
toggleTwentyFourHourFormatSwitch()332     public boolean toggleTwentyFourHourFormatSwitch() {
333         UiObject2 twentyFourHourFormatSwitch = getUseTwentyFourHourFormatSwitchWidget();
334         if (twentyFourHourFormatSwitch.isChecked()) {
335             assertTrue(
336                     "System time format is different from UI format",
337                     DateFormat.is24HourFormat(mInstrumentation.getContext()));
338         } else {
339             assertTrue(
340                     "System time format is different from UI format",
341                     !DateFormat.is24HourFormat(mInstrumentation.getContext()));
342         }
343         clickAndWaitForWindowUpdate(
344                 getApplicationConfig(AutoConfigConstants.SETTINGS_PACKAGE),
345                 twentyFourHourFormatSwitch);
346         return true;
347     }
348 
349     /** {@inheritDoc} */
350     @Override
getTimeZone()351     public String getTimeZone() {
352         UiObject2 obj = getSelectTimeZoneMenu();
353         if (obj == null) {
354             throw new RuntimeException("Unable to find timezone menu.");
355         }
356         String timeZone = getMenuSummaryText(obj);
357         return timeZone;
358     }
359 
360     /** {@inheritDoc} */
361     @Override
isTwentyFourHourFormatEnabled()362     public boolean isTwentyFourHourFormatEnabled() {
363         UiObject2 twentyFourHourFormatSwitchWidget = getUseTwentyFourHourFormatSwitchWidget();
364         return twentyFourHourFormatSwitchWidget.isChecked();
365     }
366 
getSetDateMenu()367     private UiObject2 getSetDateMenu() {
368         return getMenu(
369                 getResourceFromConfig(
370                         AutoConfigConstants.SETTINGS,
371                         AutoConfigConstants.DATE_AND_TIME_SETTINGS,
372                         AutoConfigConstants.SET_DATE));
373     }
374 
getSetTimeMenu()375     private UiObject2 getSetTimeMenu() {
376         return getMenu(
377                 getResourceFromConfig(
378                         AutoConfigConstants.SETTINGS,
379                         AutoConfigConstants.DATE_AND_TIME_SETTINGS,
380                         AutoConfigConstants.SET_TIME));
381     }
382 
getTwentyFourFormatMenu()383     private UiObject2 getTwentyFourFormatMenu() {
384         return getMenu(
385                 getResourceFromConfig(
386                         AutoConfigConstants.SETTINGS,
387                         AutoConfigConstants.DATE_AND_TIME_SETTINGS,
388                         AutoConfigConstants.USE_24_HOUR_FORMAT));
389     }
390 
getSelectTimeZoneMenu()391     private UiObject2 getSelectTimeZoneMenu() {
392         return getMenu(
393                 getResourceFromConfig(
394                         AutoConfigConstants.SETTINGS,
395                         AutoConfigConstants.DATE_AND_TIME_SETTINGS,
396                         AutoConfigConstants.SELECT_TIME_ZONE));
397     }
398 
getMenu(BySelector bySelector)399     private UiObject2 getMenu(BySelector bySelector) {
400         BySelector selector = By.clickable(true).hasDescendant(bySelector);
401         return scrollAndFindUiObject(selector, getScrollScreenIndex());
402     }
403 
getAutoDateTimeSwitchWidget()404     private UiObject2 getAutoDateTimeSwitchWidget() {
405         return getSwitchWidget(
406                 getResourceFromConfig(
407                         AutoConfigConstants.SETTINGS,
408                         AutoConfigConstants.DATE_AND_TIME_SETTINGS,
409                         AutoConfigConstants.SET_TIME_AUTOMATICALLY));
410     }
411 
getAutoTimeZoneSwitchWidget()412     private UiObject2 getAutoTimeZoneSwitchWidget() {
413         return getSwitchWidget(
414                 getResourceFromConfig(
415                         AutoConfigConstants.SETTINGS,
416                         AutoConfigConstants.DATE_AND_TIME_SETTINGS,
417                         AutoConfigConstants.SET_TIME_ZONE_AUTOMATICALLY));
418     }
419 
getUseTwentyFourHourFormatSwitchWidget()420     private UiObject2 getUseTwentyFourHourFormatSwitchWidget() {
421         return getSwitchWidget(
422                 getResourceFromConfig(
423                         AutoConfigConstants.SETTINGS,
424                         AutoConfigConstants.DATE_AND_TIME_SETTINGS,
425                         AutoConfigConstants.USE_24_HOUR_FORMAT));
426     }
427 
getSwitchWidget(BySelector bySelector)428     private UiObject2 getSwitchWidget(BySelector bySelector) {
429         BySelector selector = By.hasDescendant(bySelector);
430         UiObject2 object = scrollAndFindUiObject(selector, getScrollScreenIndex());
431         List<UiObject2> list = object.getParent().getChildren();
432         UiObject2 switchWidget = list.get(1).getChildren().get(0);
433         return switchWidget;
434     }
435 
getScrollScreenIndex()436     private int getScrollScreenIndex() {
437         int scrollScreenIndex = 0;
438         if (hasSplitScreenSettingsUI()) {
439             scrollScreenIndex = 1;
440         }
441         return scrollScreenIndex;
442     }
443 
getMenuSummaryText(UiObject2 obj)444     private String getMenuSummaryText(UiObject2 obj) {
445         return obj.getChildren().get(0).getChildren().get(1).getText();
446     }
447 
isAutomaticOn(String name)448     private boolean isAutomaticOn(String name) {
449         ContentResolver cr = mInstrumentation.getContext().getContentResolver();
450         int status = 0;
451         try {
452             status = android.provider.Settings.Global.getInt(cr, name);
453         } catch (Exception e) {
454             throw new RuntimeException(e);
455         }
456         return status == 1 ? true : false;
457     }
458 }
459