diff --git a/res/values/strings.xml b/res/values/strings.xml index 26cdde16298..593fdbbcfa5 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -10056,6 +10056,12 @@ Dark Theme + + On / Temporarily disabled due to Battery Saver + + + Temporarily turned on due to Battery Saver + Supported apps will also switch to dark theme diff --git a/src/com/android/settings/display/DarkUIPreferenceController.java b/src/com/android/settings/display/DarkUIPreferenceController.java index 9df2402850e..d3d30b50221 100644 --- a/src/com/android/settings/display/DarkUIPreferenceController.java +++ b/src/com/android/settings/display/DarkUIPreferenceController.java @@ -17,27 +17,53 @@ package com.android.settings.display; import android.app.UiModeManager; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.PowerManager; import android.provider.Settings; import androidx.annotation.VisibleForTesting; import androidx.fragment.app.Fragment; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreference; +import com.android.settings.R; import com.android.settings.core.TogglePreferenceController; +import com.android.settingslib.core.lifecycle.LifecycleObserver; +import com.android.settingslib.core.lifecycle.events.OnStart; +import com.android.settingslib.core.lifecycle.events.OnStop; -public class DarkUIPreferenceController extends TogglePreferenceController { +public class DarkUIPreferenceController extends TogglePreferenceController implements + LifecycleObserver, OnStart, OnStop { public static final String DARK_MODE_PREFS = "dark_mode_prefs"; public static final String PREF_DARK_MODE_DIALOG_SEEN = "dark_mode_dialog_seen"; public static final int DIALOG_SEEN = 1; + + @VisibleForTesting + SwitchPreference mPreference; + private UiModeManager mUiModeManager; + private PowerManager mPowerManager; private Context mContext; + private Fragment mFragment; + private BroadcastReceiver mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + updateEnabledStateIfNeeded(); + } + }; + public DarkUIPreferenceController(Context context, String key) { super(context, key); mContext = context; mUiModeManager = context.getSystemService(UiModeManager.class); + mPowerManager = context.getSystemService(PowerManager.class); } @Override @@ -45,6 +71,18 @@ public class DarkUIPreferenceController extends TogglePreferenceController { return mUiModeManager.getNightMode() == UiModeManager.MODE_NIGHT_YES; } + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mPreference = screen.findPreference(getPreferenceKey()); + } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + updateEnabledStateIfNeeded(); + } + @Override public boolean setChecked(boolean isChecked) { final boolean dialogSeen = @@ -67,6 +105,29 @@ public class DarkUIPreferenceController extends TogglePreferenceController { } } + @VisibleForTesting + void updateEnabledStateIfNeeded() { + if (mPreference == null) { + return; + } + boolean isBatterySaver = isPowerSaveMode(); + mPreference.setEnabled(!isBatterySaver); + if (isBatterySaver) { + int stringId = mUiModeManager.getNightMode() == UiModeManager.MODE_NIGHT_YES + ? R.string.dark_ui_mode_disabled_summary_dark_theme_on + : R.string.dark_ui_mode_disabled_summary_dark_theme_off; + mPreference.setSummary(mContext.getString(stringId)); + } else { + mPreference.setSummary(null); + } + } + + @VisibleForTesting + boolean isPowerSaveMode() { + return mPowerManager.isPowerSaveMode(); + } + + @VisibleForTesting void setUiModeManager(UiModeManager uiModeManager) { mUiModeManager = uiModeManager; @@ -76,6 +137,17 @@ public class DarkUIPreferenceController extends TogglePreferenceController { mFragment = fragment; } + @Override + public void onStart() { + mContext.registerReceiver(mReceiver, + new IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)); + } + + @Override + public void onStop() { + mContext.unregisterReceiver(mReceiver); + } + @Override public int getAvailabilityStatus() { return AVAILABLE; diff --git a/tests/robotests/src/com/android/settings/display/DarkUIPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/DarkUIPreferenceControllerTest.java new file mode 100644 index 00000000000..3659803cc80 --- /dev/null +++ b/tests/robotests/src/com/android/settings/display/DarkUIPreferenceControllerTest.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2019 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; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.os.Handler; +import android.os.IPowerManager; +import android.os.PowerManager; + +import androidx.fragment.app.Fragment; +import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreference; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +@RunWith(RobolectricTestRunner.class) +public class DarkUIPreferenceControllerTest { + + private DarkUIPreferenceController mController; + private Context mContext; + @Mock + private Fragment mFragment; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); + mController = spy(new DarkUIPreferenceController(mContext, "dark_ui_mode")); + mController.setParentFragment(mFragment); + mController.mPreference = new SwitchPreference(mContext); + mController.onStart(); + } + + @Test + public void batterySaverToggles_disabledStateUpdates() { + doReturn(true).when(mController).isPowerSaveMode(); + mController.updateEnabledStateIfNeeded(); + assertThat(mController.mPreference.isEnabled()).isFalse(); + + doReturn(false).when(mController).isPowerSaveMode(); + mController.updateEnabledStateIfNeeded(); + assertThat(mController.mPreference.isEnabled()).isTrue(); + + doReturn(true).when(mController).isPowerSaveMode(); + mController.updateEnabledStateIfNeeded(); + assertThat(mController.mPreference.isEnabled()).isFalse(); + } +}