diff --git a/app/src/main/java/com/amaze/filemanager/ui/activities/MainActivity.java b/app/src/main/java/com/amaze/filemanager/ui/activities/MainActivity.java index dafb859e92..1935377826 100644 --- a/app/src/main/java/com/amaze/filemanager/ui/activities/MainActivity.java +++ b/app/src/main/java/com/amaze/filemanager/ui/activities/MainActivity.java @@ -1531,21 +1531,27 @@ public SpeedDialView getFAB() { } public void showFab() { - getFAB().setVisibility(View.VISIBLE); - getFAB().show(); - CoordinatorLayout.LayoutParams params = - (CoordinatorLayout.LayoutParams) getFAB().getLayoutParams(); + showFab(getFAB()); + } + + private void showFab(SpeedDialView fab) { + fab.setVisibility(View.VISIBLE); + fab.show(); + CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) fab.getLayoutParams(); params.setBehavior(new SpeedDialView.ScrollingViewSnackbarBehavior()); - getFAB().requestLayout(); + fab.requestLayout(); } public void hideFab() { - getFAB().setVisibility(View.GONE); - getFAB().hide(); - CoordinatorLayout.LayoutParams params = - (CoordinatorLayout.LayoutParams) getFAB().getLayoutParams(); + hideFab(getFAB()); + } + + private void hideFab(SpeedDialView fab) { + fab.setVisibility(View.GONE); + fab.hide(); + CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) fab.getLayoutParams(); params.setBehavior(new SpeedDialView.NoBehavior()); - getFAB().requestLayout(); + fab.requestLayout(); } public AppBar getAppbar() { @@ -1917,7 +1923,7 @@ private FabWithLabelView initFabTitle( private void initialiseFabConfirmSelection() { fabConfirmSelection = findViewById(R.id.fabs_confirm_selection); - fabConfirmSelection.hide(); + hideFabConfirmSelection(); if (mReturnIntent) { int colorAccent = getAccent(); fabConfirmSelection.setMainFabClosedBackgroundColor(colorAccent); @@ -1952,13 +1958,13 @@ public void onToggleChanged(boolean isOpen) {} */ public void showFabConfirmSelection() { if (mReturnIntent) { - fabConfirmSelection.show(); + showFab(fabConfirmSelection); } } /** Hides the floating action button which confirms the selection */ public void hideFabConfirmSelection() { - fabConfirmSelection.hide(); + hideFab(fabConfirmSelection); } public boolean copyToClipboard(Context context, String text) { diff --git a/app/src/main/java/com/amaze/filemanager/ui/activities/superclasses/ThemedActivity.java b/app/src/main/java/com/amaze/filemanager/ui/activities/superclasses/ThemedActivity.java index e35172af3c..f94f6efac7 100644 --- a/app/src/main/java/com/amaze/filemanager/ui/activities/superclasses/ThemedActivity.java +++ b/app/src/main/java/com/amaze/filemanager/ui/activities/superclasses/ThemedActivity.java @@ -21,6 +21,7 @@ package com.amaze.filemanager.ui.activities.superclasses; import static android.os.Build.VERSION.SDK_INT; +import static android.os.Build.VERSION_CODES.LOLLIPOP; import static com.amaze.filemanager.ui.fragments.preferencefragments.PreferencesConstants.PREFERENCE_COLORED_NAVIGATION; import com.amaze.filemanager.R; @@ -34,10 +35,16 @@ import com.readystatesoftware.systembartint.SystemBarTintManager; import android.app.ActivityManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; import android.content.res.Configuration; import android.graphics.drawable.BitmapDrawable; import android.os.Build; import android.os.Bundle; +import android.os.PowerManager; import android.view.View; import android.view.ViewGroup; import android.view.Window; @@ -49,15 +56,40 @@ import androidx.annotation.Nullable; import androidx.appcompat.widget.Toolbar; import androidx.core.content.ContextCompat; +import androidx.preference.PreferenceManager; /** Created by arpitkh996 on 03-03-2016. */ public class ThemedActivity extends PreferenceActivity { private int uiModeNight = -1; + /** + * BroadcastReceiver responsible for updating the theme if battery saver mode is turned on or off + */ + private final BroadcastReceiver powerModeReceiver = + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent i) { + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); + boolean followBatterySaver = + preferences.getBoolean(PreferencesConstants.FRAGMENT_FOLLOW_BATTERY_SAVER, false); + + AppTheme theme = + AppTheme.getTheme( + Integer.parseInt( + preferences.getString(PreferencesConstants.FRAGMENT_THEME, "4"))); + + if (followBatterySaver && theme.canBeLight()) { + recreate(); + } + } + }; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + registerPowerModeReceiver(); + // setting window background color instead of each item, in order to reduce pixel overdraw if (getAppTheme().equals(AppTheme.LIGHT)) { getWindow().setBackgroundDrawableResource(android.R.color.white); @@ -134,7 +166,7 @@ public void onConfigurationChanged(@NonNull Configuration newConfig) { uiModeNight = newUiModeNight; if (getPrefs().getString(PreferencesConstants.FRAGMENT_THEME, "4").equals("4")) { - getUtilsProvider().getThemeManager().setAppTheme(AppTheme.getTheme(this, 4)); + getUtilsProvider().getThemeManager().setAppTheme(AppTheme.getTheme(4)); // Recreate activity, handling saved state // // Not smooth, but will only be called if the user changes the system theme, not @@ -309,4 +341,29 @@ protected void onResume() { uiModeNight = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; setTheme(); } + + @Override + protected void onDestroy() { + super.onDestroy(); + + unregisterPowerModeReceiver(); + } + + /** + * Registers the BroadcastReceiver \`powerModeReceiver\` to listen to broadcasts that the battery + * save mode has been changed + */ + private void registerPowerModeReceiver() { + if (SDK_INT >= LOLLIPOP) { + registerReceiver( + powerModeReceiver, new IntentFilter(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)); + } + } + + /** Unregisters the BroadcastReceiver \`powerModeReceiver\` */ + private void unregisterPowerModeReceiver() { + if (SDK_INT >= LOLLIPOP) { + unregisterReceiver(powerModeReceiver); + } + } } diff --git a/app/src/main/java/com/amaze/filemanager/ui/dialogs/ColorPickerDialog.java b/app/src/main/java/com/amaze/filemanager/ui/dialogs/ColorPickerDialog.java index 5f6db7fd8e..ac3257bc3f 100644 --- a/app/src/main/java/com/amaze/filemanager/ui/dialogs/ColorPickerDialog.java +++ b/app/src/main/java/com/amaze/filemanager/ui/dialogs/ColorPickerDialog.java @@ -171,8 +171,7 @@ public void onBindDialogView(View view) { ((AppCompatTextView) child.findViewById(R.id.text)).setText(COLORS[i].first); CircularColorsView colorsView = child.findViewById(R.id.circularColorsView); colorsView.setColors(getColor(i, 0), getColor(i, 1), getColor(i, 2), getColor(i, 3)); - AppTheme appTheme = - AppTheme.getTheme(requireContext(), requireArguments().getInt(ARG_APP_THEME)); + AppTheme appTheme = AppTheme.getTheme(requireArguments().getInt(ARG_APP_THEME)); if (appTheme.getMaterialDialogTheme(requireContext()) == Theme.LIGHT) colorsView.setDividerColor(Color.WHITE); else colorsView.setDividerColor(Color.BLACK); diff --git a/app/src/main/java/com/amaze/filemanager/ui/fragments/preferencefragments/AppearancePrefsFragment.kt b/app/src/main/java/com/amaze/filemanager/ui/fragments/preferencefragments/AppearancePrefsFragment.kt index a18b093896..dc70ea6edb 100644 --- a/app/src/main/java/com/amaze/filemanager/ui/fragments/preferencefragments/AppearancePrefsFragment.kt +++ b/app/src/main/java/com/amaze/filemanager/ui/fragments/preferencefragments/AppearancePrefsFragment.kt @@ -54,8 +54,7 @@ class AppearancePrefsFragment : BasePrefsFragment() { editor.putString(PreferencesConstants.FRAGMENT_THEME, which.toString()) editor.apply() - activity.utilsProvider.themeManager.appTheme = - AppTheme.getTheme(activity, which) + activity.utilsProvider.themeManager.appTheme = AppTheme.getTheme(which) activity.recreate() dialog.dismiss() @@ -105,6 +104,12 @@ class AppearancePrefsFragment : BasePrefsFragment() { true } + private val onClickFollowBatterySaver = Preference.OnPreferenceClickListener { + // recreate the activity since the theme could have changed with this preference change + activity.recreate() + true + } + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { setPreferencesFromResource(R.xml.appearance_prefs, rootKey) @@ -114,9 +119,18 @@ class AppearancePrefsFragment : BasePrefsFragment() { .prefs .getString(PreferencesConstants.FRAGMENT_THEME, "4")!! .toInt() + themePref?.summary = themes[currentTheme] themePref?.onPreferenceClickListener = onClickTheme + val batterySaverPref = findPreference( + PreferencesConstants.FRAGMENT_FOLLOW_BATTERY_SAVER + ) + + val currentThemeEnum = AppTheme.getTheme(currentTheme) + batterySaverPref?.isVisible = currentThemeEnum.canBeLight() + batterySaverPref?.onPreferenceClickListener = onClickFollowBatterySaver + findPreference(PreferencesConstants.PREFERENCE_COLORED_NAVIGATION) ?.let { it.isEnabled = true diff --git a/app/src/main/java/com/amaze/filemanager/ui/fragments/preferencefragments/PreferencesConstants.kt b/app/src/main/java/com/amaze/filemanager/ui/fragments/preferencefragments/PreferencesConstants.kt index b77e0cfbba..e276f1f67e 100644 --- a/app/src/main/java/com/amaze/filemanager/ui/fragments/preferencefragments/PreferencesConstants.kt +++ b/app/src/main/java/com/amaze/filemanager/ui/fragments/preferencefragments/PreferencesConstants.kt @@ -23,6 +23,7 @@ package com.amaze.filemanager.ui.fragments.preferencefragments object PreferencesConstants { // appearance_prefs.xml const val FRAGMENT_THEME = "theme" + const val FRAGMENT_FOLLOW_BATTERY_SAVER = "follow_battery_saver" const val PREFERENCE_USE_CIRCULAR_IMAGES = "circularimages" const val PREFERENCE_SHOW_DIVIDERS = "showDividers" const val PREFERENCE_SHOW_HEADERS = "showHeaders" diff --git a/app/src/main/java/com/amaze/filemanager/ui/provider/UtilitiesProvider.java b/app/src/main/java/com/amaze/filemanager/ui/provider/UtilitiesProvider.java index 781e5df797..11834b5f22 100644 --- a/app/src/main/java/com/amaze/filemanager/ui/provider/UtilitiesProvider.java +++ b/app/src/main/java/com/amaze/filemanager/ui/provider/UtilitiesProvider.java @@ -26,7 +26,6 @@ import android.content.Context; import android.content.SharedPreferences; -import android.content.res.Configuration; import androidx.preference.PreferenceManager; @@ -40,11 +39,7 @@ public UtilitiesProvider(Context context) { colorPreference = new ColorPreferenceHelper(); colorPreference.getCurrentUserColorPreferences(context, sharedPreferences); - appThemeManager = - new AppThemeManager( - sharedPreferences, - (context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) - == Configuration.UI_MODE_NIGHT_YES); + appThemeManager = new AppThemeManager(sharedPreferences, context); } public ColorPreferenceHelper getColorPreference() { diff --git a/app/src/main/java/com/amaze/filemanager/ui/theme/AppTheme.java b/app/src/main/java/com/amaze/filemanager/ui/theme/AppTheme.java index aabee77cdd..89f50cca23 100644 --- a/app/src/main/java/com/amaze/filemanager/ui/theme/AppTheme.java +++ b/app/src/main/java/com/amaze/filemanager/ui/theme/AppTheme.java @@ -23,17 +23,23 @@ import java.util.Calendar; import com.afollestad.materialdialogs.Theme; +import com.amaze.filemanager.ui.fragments.preferencefragments.PreferencesConstants; import android.content.Context; +import android.content.SharedPreferences; import android.content.res.Configuration; +import android.os.Build; +import android.os.PowerManager; + +import androidx.preference.PreferenceManager; /** This enum represents the theme of the app (LIGHT or DARK) */ public enum AppTheme { - LIGHT(0), - DARK(1), - TIMED(2), - BLACK(3), - SYSTEM(4); + LIGHT(0, true), + DARK(1, false), + TIMED(2, true), + BLACK(3, false), + SYSTEM(4, true); public static final int LIGHT_INDEX = 0; public static final int DARK_INDEX = 1; @@ -43,8 +49,15 @@ public enum AppTheme { private int id; - AppTheme(int id) { + /** + * Specifies if the theme can be light in some situations. Used for the "Follow battery saver" + * option. + */ + private final boolean canBeLight; + + AppTheme(int id, boolean canBeLight) { this.id = id; + this.canBeLight = canBeLight; } /** @@ -53,11 +66,7 @@ public enum AppTheme { * @param index The theme index * @return The AppTheme for the given index */ - public static AppTheme getTheme(Context context, int index) { - return getTheme(isNightMode(context), index); - } - - public static AppTheme getTheme(boolean isNightMode, int index) { + public static AppTheme getTheme(int index) { switch (index) { default: case LIGHT_INDEX: @@ -69,27 +78,19 @@ public static AppTheme getTheme(boolean isNightMode, int index) { case BLACK_INDEX: return BLACK; case SYSTEM_INDEX: - return isNightMode ? DARK : LIGHT; + return SYSTEM; } } public Theme getMaterialDialogTheme(Context context) { - switch (id) { + AppTheme simpleTheme = getSimpleTheme(context); + switch (simpleTheme.id) { default: case LIGHT_INDEX: return Theme.LIGHT; case DARK_INDEX: case BLACK_INDEX: return Theme.DARK; - case TIME_INDEX: - int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY); - if (hour <= 6 || hour >= 18) { - return Theme.DARK; - } else { - return Theme.LIGHT; - } - case SYSTEM_INDEX: - return isNightMode(context) ? Theme.DARK : Theme.LIGHT; } } @@ -99,10 +100,17 @@ public Theme getMaterialDialogTheme(Context context) { * @return The AppTheme for the given index */ public AppTheme getSimpleTheme(Context context) { - return getSimpleTheme(isNightMode(context)); + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); + boolean followBatterySaver = + preferences.getBoolean(PreferencesConstants.FRAGMENT_FOLLOW_BATTERY_SAVER, false); + return getSimpleTheme(isNightMode(context), followBatterySaver && isBatterySaverMode(context)); } - public AppTheme getSimpleTheme(boolean isNightMode) { + public AppTheme getSimpleTheme(boolean isNightMode, boolean isBatterySaver) { + if (this.canBeLight() && isBatterySaver) { + return DARK; + } + switch (id) { default: case LIGHT_INDEX: @@ -127,8 +135,28 @@ public int getId() { return id; } + /** Returns if the theme can be light in some situations */ + public boolean canBeLight() { + return this.canBeLight; + } + private static boolean isNightMode(Context context) { return (context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES; } + + /** + * Checks if battery saver mode is on + * + * @param context The context in which the battery saver mode should be checked + * @return Whether battery saver mode is on or off + */ + private static boolean isBatterySaverMode(Context context) { + PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + return powerManager.isPowerSaveMode(); + } else { + return false; + } + } } diff --git a/app/src/main/java/com/amaze/filemanager/ui/theme/AppThemeManager.java b/app/src/main/java/com/amaze/filemanager/ui/theme/AppThemeManager.java index 0135d2f028..49d0067a5c 100644 --- a/app/src/main/java/com/amaze/filemanager/ui/theme/AppThemeManager.java +++ b/app/src/main/java/com/amaze/filemanager/ui/theme/AppThemeManager.java @@ -22,27 +22,27 @@ import com.amaze.filemanager.ui.fragments.preferencefragments.PreferencesConstants; +import android.content.Context; import android.content.SharedPreferences; /** Saves and restores the AppTheme */ public class AppThemeManager { private SharedPreferences preferences; private AppTheme appTheme; - private final boolean isNightMode; + private final Context context; - public AppThemeManager(SharedPreferences preferences, boolean isNightMode) { + public AppThemeManager(SharedPreferences preferences, Context context) { this.preferences = preferences; - this.isNightMode = isNightMode; + this.context = context; String themeId = preferences.getString(PreferencesConstants.FRAGMENT_THEME, "4"); - appTheme = - AppTheme.getTheme(isNightMode, Integer.parseInt(themeId)).getSimpleTheme(isNightMode); + appTheme = AppTheme.getTheme(Integer.parseInt(themeId)); } /** * @return The current Application theme */ public AppTheme getAppTheme() { - return appTheme.getSimpleTheme(isNightMode); + return appTheme.getSimpleTheme(context); } /** diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 565e272446..4708647c32 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -183,6 +183,8 @@ Q&A, Help & Troubleshooting Use circular icons for images and videos Use circular icons + Follow battery saver + If selected and the battery saver mode is turned on, the theme changes to dark theme Back navigation Enables custom back navigation at top of the list Details diff --git a/app/src/main/res/xml/appearance_prefs.xml b/app/src/main/res/xml/appearance_prefs.xml index f53e8006fb..ef2c5e4042 100644 --- a/app/src/main/res/xml/appearance_prefs.xml +++ b/app/src/main/res/xml/appearance_prefs.xml @@ -4,7 +4,12 @@ - + () - Assert.assertEquals(AppTheme.LIGHT, AppTheme.getTheme(context, AppTheme.LIGHT_INDEX)) + Assert.assertEquals(AppTheme.LIGHT, AppTheme.getTheme(AppTheme.LIGHT_INDEX)) + + Assert.assertEquals(AppTheme.DARK, AppTheme.getTheme(AppTheme.DARK_INDEX)) - Assert.assertEquals(AppTheme.DARK, AppTheme.getTheme(context, AppTheme.DARK_INDEX)) + Assert.assertEquals(AppTheme.TIMED, AppTheme.getTheme(AppTheme.TIME_INDEX)) - Assert.assertEquals(AppTheme.TIMED, AppTheme.getTheme(context, AppTheme.TIME_INDEX)) + Assert.assertEquals(AppTheme.BLACK, AppTheme.getTheme(AppTheme.BLACK_INDEX)) - Assert.assertEquals(AppTheme.BLACK, AppTheme.getTheme(context, AppTheme.BLACK_INDEX)) + Assert.assertEquals(AppTheme.SYSTEM, AppTheme.getTheme(AppTheme.SYSTEM_INDEX)) } /** @@ -64,22 +69,18 @@ class AppThemeTest { fun testMaterialDialogTheme() { val context = ApplicationProvider.getApplicationContext() - val getMaterialDialogTheme = { apptheme: Int -> - AppTheme.getTheme(context, apptheme).getMaterialDialogTheme(context) - } + Assert.assertEquals(Theme.LIGHT, getMaterialDialogTheme(AppTheme.LIGHT_INDEX, context)) - Assert.assertEquals(Theme.LIGHT, getMaterialDialogTheme(AppTheme.LIGHT_INDEX)) - - Assert.assertEquals(Theme.DARK, getMaterialDialogTheme(AppTheme.DARK_INDEX)) + Assert.assertEquals(Theme.DARK, getMaterialDialogTheme(AppTheme.DARK_INDEX, context)) val hour = Calendar.getInstance()[Calendar.HOUR_OF_DAY] if (hour <= 6 || hour >= 18) { - Assert.assertEquals(Theme.DARK, getMaterialDialogTheme(AppTheme.TIME_INDEX)) + Assert.assertEquals(Theme.DARK, getMaterialDialogTheme(AppTheme.TIME_INDEX, context)) } else { - Assert.assertEquals(Theme.LIGHT, getMaterialDialogTheme(AppTheme.TIME_INDEX)) + Assert.assertEquals(Theme.LIGHT, getMaterialDialogTheme(AppTheme.TIME_INDEX, context)) } - Assert.assertEquals(Theme.DARK, getMaterialDialogTheme(AppTheme.BLACK_INDEX)) + Assert.assertEquals(Theme.DARK, getMaterialDialogTheme(AppTheme.BLACK_INDEX, context)) } /** @@ -88,33 +89,182 @@ class AppThemeTest { @Test fun testSimpleTheme() { val context = ApplicationProvider.getApplicationContext() - val mask = context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK - val isNightMode = mask == Configuration.UI_MODE_NIGHT_YES Assert.assertEquals( AppTheme.LIGHT, - AppTheme.getTheme(context, AppTheme.LIGHT_INDEX).getSimpleTheme(isNightMode) + getSimpleTheme(AppTheme.LIGHT_INDEX, context) ) Assert.assertEquals( AppTheme.DARK, - AppTheme.getTheme(context, AppTheme.DARK_INDEX).getSimpleTheme(isNightMode) + getSimpleTheme(AppTheme.DARK_INDEX, context) ) val hour = Calendar.getInstance()[Calendar.HOUR_OF_DAY] if (hour <= 6 || hour >= 18) { Assert.assertEquals( AppTheme.DARK, - AppTheme.getTheme(context, AppTheme.TIME_INDEX).getSimpleTheme(isNightMode) + getSimpleTheme(AppTheme.TIME_INDEX, context) ) } else Assert.assertEquals( AppTheme.LIGHT, - AppTheme.getTheme(context, AppTheme.TIME_INDEX).getSimpleTheme(isNightMode) + getSimpleTheme(AppTheme.TIME_INDEX, context) + ) + + Assert.assertEquals( + AppTheme.BLACK, + getSimpleTheme(AppTheme.BLACK_INDEX, context) + ) + } + + /** + * Tests the "System" theme when night mode is on + */ + @Test + @Config(qualifiers = "night") + fun testSimpleSystemThemeNightModeOn() { + val context = ApplicationProvider.getApplicationContext() + + Assert.assertEquals(AppTheme.DARK, getSimpleTheme(AppTheme.SYSTEM_INDEX, context)) + } + + /** + * Tests the "System" theme when night mode is off + */ + @Test + @Config(qualifiers = "notnight") + fun testSimpleSystemThemeNightModeOff() { + val context = ApplicationProvider.getApplicationContext() + + Assert.assertEquals(AppTheme.LIGHT, getSimpleTheme(AppTheme.SYSTEM_INDEX, context)) + } + + /** + * Tests the themes with "Follow Battery Saver" option selected when battery saver is on + */ + @Test + @Config( + shadows = [ShadowPowerManager::class, ShadowMultiDex::class], + qualifiers = "notnight", + minSdk = Build.VERSION_CODES.LOLLIPOP + ) + fun testSimpleAppThemeWithFollowBatterySaverAndBatterySaverOn() { + val context = ApplicationProvider.getApplicationContext() + + setUpForFollowBatterySaverMode(context, true) + + val canBeLightThemes = AppTheme.values().filter { it.canBeLight() } + + for (lightTheme in canBeLightThemes) { + Assert.assertEquals( + "For $lightTheme: ", + AppTheme.DARK, + getSimpleTheme(lightTheme.id, context) + ) + } + + Assert.assertEquals( + AppTheme.DARK, + getSimpleTheme(AppTheme.DARK_INDEX, context) ) Assert.assertEquals( AppTheme.BLACK, - AppTheme.getTheme(context, AppTheme.BLACK_INDEX).getSimpleTheme(isNightMode) + getSimpleTheme(AppTheme.BLACK_INDEX, context) ) } + + /** + * Tests the themes with "Follow Battery Saver" option selected when battery saver is off + */ + @Test + @Config( + shadows = [ShadowPowerManager::class, ShadowMultiDex::class], + qualifiers = "notnight", + minSdk = Build.VERSION_CODES.LOLLIPOP + ) + fun testSimpleAppThemeWithFollowBatterySaverAndBatterySaverOff() { + val context = ApplicationProvider.getApplicationContext() + + setUpForFollowBatterySaverMode(context, false) + + // Behavior should be like in testSimpleTheme + testSimpleTheme() + } + + /** + * Tests the material dialog theme with "Follow Battery Saver" option selected when battery saver is on + */ + @Test + @Config( + shadows = [ShadowPowerManager::class, ShadowMultiDex::class], + qualifiers = "notnight", + minSdk = Build.VERSION_CODES.LOLLIPOP + ) + fun testMaterialDialogThemeWithFollowBatterySaverAndBatterySaverOn() { + val context = ApplicationProvider.getApplicationContext() + + setUpForFollowBatterySaverMode(context, true) + + val canBeLightThemes = AppTheme.values().filter { it.canBeLight() } + + for (lightTheme in canBeLightThemes) { + Assert.assertEquals( + "For $lightTheme: ", + Theme.DARK, + getMaterialDialogTheme(lightTheme.id, context) + ) + } + + Assert.assertEquals( + Theme.DARK, + getMaterialDialogTheme(AppTheme.DARK_INDEX, context) + ) + + Assert.assertEquals( + Theme.DARK, + getMaterialDialogTheme(AppTheme.BLACK_INDEX, context) + ) + } + + /** + * Tests the material dialog theme with "Follow Battery Saver" option selected when battery saver is off + */ + @Test + @Config( + shadows = [ShadowPowerManager::class, ShadowMultiDex::class], + qualifiers = "notnight", + minSdk = Build.VERSION_CODES.LOLLIPOP + ) + fun testMaterialDialogThemeWithFollowBatterySaverAndBatterySaverOff() { + val context = ApplicationProvider.getApplicationContext() + + setUpForFollowBatterySaverMode(context, false) + + // Should have the same behavior + testMaterialDialogTheme() + } + + /** Shortcut to get the material dialog theme from the theme index */ + private fun getMaterialDialogTheme(apptheme: Int, context: Context): Theme = + AppTheme.getTheme(apptheme).getMaterialDialogTheme(context) + + /** Shortcut to get the simple theme from the theme index */ + private fun getSimpleTheme(index: Int, context: Context): AppTheme = + AppTheme.getTheme(index).getSimpleTheme(context) + + /** Sets the battery saver mode to [batterySaverOn] and the "Follow battery saver" option to true */ + private fun setUpForFollowBatterySaverMode(context: Context, batterySaverOn: Boolean) { + // Set Battery saver mode to given state `batterySaverOn` + val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager + val shadowPowerManager = Shadows.shadowOf(powerManager) + shadowPowerManager.setIsPowerSaveMode(batterySaverOn) + + // Set follow battery saver preference to true + val preferences = PreferenceManager.getDefaultSharedPreferences(context) + preferences + .edit() + .putBoolean(PreferencesConstants.FRAGMENT_FOLLOW_BATTERY_SAVER, true) + .apply() + } }