From 278b1e8cce48e03876cd42778280995e68d7d5bc Mon Sep 17 00:00:00 2001 From: Syaoran Kuo Date: Tue, 15 Jun 2021 14:25:41 +0800 Subject: [PATCH] Add test case for dark theme scheduler. Bug: 189722519 Test: atest com.android.settings.display.darkmode.DarkThemeScheduleComponentTest Change-Id: I94cbff123af0eaef7834aa636e3b38c6da3f2235 --- .../DarkThemeScheduleComponentTest.java | 145 ++++++++++++++++++ .../android/settings/testutils/AdbUtils.java | 21 +++ .../settings/testutils/CommonUtils.java | 26 ++++ 3 files changed, 192 insertions(+) create mode 100644 tests/componenttests/src/com/android/settings/display/darkmode/DarkThemeScheduleComponentTest.java diff --git a/tests/componenttests/src/com/android/settings/display/darkmode/DarkThemeScheduleComponentTest.java b/tests/componenttests/src/com/android/settings/display/darkmode/DarkThemeScheduleComponentTest.java new file mode 100644 index 00000000000..3822c82509b --- /dev/null +++ b/tests/componenttests/src/com/android/settings/display/darkmode/DarkThemeScheduleComponentTest.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.display.darkmode; + +import static com.google.common.truth.Truth.assertThat; + +import android.app.Instrumentation; +import android.app.TimePickerDialog; +import android.app.UiModeManager; +import android.content.Intent; +import android.content.res.Configuration; +import android.provider.Settings; +import android.util.Log; + +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.test.core.app.ActivityScenario; +import androidx.test.ext.junit.rules.ActivityScenarioRule; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.runner.lifecycle.Stage; + +import com.android.settings.testutils.CommonUtils; +import com.android.settings.testutils.UiUtils; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.time.LocalTime; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class DarkThemeScheduleComponentTest { + private static final int DIALOG_START_TIME = 0; + private static final int DIALOG_END_TIME = 1; + /** The identifier for the positive button. */ + private static final int BUTTON_POSITIVE = -1; + public final String TAG = this.getClass().getName(); + private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation(); + + @Rule + public ActivityScenarioRule rule = + new ActivityScenarioRule<>( + new Intent( + Settings.ACTION_DARK_THEME_SETTINGS).setFlags( + Intent.FLAG_ACTIVITY_NEW_TASK)); + private UiModeManager mUiModeManager; + + @Before + public void setUp() { + mUiModeManager = mInstrumentation.getTargetContext().getSystemService(UiModeManager.class); + if (mUiModeManager.getNightMode() != UiModeManager.MODE_NIGHT_NO) { + mUiModeManager.setNightMode(UiModeManager.MODE_NIGHT_NO); + } + } + + private void test_step_for_custom_time(int startTimeDiff, int endTimeDiff) { + + ActivityScenario scenario = rule.getScenario(); + scenario.onActivity(activity -> { + mUiModeManager.setNightMode(UiModeManager.MODE_NIGHT_CUSTOM); + Fragment f = + ((FragmentActivity) activity).getSupportFragmentManager().getFragments().get(0); + DarkModeSettingsFragment fragment = (DarkModeSettingsFragment) f; + + setCustomTime(fragment, DIALOG_START_TIME, LocalTime.now().plusMinutes(startTimeDiff)); + setCustomTime(fragment, DIALOG_END_TIME, LocalTime.now().plusMinutes(endTimeDiff)); + + // The night mode need to reopen the screen to trigger UI change after mode change. + CommonUtils.reopenScreen(); + }); + + // Recreate the scenario to make sure UI apply new mode. + scenario.recreate(); + scenario.onActivity(activity -> { + Log.d(TAG, "Activity Recreated!"); + UiUtils.waitForActivitiesInStage(2000, Stage.RESUMED); + }); + } + + @Test + public void test_dark_mode_in_custom_time() { + test_step_for_custom_time(-1, 11); + assertThat(checkNightMode(true)).isTrue(); + } + + @Test + public void test_dark_mode_after_custom_time() { + test_step_for_custom_time(-11, -1); + assertThat(checkNightMode(false)).isTrue(); + } + + @Test + public void test_dark_mode_before_custom_time() { + test_step_for_custom_time(2, 20); + assertThat(checkNightMode(false)).isTrue(); + } + + /** + * Sets custom time for night mode. + * + * @param fragment The DarkModeSettingsFragment. + * @param dialogId Dialog id for start time or end time. + * @param time The time to be set. + */ + private void setCustomTime(DarkModeSettingsFragment fragment, int dialogId, LocalTime time) { + Log.d(TAG, "Start to set custom time " + (dialogId == DIALOG_START_TIME ? "StartTime" + : "EndTime") + " to " + time.getHour() + ":" + time.getMinute()); + TimePickerDialog startTimeDialog = (TimePickerDialog) fragment.onCreateDialog(dialogId); + startTimeDialog.updateTime(time.getHour(), time.getMinute()); + startTimeDialog.onClick(startTimeDialog, BUTTON_POSITIVE); + } + + private boolean checkNightMode(boolean isNightMode) { + int mask = (isNightMode ? Configuration.UI_MODE_NIGHT_YES : Configuration.UI_MODE_NIGHT_NO); + int mode = mInstrumentation.getTargetContext().getResources().getConfiguration().uiMode; + return (mode & mask) != 0; + } + + @After + public void tearDown() { + Log.d(TAG, "tearDown."); + if (mUiModeManager.getNightMode() != UiModeManager.MODE_NIGHT_NO) { + mUiModeManager.setNightMode(UiModeManager.MODE_NIGHT_NO); + } + } +} diff --git a/tests/componenttests/src/com/android/settings/testutils/AdbUtils.java b/tests/componenttests/src/com/android/settings/testutils/AdbUtils.java index 08eb47a4a64..d2b46f8b203 100644 --- a/tests/componenttests/src/com/android/settings/testutils/AdbUtils.java +++ b/tests/componenttests/src/com/android/settings/testutils/AdbUtils.java @@ -23,9 +23,11 @@ import android.util.Log; import androidx.test.platform.app.InstrumentationRegistry; import java.io.BufferedReader; +import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.Optional; +import java.util.stream.Collectors; public class AdbUtils { public static boolean checkStringInAdbCommandOutput(String logTag, String command, @@ -59,4 +61,23 @@ public class AdbUtils { return false; } + + public static String shell(String shellCommand) { + String returnValue = ""; + try (ParcelFileDescriptor.AutoCloseInputStream in = + new ParcelFileDescriptor.AutoCloseInputStream( + InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .executeShellCommand(shellCommand))) { + try (BufferedReader br = + new BufferedReader( + new InputStreamReader(in, StandardCharsets.UTF_8))) { + returnValue = br.lines().collect(Collectors.joining()); + } + } catch (IOException e) { + e.printStackTrace(); + } + + return returnValue; + } } diff --git a/tests/componenttests/src/com/android/settings/testutils/CommonUtils.java b/tests/componenttests/src/com/android/settings/testutils/CommonUtils.java index 02a83fcd600..7cc4d2d856f 100644 --- a/tests/componenttests/src/com/android/settings/testutils/CommonUtils.java +++ b/tests/componenttests/src/com/android/settings/testutils/CommonUtils.java @@ -17,8 +17,12 @@ package com.android.settings.testutils; import android.app.Activity; +import android.app.Instrumentation; +import android.content.Context; import android.graphics.Bitmap; import android.os.Environment; +import android.os.PowerManager; +import android.os.SystemClock; import android.util.Log; import android.view.View; @@ -36,6 +40,11 @@ import javax.net.ssl.HttpsURLConnection; public class CommonUtils { private static final String TAG = CommonUtils.class.getSimpleName(); + private static Instrumentation sInstrumentation = + InstrumentationRegistry.getInstrumentation(); + private static PowerManager sPowerManager = + (PowerManager) sInstrumentation.getTargetContext().getSystemService( + Context.POWER_SERVICE); public static void takeScreenshot(Activity activity) { long now = System.currentTimeMillis(); @@ -106,4 +115,21 @@ public class CommonUtils { return InstrumentationRegistry.getInstrumentation().getTargetContext().getResources() .getIdentifier(name, "id", Constants.SETTINGS_PACKAGE_NAME); } + + public static void reopenScreen() { + sPowerManager.goToSleep(SystemClock.uptimeMillis()); + // According to local test, we need to sleep to wait it fully processed. + // 1000 ms is a good value to sleep, otherwise it might cause keyDispatchingTimedOut. + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + UiUtils.waitUntilCondition(1000, () -> !sPowerManager.isInteractive()); + sPowerManager.wakeUp(SystemClock.uptimeMillis()); + UiUtils.waitUntilCondition(1000, () -> sPowerManager.isInteractive()); + + // After power on screen, need to unlock and goto home page. + AdbUtils.shell("input keyevent KEYCODE_MENU"); + } }