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