/*
* 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 android.support.v7.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 android.support.v7.app.NightModeActivity.TOP_ACTIVITY;
import static android.support.v7.testutils.TestUtilsMatchers.isBackground;
import static org.junit.Assert.assertFalse;
import android.app.Instrumentation;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SdkSuppress;
import android.support.v4.content.ContextCompat;
import android.support.v7.appcompat.test.R;
import android.test.suitebuilder.annotation.MediumTest;
import org.junit.Before;
import org.junit.Test;
@MediumTest
@SdkSuppress(minSdkVersion = 14)
public class NightModeTestCase extends BaseInstrumentationTestCase<NightModeActivity> {
private static final String STRING_DAY = "DAY";
private static final String STRING_NIGHT = "NIGHT";
public NightModeTestCase() {
super(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();
final AppCompatDelegateImplV14 delegate = (AppCompatDelegateImplV14) activity.getDelegate();
// Verify that we're currently in day mode
onView(withId(R.id.text_night_mode)).check(matches(withText(STRING_DAY)));
// Now set MODE_NIGHT_AUTO so that we will change to night mode automatically
setLocalNightModeAndWaitForRecreate(activity, AppCompatDelegate.MODE_NIGHT_AUTO);
// Assert that the original Activity has not been destroyed yet
assertFalse(activity.isDestroyed());
// Now 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);
delegate.getAutoNightModeManager().dispatchTimeChanged();
}
});
// Now wait for the recreate
getInstrumentation().waitForIdleSync();
// Now 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);
final NightModeActivity activity = getActivity();
// Set MODE_NIGHT_AUTO so that we will change to night mode automatically
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)));
mActivityTestRule.runOnUiThread(new Runnable() {
@Override
public void run() {
final Instrumentation instrumentation = getInstrumentation();
// Now fool the Activity into thinking that it has gone into the background
instrumentation.callActivityOnPause(activity);
instrumentation.callActivityOnStop(activity);
// 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(activity);
instrumentation.callActivityOnResume(activity);
}
});
// 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 void setLocalNightModeAndWaitForRecreate(final AppCompatActivity 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);
}
});
instrumentation.waitForIdleSync();
}
}