blob: c079f44cf00a9fae1e25c77c0c3eb5276189a366 [file] [log] [blame]
/*
* Copyright (C) 2016 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 androidx.appcompat.app;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static androidx.appcompat.app.NightModeActivity.TOP_ACTIVITY;
import static androidx.appcompat.testutils.TestUtilsMatchers.isBackground;
import static org.junit.Assert.assertTrue;
import android.app.Instrumentation;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.LargeTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import androidx.appcompat.test.R;
import androidx.core.content.ContextCompat;
import androidx.testutils.AppCompatActivityUtils;
import androidx.testutils.RecreatedAppCompatActivity;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@LargeTest
@RunWith(AndroidJUnit4.class)
public class NightModeTestCase {
@Rule
public final ActivityTestRule<NightModeActivity> mActivityTestRule;
private static final String STRING_DAY = "DAY";
private static final String STRING_NIGHT = "NIGHT";
public NightModeTestCase() {
mActivityTestRule = new ActivityTestRule<>(NightModeActivity.class);
}
@Before
public void setup() {
// By default we'll set the night mode to NO, which allows us to make better
// assumptions in the test below
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
}
@Test
public void testLocalDayNightModeRecreatesActivity() throws Throwable {
// Verify first that we're in day mode
onView(withId(R.id.text_night_mode)).check(matches(withText(STRING_DAY)));
// Now force the local night mode to be yes (aka night mode)
setLocalNightModeAndWaitForRecreate(
mActivityTestRule.getActivity(), AppCompatDelegate.MODE_NIGHT_YES);
// Now check the text has changed, signifying that night resources are being used
onView(withId(R.id.text_night_mode)).check(matches(withText(STRING_NIGHT)));
}
@Test
public void testColorConvertedDrawableChangesWithNightMode() throws Throwable {
final NightModeActivity activity = mActivityTestRule.getActivity();
final int dayColor = ContextCompat.getColor(activity, R.color.color_sky_day);
final int nightColor = ContextCompat.getColor(activity, R.color.color_sky_night);
// Loop through and switching from day to night and vice-versa multiple times. It needs
// to be looped since the issue is with drawable caching, therefore we need to prime the
// cache for the issue to happen
for (int i = 0; i < 5; i++) {
// First force it to not be night mode
setLocalNightModeAndWaitForRecreate(TOP_ACTIVITY, AppCompatDelegate.MODE_NIGHT_NO);
// ... and verify first that we're in day mode
onView(withId(R.id.view_background)).check(matches(isBackground(dayColor)));
// Now force the local night mode to be yes (aka night mode)
setLocalNightModeAndWaitForRecreate(TOP_ACTIVITY, AppCompatDelegate.MODE_NIGHT_YES);
// ... and verify first that we're in night mode
onView(withId(R.id.view_background)).check(matches(isBackground(nightColor)));
}
}
@Test
public void testNightModeAutoRecreatesOnTimeChange() throws Throwable {
// Create a fake TwilightManager and set it as the app instance
final FakeTwilightManager twilightManager = new FakeTwilightManager();
TwilightManager.setInstance(twilightManager);
final NightModeActivity activity = mActivityTestRule.getActivity();
// Verify that we're currently in day mode
onView(withId(R.id.text_night_mode)).check(matches(withText(STRING_DAY)));
// Set MODE_NIGHT_AUTO so that we will change to night mode automatically
final NightModeActivity newActivity =
setLocalNightModeAndWaitForRecreate(activity, AppCompatDelegate.MODE_NIGHT_AUTO);
final AppCompatDelegateImplBase newDelegate =
(AppCompatDelegateImplBase) newActivity.getDelegate();
// Update the fake twilight manager to be in night and trigger a fake 'time' change
mActivityTestRule.runOnUiThread(new Runnable() {
@Override
public void run() {
twilightManager.setIsNight(true);
newDelegate.getAutoNightModeManager().dispatchTimeChanged();
}
});
RecreatedAppCompatActivity.sResumed = new CountDownLatch(1);
assertTrue(RecreatedAppCompatActivity.sResumed.await(1, TimeUnit.SECONDS));
// At this point recreate that has been triggered by dispatchTimeChanged call
// has completed
// Check that the text has changed, signifying that night resources are being used
onView(withId(R.id.text_night_mode)).check(matches(withText(STRING_NIGHT)));
}
@Test
public void testNightModeAutoRecreatesOnResume() throws Throwable {
// Create a fake TwilightManager and set it as the app instance
final FakeTwilightManager twilightManager = new FakeTwilightManager();
TwilightManager.setInstance(twilightManager);
NightModeActivity activity = mActivityTestRule.getActivity();
// Set MODE_NIGHT_AUTO so that we will change to night mode automatically
activity = setLocalNightModeAndWaitForRecreate(activity, AppCompatDelegate.MODE_NIGHT_AUTO);
// Verify that we're currently in day mode
onView(withId(R.id.text_night_mode)).check(matches(withText(STRING_DAY)));
final NightModeActivity toTest = activity;
mActivityTestRule.runOnUiThread(new Runnable() {
@Override
public void run() {
final Instrumentation instrumentation =
InstrumentationRegistry.getInstrumentation();
// Now fool the Activity into thinking that it has gone into the background
instrumentation.callActivityOnPause(toTest);
instrumentation.callActivityOnStop(toTest);
// Now update the twilight manager while the Activity is in the 'background'
twilightManager.setIsNight(true);
// Now tell the Activity that it has gone into the foreground again
instrumentation.callActivityOnStart(toTest);
instrumentation.callActivityOnResume(toTest);
}
});
// finally check that the text has changed, signifying that night resources are being used
onView(withId(R.id.text_night_mode)).check(matches(withText(STRING_NIGHT)));
}
private static class FakeTwilightManager extends TwilightManager {
private boolean mIsNight;
FakeTwilightManager() {
super(null, null);
}
@Override
boolean isNight() {
return mIsNight;
}
void setIsNight(boolean night) {
mIsNight = night;
}
}
private NightModeActivity setLocalNightModeAndWaitForRecreate(
final NightModeActivity activity,
@AppCompatDelegate.NightMode final int nightMode) throws Throwable {
final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
mActivityTestRule.runOnUiThread(new Runnable() {
@Override
public void run() {
activity.getDelegate().setLocalNightMode(nightMode);
}
});
final NightModeActivity result =
AppCompatActivityUtils.recreateActivity(mActivityTestRule, activity);
AppCompatActivityUtils.waitForExecution(mActivityTestRule);
instrumentation.waitForIdleSync();
return result;
}
}