AdevintaSpain / AdevintaSpain/Barista

Change android time settings

Open
#324 1 comment 3 reactions 0 assignees View on GitHub
Dominant language
Kotlin
Stars
1.7k
Forks
119
PR merge metrics
No merged PRs in 30d

Description

Hi,

I've implemented a class to change the device time using UiAutomator. Likely to be useful for scheduled notification testing.

It relies only on UiAutomator. The idea is to have a simple way to test notifications e2e in the end with other POM/like helpers for notifications for instance. I like the idea of making it as low level as possible. Preferably without espresso dependency. Perhaps it would make sense to integrate it in here though. It loosely follows the page object model framework.

I am open to any idea (or ticket rejection).

Here is the class at the moment.

```java
package org.pnplab.flux.notifications;

import android.content.Context;
import android.content.Intent;
import android.os.RemoteException;
import android.util.Log;

import androidx.test.core.app.ApplicationProvider;
import androidx.test.uiautomator.By;
import androidx.test.uiautomator.UiCollection;
import androidx.test.uiautomator.UiDevice;
import androidx.test.uiautomator.UiObject;
import androidx.test.uiautomator.UiObject2;
import androidx.test.uiautomator.UiObjectNotFoundException;
import androidx.test.uiautomator.UiScrollable;
import androidx.test.uiautomator.UiSelector;
import androidx.test.uiautomator.Until;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Period;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

// Some helper class to set the time for notifications using UIAutomator, only works with english
// android and only tested w/ android v28.
//
// For DateTimeFormatter doc, used at multiple time in this class, see
// `https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html`.
// @note Have found this lib that provides helper function to handle datepicker and timepicker in
// android after writing these tests `https://github.com/AdevintaSpain/Barista`.
// @todo make that class locale agnostic and inject it class into Barista framework :-)
public class DateTimeSettingsPOM {

private final UiDevice device;
private final long timeout;

public DateTimeSettingsPOM(UiDevice device, long timeout) {
this.device = device;
this.timeout = timeout;
}

/**
* Open the android Settings app at the date & time panel.
*/
public void openSettings() {
// Start from the home screen
device.pressHome();

// Wait for launcher
final String launcherPackage = device.getLauncherPackageName();
assert(launcherPackage != null);
device.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)), timeout);

// Get context (of Home app ?).
Context context = ApplicationProvider.getApplicationContext();

// Launch Date & Time settings.
final Intent intent = new Intent(android.provider.Settings.ACTION_DATE_SETTINGS);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}

/**
* Enable manual time settings.
*
* @pre User must be in settings (see `#openSettings`).
* @post User is in settings.
*
* @throws UiObjectNotFoundException
*/
public void enableManualDateTime() throws UiObjectNotFoundException {
// Toggle automatic date & time off.
UiScrollable dateTimeSettingList = new UiScrollable(new UiSelector().className("android.support.v7.widget.RecyclerView"));
UiObject automaticDateTimeOption = dateTimeSettingList.getChildByText(new UiSelector().className("android.widget.LinearLayout"), "Automatic date & time");
UiObject automaticDateTimeSwitch = automaticDateTimeOption.getChild(new UiSelector().className("android.widget.Switch"));
if (automaticDateTimeSwitch.isChecked()) {
automaticDateTimeSwitch.click();
}
}

/**
* Set the time automatically based on NTP server sync. Disable manual time settings.
*
* @pre User must be in settings (see `#openSettings`).
* @post User is in settings.
*
* @throws UiObjectNotFoundException
*/
public void disableManualDateTime() throws UiObjectNotFoundException {
// Turn automatic date & time on.
UiScrollable dateTimeSettingList = new UiScrollable(new UiSelector().className("android.support.v7.widget.RecyclerView"));
UiObject automaticDateTimeOption = dateTimeSettingList.getChildByText(new UiSelector().className("android.widget.LinearLayout"), "Automatic date & time");
UiObject automaticDateTimeSwitch = automaticDateTimeOption.getChild(new UiSelector().className("android.widget.Switch"));
if (!automaticDateTimeSwitch.isChecked()) {
automaticDateTimeSwitch.click();
}
}

/**
* Change the phone's date and time settings.
*
* @param datetimeStr "yyyy-MM-dd HH:mm" format. seconds throw exception.
*
* @pre User must be in settings (see `#openSettings`).
* @post User is in settings.
*/
public void setIsoDateTime(String datetimeStr) throws UiObjectNotFoundException {
// Split datetime into date and time str.
LocalDateTime dateTime = LocalDateTime.parse(datetimeStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
LocalDate localDate = dateTime.toLocalDate();
LocalTime localTime = dateTime.toLocalTime();
String localDateStr = localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
String localTimeStr = localTime.format(DateTimeFormatter.ofPattern("HH:mm"));

// Apply date and time setting changes.
setIsoDate(localDateStr);
setIsoTime(localTimeStr);
}

/**
* Set the current date.
*
* @param dateStr "yyyy-MM-dd" format
*
* @pre User must be in settings (see `#openSettings`).
* @pre Automatic date time must be disabled (see `#enableManualDateTime`).
* @post User is in settings.
*
* @throws UiObjectNotFoundException
*/
public void setIsoDate(String dateStr) throws UiObjectNotFoundException {
// Open Set date panel.
UiScrollable dateTimeSettingList = new UiScrollable(new UiSelector().className("android.support.v7.widget.RecyclerView"));
UiObject setDate = dateTimeSettingList.getChildByText(new UiSelector().className("android.widget.TextView"), "Set date");
setDate.click();

// Get current day, month and year.
UiObject yearItem = new UiObject(new UiSelector().resourceId("android:id/date_picker_header_year"));
String year = yearItem.getText();
UiObject dateWithoutYearItem = new UiObject(new UiSelector().resourceId("android:id/date_picker_header_date"));
String dateWithoutYear = dateWithoutYearItem.getText(); // ie. `Wed, Oct 9`

// Parse it as a date object.
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("E, MMM d yyyy");
dateTimeFormatter = dateTimeFormatter.withLocale(Locale.US);
// Line commented out because doesn't parse with dual locale for some reason...
// dateTimeFormatter = dateTimeFormatter.withLocale(Locale.FRENCH);
LocalDate outputDate = LocalDate.parse(dateWithoutYear + " " + year, dateTimeFormatter);

// Set target date.
LocalDate targetDate = LocalDate.parse(dateStr);

// Get date diff.
Period period = Period.between(outputDate, targetDate);
int yearDiff = period.getYears();
int monthDiff = period.getMonths() + (yearDiff * 12);
period = period.minusMonths(monthDiff);
int dayDiff = period.getDays();

// Log
Log.i("TAG", dateStr + " " + targetDate.toString() + " " + monthDiff + " " + targetDate.getDayOfMonth());

// Cycle through months.
if (monthDiff == 0) {
// ...nothing to do. Currently on the right month.
}
// Go backward until targeted month is selected.
else if (monthDiff < 0) {
for (int i=monthDiff; i<0; ++i) {
UiObject previousMonthButtonItem = new UiObject(new UiSelector().resourceId("android:id/prev"));
previousMonthButtonItem.click();
}
}
// Go forward until targeted month is selected.
else if (monthDiff > 0) {
for (int i=0; i

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.