Update "Dark Theme" Settings screen to account for Modes that can toggle it

Bedtime is no longer a special case.

Fixes: 361592187
Test: atest com.android.settings.display.darkmode
Flag: android.app.modes_ui
Change-Id: Iddc5d8142d6bc0bb1f5c4ead876ee201c8818b12
This commit is contained in:
Matías Hernández
2024-09-10 12:13:41 +02:00
parent 1ffafd365e
commit 2a3e8b3070
10 changed files with 562 additions and 156 deletions

View File

@@ -0,0 +1,207 @@
/*
* Copyright (C) 2024 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 android.app.UiModeManager.MODE_ATTENTION_THEME_OVERLAY_NIGHT;
import static android.app.UiModeManager.MODE_NIGHT_AUTO;
import static android.app.UiModeManager.MODE_NIGHT_CUSTOM;
import static android.app.UiModeManager.MODE_NIGHT_CUSTOM_TYPE_BEDTIME;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.when;
import android.app.Flags;
import android.app.UiModeManager;
import android.content.Context;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.service.notification.ZenDeviceEffects;
import androidx.test.core.app.ApplicationProvider;
import com.android.settingslib.notification.modes.TestModeBuilder;
import com.android.settingslib.notification.modes.ZenMode;
import com.android.settingslib.notification.modes.ZenModesBackend;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.shadows.ShadowApplication;
import java.time.LocalTime;
import java.util.List;
@RunWith(RobolectricTestRunner.class)
public class AutoDarkThemeTest {
@Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
private static final ZenDeviceEffects DEVICE_EFFECTS_WITH_DARK_THEME =
new ZenDeviceEffects.Builder().setShouldUseNightMode(true).build();
private static final ZenMode MODE_WITH_DARK_THEME = new TestModeBuilder()
.setName("Sechseläuten")
.setDeviceEffects(DEVICE_EFFECTS_WITH_DARK_THEME)
.build();
private Context mContext;
@Mock private UiModeManager mUiModeManager;
@Mock private ZenModesBackend mZenModesBackend;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = ApplicationProvider.getApplicationContext();
ShadowApplication shadowApp = ShadowApplication.getInstance();
shadowApp.setSystemService(Context.UI_MODE_SERVICE, mUiModeManager);
ZenModesBackend.setInstance(mZenModesBackend);
when(mZenModesBackend.getModes()).thenReturn(List.of());
}
@Test
public void getStatus_inactiveButAuto() {
when(mUiModeManager.getNightMode()).thenReturn(MODE_NIGHT_AUTO);
assertThat(getStatus(false)).isEqualTo("Will turn on automatically at sunset");
}
@Test
public void getStatus_activeDueToAuto() {
when(mUiModeManager.getNightMode()).thenReturn(MODE_NIGHT_AUTO);
assertThat(getStatus(true)).isEqualTo("Will turn off automatically at sunrise");
}
@Test
@EnableFlags(Flags.FLAG_MODES_UI)
public void getStatus_inactiveButUsedInModes() {
when(mUiModeManager.getNightMode()).thenReturn(MODE_NIGHT_CUSTOM);
when(mZenModesBackend.getModes()).thenReturn(List.of(MODE_WITH_DARK_THEME));
assertThat(getStatus(false)).isEqualTo("Will turn on when Sechseläuten starts");
}
@Test
@EnableFlags(Flags.FLAG_MODES_UI)
public void getStatus_activeDueToModes() {
when(mUiModeManager.getNightMode()).thenReturn(MODE_NIGHT_CUSTOM);
when(mUiModeManager.getAttentionModeThemeOverlay()).thenReturn(
MODE_ATTENTION_THEME_OVERLAY_NIGHT);
when(mZenModesBackend.getModes()).thenReturn(
List.of(new TestModeBuilder(MODE_WITH_DARK_THEME).setActive(true).build()));
assertThat(getStatus(true)).isEqualTo("Will turn off when Sechseläuten ends");
}
@Test
@DisableFlags(Flags.FLAG_MODES_UI)
public void getStatus_inactiveButUsingBedtime() {
when(mUiModeManager.getNightMode()).thenReturn(MODE_NIGHT_CUSTOM);
when(mUiModeManager.getNightModeCustomType()).thenReturn(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
assertThat(getStatus(false)).isEqualTo("Will turn on automatically at bedtime");
}
@Test
@DisableFlags(Flags.FLAG_MODES_UI)
public void getStatus_activeDueToBedtime() {
when(mUiModeManager.getNightMode()).thenReturn(MODE_NIGHT_CUSTOM);
when(mUiModeManager.getNightModeCustomType()).thenReturn(MODE_NIGHT_CUSTOM_TYPE_BEDTIME);
assertThat(getStatus(true)).isEqualTo("Will turn off automatically after bedtime");
}
@Test
public void getStatus_inactiveButHasSchedule() {
when(mUiModeManager.getNightMode()).thenReturn(MODE_NIGHT_CUSTOM);
when(mUiModeManager.getCustomNightModeStart()).thenReturn(LocalTime.of(22, 0, 0, 0));
when(mUiModeManager.getCustomNightModeEnd()).thenReturn(LocalTime.of(8, 0, 0, 0));
assertThat(getStatus(false)).isEqualTo("Will turn on automatically at 10:00 PM");
}
@Test
public void getStatus_activeDueToSchedule() {
when(mUiModeManager.getNightMode()).thenReturn(MODE_NIGHT_CUSTOM);
when(mUiModeManager.getCustomNightModeStart()).thenReturn(LocalTime.of(22, 0, 0, 0));
when(mUiModeManager.getCustomNightModeEnd()).thenReturn(LocalTime.of(8, 0, 0, 0));
assertThat(getStatus(true)).isEqualTo("Will turn off automatically at 8:00 AM");
}
private String getStatus(boolean active) {
return AutoDarkTheme.getStatus(mContext, active);
}
@Test
@EnableFlags(Flags.FLAG_MODES_UI)
public void getModesThatChangeDarkTheme_returnsModeNames() {
ZenMode modeThatChanges1 = new TestModeBuilder()
.setName("Inactive")
.setDeviceEffects(DEVICE_EFFECTS_WITH_DARK_THEME)
.setActive(false)
.build();
ZenMode modeThatDoesNotChange = new TestModeBuilder()
.setName("Unrelated")
.build();
ZenMode modeThatChanges2 = new TestModeBuilder()
.setName("Active")
.setDeviceEffects(DEVICE_EFFECTS_WITH_DARK_THEME)
.setActive(true)
.build();
when(mZenModesBackend.getModes()).thenReturn(
List.of(modeThatChanges1, modeThatDoesNotChange, modeThatChanges2));
assertThat(AutoDarkTheme.getModesThatChangeDarkTheme(mContext))
.containsExactly("Inactive", "Active")
.inOrder();
}
@Test
@EnableFlags(Flags.FLAG_MODES_UI)
public void getActiveModesThatChangeDarkTheme_returnsModeNames() {
ZenMode inactiveModeThatUsesDarkTheme = new TestModeBuilder()
.setName("Inactive")
.setDeviceEffects(DEVICE_EFFECTS_WITH_DARK_THEME)
.setActive(false)
.build();
ZenMode otherInactiveMode = new TestModeBuilder()
.setName("Unrelated, inactive")
.setActive(false)
.build();
ZenMode otherActiveMode = new TestModeBuilder()
.setName("Unrelated, active")
.setActive(true)
.build();
ZenMode activeModeThatUsesDarkTheme = new TestModeBuilder()
.setName("Active")
.setDeviceEffects(DEVICE_EFFECTS_WITH_DARK_THEME)
.setActive(true)
.build();
when(mZenModesBackend.getModes()).thenReturn(
List.of(inactiveModeThatUsesDarkTheme, otherInactiveMode, otherActiveMode,
activeModeThatUsesDarkTheme));
assertThat(AutoDarkTheme.getActiveModesThatChangeDarkTheme(mContext))
.containsExactly("Active");
}
}

View File

@@ -22,23 +22,29 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.app.Flags;
import android.app.UiModeManager;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.PowerManager;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settingslib.notification.modes.ZenModesBackend;
import com.android.settingslib.widget.MainSwitchPreference;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -47,6 +53,8 @@ import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import java.time.LocalTime;
import java.util.List;
import java.util.Locale;
@RunWith(RobolectricTestRunner.class)
@@ -57,6 +65,9 @@ public class DarkModeActivationPreferenceControllerTest {
private DarkModeActivationPreferenceController mController;
private String mPreferenceKey = "key";
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
private MainSwitchPreference mPreference;
@Mock
private PreferenceScreen mScreen;
@@ -67,7 +78,7 @@ public class DarkModeActivationPreferenceControllerTest {
@Mock
private PowerManager mPM;
@Mock
private TimeFormatter mFormat;
private ZenModesBackend mZenModesBackend;
private Context mContext;
private Configuration mConfigNightYes = new Configuration();
@@ -87,7 +98,6 @@ public class DarkModeActivationPreferenceControllerTest {
when(mContext.getSystemService(PowerManager.class)).thenReturn(mPM);
when(mScreen.findPreference(anyString())).thenReturn(mPreference);
when(mService.setNightModeActivated(anyBoolean())).thenReturn(true);
when(mFormat.of(any())).thenReturn("10:00 AM");
when(mContext.getString(
R.string.dark_ui_activation_off_auto)).thenReturn("off_auto");
when(mContext.getString(
@@ -104,20 +114,23 @@ public class DarkModeActivationPreferenceControllerTest {
R.string.dark_ui_summary_off_auto_mode_never)).thenReturn("summary_off_manual");
when(mContext.getString(
R.string.dark_ui_summary_on_auto_mode_never)).thenReturn("summary_on_manual");
when(mContext.getString(R.string.dark_ui_summary_on_auto_mode_custom, "10:00 AM"))
when(mContext.getString(eq(R.string.dark_ui_summary_on_auto_mode_custom), any()))
.thenReturn("summary_on_custom");
when(mContext.getString(R.string.dark_ui_summary_off_auto_mode_custom, "10:00 AM"))
when(mContext.getString(eq(R.string.dark_ui_summary_off_auto_mode_custom), any()))
.thenReturn("summary_off_custom");
when(mContext.getString(R.string.dark_ui_summary_on_auto_mode_custom_bedtime))
.thenReturn("summary_on_custom_bedtime");
when(mContext.getString(R.string.dark_ui_summary_off_auto_mode_custom_bedtime))
.thenReturn("summary_off_custom_bedtime");
mController = new DarkModeActivationPreferenceController(mContext, mPreferenceKey, mFormat);
mController = new DarkModeActivationPreferenceController(mContext, mPreferenceKey);
mController.displayPreference(mScreen);
mConfigNightNo.uiMode = Configuration.UI_MODE_NIGHT_NO;
mConfigNightYes.uiMode = Configuration.UI_MODE_NIGHT_YES;
mConfigNightNo.locale = mLocal;
mConfigNightYes.locale = mLocal;
ZenModesBackend.setInstance(mZenModesBackend);
when(mZenModesBackend.getModes()).thenReturn(List.of());
}
@Test
@@ -145,6 +158,8 @@ public class DarkModeActivationPreferenceControllerTest {
@Test
public void nightMode_toggleButton_onCustom() {
when(mService.getNightMode()).thenReturn(UiModeManager.MODE_NIGHT_CUSTOM);
when(mService.getCustomNightModeStart()).thenReturn(LocalTime.of(10, 0, 0, 0));
when(mService.getCustomNightModeEnd()).thenReturn(LocalTime.of(12, 0, 0, 0));
when(mRes.getConfiguration()).thenReturn(mConfigNightYes);
mController.updateState(mPreference);
@@ -156,6 +171,8 @@ public class DarkModeActivationPreferenceControllerTest {
@Test
public void nightMode_toggleButton_offCustom() {
when(mService.getNightMode()).thenReturn(UiModeManager.MODE_NIGHT_CUSTOM);
when(mService.getCustomNightModeStart()).thenReturn(LocalTime.of(10, 0, 0, 0));
when(mService.getCustomNightModeEnd()).thenReturn(LocalTime.of(12, 0, 0, 0));
when(mRes.getConfiguration()).thenReturn(mConfigNightNo);
mController.updateState(mPreference);
@@ -165,6 +182,7 @@ public class DarkModeActivationPreferenceControllerTest {
}
@Test
@DisableFlags(Flags.FLAG_MODES_UI)
public void nightMode_toggleButton_onCustomBedtime() {
when(mService.getNightMode()).thenReturn(UiModeManager.MODE_NIGHT_CUSTOM);
when(mService.getNightModeCustomType())
@@ -178,6 +196,7 @@ public class DarkModeActivationPreferenceControllerTest {
}
@Test
@DisableFlags(Flags.FLAG_MODES_UI)
public void nightMode_toggleButton_offCustomBedtime() {
when(mService.getNightMode()).thenReturn(UiModeManager.MODE_NIGHT_CUSTOM);
when(mService.getNightModeCustomType())

View File

@@ -27,42 +27,62 @@ import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Flags;
import android.app.UiModeManager;
import android.content.Context;
import android.content.res.Resources;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.service.notification.ZenDeviceEffects;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.testutils.BedtimeSettingsUtils;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settingslib.notification.modes.TestModeBuilder;
import com.android.settingslib.notification.modes.ZenMode;
import com.android.settingslib.notification.modes.ZenModesBackend;
import com.android.settingslib.widget.FooterPreference;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import java.util.List;
@RunWith(RobolectricTestRunner.class)
public class DarkModeCustomBedtimePreferenceControllerTest {
public class DarkModeCustomModesPreferenceControllerTest {
private static final ZenMode MODE_WITH_DARK_THEME = new TestModeBuilder()
.setDeviceEffects(new ZenDeviceEffects.Builder().setShouldUseNightMode(true).build())
.build();
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@Mock
private UiModeManager mService;
@Mock
private PreferenceScreen mScreen;
@Mock
private Resources mResources;
@Mock
private FooterPreference mFooterPreference;
@Mock
private ZenModesBackend mZenModesBackend;
private DarkModeCustomBedtimePreferenceController mController;
private DarkModeCustomModesPreferenceController mController;
private Context mContext;
private BedtimeSettingsUtils mBedtimeSettingsUtils;
@@ -75,17 +95,78 @@ public class DarkModeCustomBedtimePreferenceControllerTest {
mBedtimeSettingsUtils = new BedtimeSettingsUtils(mContext);
when(mContext.getSystemService(UiModeManager.class)).thenReturn(mService);
when(mContext.getResources()).thenReturn(mResources);
when(mResources.getString(com.android.internal.R.string.config_systemWellbeing))
Resources res = spy(mContext.getResources());
when(res.getString(com.android.internal.R.string.config_systemWellbeing))
.thenReturn("wellbeing");
when(mContext.getResources()).thenReturn(res);
when(mScreen.findPreference(anyString())).thenReturn(mFooterPreference);
mController = new DarkModeCustomBedtimePreferenceController(mContext, "key");
mController = new DarkModeCustomModesPreferenceController(mContext, "key");
ZenModesBackend.setInstance(mZenModesBackend);
when(mZenModesBackend.getModes()).thenReturn(List.of());
}
@Test
@EnableFlags(Flags.FLAG_MODES_UI)
public void displayPreference_withOneModeTogglingDarkTheme() {
when(mZenModesBackend.getModes()).thenReturn(List.of(
new TestModeBuilder(MODE_WITH_DARK_THEME).setName("A").build()));
mController.displayPreference(mScreen);
verify(mFooterPreference).setTitle("A also activates dark theme");
verify(mFooterPreference).setLearnMoreAction(any());
verify(mFooterPreference).setLearnMoreText("Modes settings");
}
@Test
@EnableFlags(Flags.FLAG_MODES_UI)
public void displayPreference_withTwoModesTogglingDarkTheme() {
when(mZenModesBackend.getModes()).thenReturn(List.of(
new TestModeBuilder(MODE_WITH_DARK_THEME).setName("A").build(),
new TestModeBuilder(MODE_WITH_DARK_THEME).setName("B").build()));
mController.displayPreference(mScreen);
verify(mFooterPreference).setTitle("A and B also activate dark theme");
verify(mFooterPreference).setLearnMoreAction(any());
verify(mFooterPreference).setLearnMoreText("Modes settings");
}
@Test
@EnableFlags(Flags.FLAG_MODES_UI)
public void displayPreference_withManyModesTogglingDarkTheme() {
when(mZenModesBackend.getModes()).thenReturn(List.of(
new TestModeBuilder(MODE_WITH_DARK_THEME).setName("A").build(),
new TestModeBuilder(MODE_WITH_DARK_THEME).setName("B").build(),
new TestModeBuilder(MODE_WITH_DARK_THEME).setName("C").build(),
new TestModeBuilder(MODE_WITH_DARK_THEME).setName("D").build(),
new TestModeBuilder(MODE_WITH_DARK_THEME).setName("E").build()
));
mController.displayPreference(mScreen);
verify(mFooterPreference).setTitle("A, B, and 3 more also activate dark theme");
verify(mFooterPreference).setLearnMoreAction(any());
verify(mFooterPreference).setLearnMoreText("Modes settings");
}
@Test
@EnableFlags(Flags.FLAG_MODES_UI)
public void displayPreference_withZeroModesTogglingDarkTheme() {
when(mZenModesBackend.getModes()).thenReturn(List.of());
mController.displayPreference(mScreen);
verify(mFooterPreference).setTitle("Modes can also activate dark theme");
verify(mFooterPreference).setLearnMoreAction(any());
verify(mFooterPreference).setLearnMoreText("Modes settings");
}
@Test
@DisableFlags(Flags.FLAG_MODES_UI)
public void getAvailabilityStatus_bedtimeSettingsExist_shouldBeAvailableUnsearchable() {
mBedtimeSettingsUtils.installBedtimeSettings("wellbeing" /* wellbeingPackage */,
true /* enabled */);
@@ -95,6 +176,7 @@ public class DarkModeCustomBedtimePreferenceControllerTest {
}
@Test
@DisableFlags(Flags.FLAG_MODES_UI)
public void getAvailabilityStatus_bedtimeSettingsDisabled_shouldBeUnsupportedOnDevice() {
mBedtimeSettingsUtils.installBedtimeSettings("wellbeing" /* wellbeingPackage */,
false /* enabled */);
@@ -104,6 +186,7 @@ public class DarkModeCustomBedtimePreferenceControllerTest {
}
@Test
@DisableFlags(Flags.FLAG_MODES_UI)
public void nightModeCustomModeBedtime_bedtimeSettingsExist_shouldShowFooterPreference() {
mBedtimeSettingsUtils.installBedtimeSettings("wellbeing" /* wellbeingPackage */,
true /* enabled */);
@@ -116,6 +199,7 @@ public class DarkModeCustomBedtimePreferenceControllerTest {
}
@Test
@DisableFlags(Flags.FLAG_MODES_UI)
public void nightModeCustomModeSchedule_bedtimeSettingsExist_shouldHideFooterPreference() {
mBedtimeSettingsUtils.installBedtimeSettings("wellbeing" /* wellbeingPackage */,
true /* enabled */);
@@ -127,6 +211,7 @@ public class DarkModeCustomBedtimePreferenceControllerTest {
}
@Test
@DisableFlags(Flags.FLAG_MODES_UI)
public void nightModeNo_bedtimeSettingsExist_shouldHideFooterPreference() {
mBedtimeSettingsUtils.installBedtimeSettings("wellbeing" /* wellbeingPackage */,
true /* enabled */);
@@ -138,6 +223,7 @@ public class DarkModeCustomBedtimePreferenceControllerTest {
}
@Test
@DisableFlags(Flags.FLAG_MODES_UI)
public void nightModeYes_bedtimeSettingsExist_shouldHideFooterPreference() {
mBedtimeSettingsUtils.installBedtimeSettings("wellbeing" /* wellbeingPackage */,
true /* enabled */);
@@ -149,6 +235,7 @@ public class DarkModeCustomBedtimePreferenceControllerTest {
}
@Test
@DisableFlags(Flags.FLAG_MODES_UI)
public void nightModeAuto_bedtimeSettingsExist_shouldHideFooterPreference() {
mBedtimeSettingsUtils.installBedtimeSettings("wellbeing" /* wellbeingPackage */,
true /* enabled */);