diff options
| author | 2018-10-02 11:28:39 -0700 | |
|---|---|---|
| committer | 2018-11-13 09:29:36 -0800 | |
| commit | 04b98338f7c9388889da08b091bf77b5654dc144 (patch) | |
| tree | c48107d408d865b2056b270ee838674404e051f2 | |
| parent | 1c6deebbbfe2d5edb2f7292660e23b8191d5d768 (diff) | |
Create new battery saver mode
Creates the concept of a "dynamic" battery saver mode controlled by
an external input in the framework. This mode behaves similarly to the
current automatic percentage based battery saver minus the fact that
the trigger is not static and that we might want to disable it at
a different level than when it was triggered.
Test: atest BatterySaverStateMachineTest
Bug: 111450127
Change-Id: Iac0de4f8f0336ed8870d2397574bd8885b7aa6a2
9 files changed, 353 insertions, 21 deletions
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index f84079222536..4b3fbe661e6e 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -11811,14 +11811,93 @@ public final class Settings { /** * Battery level [1-100] at which low power mode automatically turns on. - * If 0, it will not automatically turn on. + * Pre-Q If 0, it will not automatically turn on. Q and newer it will only automatically + * turn on if the {@link #AUTOMATIC_POWER_SAVER_MODE} setting is also set to + * {@link #AUTOMATIC_POWER_SAVER_MODE_PERCENTAGE}. + * + * @see #AUTOMATIC_POWER_SAVER_MODE * @hide */ public static final String LOW_POWER_MODE_TRIGGER_LEVEL = "low_power_trigger_level"; + private static final Validator LOW_POWER_MODE_TRIGGER_LEVEL_VALIDATOR = new SettingsValidators.InclusiveIntegerRangeValidator(0, 100); + /** + * Indicates automatic battery saver toggling by the system will be based on battery level. + * + * @hide + */ + public static final int AUTOMATIC_POWER_SAVER_MODE_PERCENTAGE = 0; + + /** + * Indicates automatic battery saver toggling by the system will be based on + * {@link #DYNAMIC_POWER_SAVINGS_ENABLED} and + * {@link #DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD}. + * + * @see #DYNAMIC_POWER_SAVINGS_ENABLED + * + * @hide + */ + public static final int AUTOMATIC_POWER_SAVER_MODE_DYNAMIC = 1; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = { + AUTOMATIC_POWER_SAVER_MODE_PERCENTAGE, + AUTOMATIC_POWER_SAVER_MODE_DYNAMIC + + }) + public @interface AutoPowerSaverMode{} + + /** + * Whether battery saver is currently set to trigger based on percentage, dynamic power + * savings trigger, or none. See {@link AutoPowerSaverMode} for accepted values. + * + * @hide + */ + public static final String AUTOMATIC_POWER_SAVER_MODE = "automatic_power_saver_mode"; + + private static final Validator AUTOMATIC_POWER_SAVER_MODE_VALIDATOR = + new SettingsValidators.DiscreteValueValidator(new String[] {"0", "1"}); + + /** + * The percentage the system should consider itself safe at if the dynamic power savings was + * previously enabled and it enacted measures to reduce power consumption. Value is + * an integer representing a battery level. + * + * <p>This value is used to set an explicit stopping point for dynamic power savings + * functionality so that the {@link #DYNAMIC_POWER_SAVINGS_ENABLED} setting remains a signal + * for the system rather than becoming an on/off switch itself. + * @hide + */ + public static final String DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD = + "dynamic_power_savings_disable_threshold"; + + /** + * A signal to the system which an app can update which indicates that + * the user will be in a battery critical situation in the near future. + * Only apps with the {@link android.Manifest.permission.POWER_SAVER} permission may modify + * this setting. + * + * <p>When enabled, the system may enact various measures for reducing power consumption in + * order to help ensure that the user will make it to their next charging point. The most + * visible of these will be the automatic enabling of battery saver if the user has set + * {@link #AUTOMATIC_POWER_SAVER_MODE} to {@link #AUTOMATIC_POWER_SAVER_MODE_DYNAMIC}. Note + * that this is NOT an on/off switch for all these features, but rather a hint for the + * system to consider enacting these power saving features, some of which have additional + * logic around when to activate based on this signal. + * + * <p>Supported values: + * <ul> + * <li>0 = Disabled + * <li>1 = Enabled + * </ul> + * @see #DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD + * @hide + */ + public static final String DYNAMIC_POWER_SAVINGS_ENABLED = "dynamic_power_savings_enabled"; /** * The max value for {@link #LOW_POWER_MODE_TRIGGER_LEVEL}. If this setting is not set @@ -12742,6 +12821,7 @@ public final class Settings { VALIDATORS.put(LOW_POWER_MODE_TRIGGER_LEVEL, LOW_POWER_MODE_TRIGGER_LEVEL_VALIDATOR); VALIDATORS.put(LOW_POWER_MODE_TRIGGER_LEVEL_MAX, LOW_POWER_MODE_TRIGGER_LEVEL_VALIDATOR); + VALIDATORS.put(AUTOMATIC_POWER_SAVER_MODE, AUTOMATIC_POWER_SAVER_MODE_VALIDATOR); VALIDATORS.put(BLUETOOTH_ON, BLUETOOTH_ON_VALIDATOR); VALIDATORS.put(PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_VALIDATOR); VALIDATORS.put(PRIVATE_DNS_SPECIFIER, PRIVATE_DNS_SPECIFIER_VALIDATOR); diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto index 72892fa07381..7de8020c4d32 100644 --- a/core/proto/android/providers/settings/global.proto +++ b/core/proto/android/providers/settings/global.proto @@ -332,6 +332,18 @@ message GlobalSettingsProto { } optional Dropbox dropbox = 46; + message DynamicPowerSavings { + option (android.msg_privacy).dest = DEST_EXPLICIT; + + // When to auto disable interventions that were triggered due to + // {@link #DYNAMIC_POWER_SAVINGS_ENABLED}. Value is a percentage indicating + // a battery level. + optional SettingProto disable_threshold = 1 [ (android.privacy).dest = DEST_AUTOMATIC]; + // Whether dynamic power savings based behaviors should be running or not. + optional SettingProto enabled = 2 [ (android.privacy).dest = DEST_AUTOMATIC]; + } + optional DynamicPowerSavings dynamic_power_savings = 143; + message Emergency { option (android.msg_privacy).dest = DEST_EXPLICIT; @@ -491,6 +503,9 @@ message GlobalSettingsProto { // The max value for {@link #LOW_POWER_MODE_TRIGGER_LEVEL}. If this setting // is not set or the value is 0, the default max will be used. optional SettingProto trigger_level_max = 3 [ (android.privacy).dest = DEST_AUTOMATIC ]; + // Whether automatic battery saver mode is controlled via percentage, + // {@link #DYNAMIC_POWER_SAVINGS_ENABLED} or disabled. + optional SettingProto automatic_power_saver_mode = 4 [ (android.privacy).dest = DEST_AUTOMATIC]; } optional LowPowerMode low_power_mode = 70; @@ -972,5 +987,5 @@ message GlobalSettingsProto { // Please insert fields in alphabetical order and group them into messages // if possible (to avoid reaching the method limit). - // Next tag = 143; + // Next tag = 144; } diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 6ae183b99942..26f3370f0dc5 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -3531,6 +3531,9 @@ <!-- Whether or not battery saver should be "sticky" when manually enabled. --> <bool name="config_batterySaverStickyBehaviourDisabled">false</bool> + <!-- Config flag to track default disable threshold for Dynamic power savings enabled battery saver. --> + <integer name="config_dynamicPowerSavingsDefaultDisableThreshold">80</integer> + <!-- Model of potentially misprovisioned devices. If none is specified in an overlay, an empty string is passed in. --> <string name="config_misprovisionedDeviceModel" translatable="false"></string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 6276884801a4..4eb723eb973d 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3436,6 +3436,7 @@ <java-symbol type="integer" name="config_lowBatteryAutoTriggerDefaultLevel" /> <java-symbol type="bool" name="config_batterySaverStickyBehaviourDisabled" /> + <java-symbol type="integer" name="config_dynamicPowerSavingsDefaultDisableThreshold" /> <!-- For car devices --> <java-symbol type="string" name="car_loading_profile" /> diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 727f3998b03c..8c91c370fcf6 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -124,6 +124,7 @@ public class SettingsBackupTest { Settings.Global.AUTOFILL_LOGGING_LEVEL, Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE, Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS, + Settings.Global.AUTOMATIC_POWER_SAVER_MODE, Settings.Global.BATTERY_DISCHARGE_DURATION_THRESHOLD, Settings.Global.BATTERY_DISCHARGE_THRESHOLD, Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS, @@ -235,6 +236,8 @@ public class SettingsBackupTest { Settings.Global.ENABLE_DELETION_HELPER_NO_THRESHOLD_TOGGLE, Settings.Global.ENABLE_DISKSTATS_LOGGING, Settings.Global.ENABLE_EPHEMERAL_FEATURE, + Settings.Global.DYNAMIC_POWER_SAVINGS_ENABLED, + Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS, Settings.Global.ENHANCED_4G_MODE_ENABLED, Settings.Global.EPHEMERAL_COOKIE_MAX_SIZE_BYTES, diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index 448a96301990..cbb6e82c8f86 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -572,6 +572,15 @@ class SettingsProtoDumpUtil { GlobalSettingsProto.Dropbox.SETTINGS); p.end(dropboxToken); + final long dynamicPowerSavingsToken = p.start(GlobalSettingsProto.DYNAMIC_POWER_SAVINGS); + dumpSetting(s, p, + Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, + GlobalSettingsProto.DynamicPowerSavings.DISABLE_THRESHOLD); + dumpSetting(s, p, + Settings.Global.DYNAMIC_POWER_SAVINGS_ENABLED, + GlobalSettingsProto.DynamicPowerSavings.ENABLED); + p.end(dynamicPowerSavingsToken); + final long emergencyToken = p.start(GlobalSettingsProto.EMERGENCY); dumpSetting(s, p, Settings.Global.EMERGENCY_TONE, @@ -794,6 +803,9 @@ class SettingsProtoDumpUtil { dumpSetting(s, p, Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL_MAX, GlobalSettingsProto.LowPowerMode.TRIGGER_LEVEL_MAX); + dumpSetting(s, p, + Settings.Global.AUTOMATIC_POWER_SAVER_MODE, + GlobalSettingsProto.LowPowerMode.AUTOMATIC_POWER_SAVER_MODE); p.end(lpmToken); dumpSetting(s, p, diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java index 5569822300b9..6400c88b320f 100644 --- a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java +++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java @@ -93,8 +93,8 @@ public class BatterySaverController implements BatterySaverPolicyListener { */ private final Plugin[] mPlugins; - public static final int REASON_AUTOMATIC_ON = 0; - public static final int REASON_AUTOMATIC_OFF = 1; + public static final int REASON_PERCENTAGE_AUTOMATIC_ON = 0; + public static final int REASON_PERCENTAGE_AUTOMATIC_OFF = 1; public static final int REASON_MANUAL_ON = 2; public static final int REASON_MANUAL_OFF = 3; public static final int REASON_STICKY_RESTORE = 4; @@ -102,6 +102,8 @@ public class BatterySaverController implements BatterySaverPolicyListener { public static final int REASON_POLICY_CHANGED = 6; public static final int REASON_PLUGGED_IN = 7; public static final int REASON_SETTING_CHANGED = 8; + public static final int REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON = 9; + public static final int REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_OFF = 10; /** * Plugin interface. All methods are guaranteed to be called on the same (handler) thread. diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java index 20ceed43d27d..6acaf0e3a1e8 100644 --- a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java +++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java @@ -87,6 +87,11 @@ public class BatterySaverStateMachine { /** Config flag to track if battery saver's sticky behaviour is disabled. */ private final boolean mBatterySaverStickyBehaviourDisabled; + /** Config flag to track default disable threshold for Dynamic Power Savings enabled battery + * saver. */ + @GuardedBy("mLock") + private final int mDynamicPowerSavingsDefaultDisableThreshold; + /** * Previously known value of Global.LOW_POWER_MODE_TRIGGER_LEVEL. * (Currently only used in dumpsys.) @@ -94,6 +99,23 @@ public class BatterySaverStateMachine { @GuardedBy("mLock") private int mSettingBatterySaverTriggerThreshold; + /** Previously known value of Global.AUTOMATIC_POWER_SAVER_MODE. */ + @GuardedBy("mLock") + private int mSettingAutomaticBatterySaver; + + /** When to disable battery saver again if it was enabled due to an external suggestion. + * Corresponds to Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD. + */ + @GuardedBy("mLock") + private int mDynamicPowerSavingsDisableThreshold; + + /** + * Whether we've received a suggestion that battery saver should be on from an external app. + * Updates when Global.DYNAMIC_POWER_SAVINGS_ENABLED changes. + */ + @GuardedBy("mLock") + private boolean mDynamicPowerSavingsBatterySaver; + /** * Whether BS has been manually disabled while the battery level is low, in which case we * shouldn't auto re-enable it until the battery level is not low. @@ -130,13 +152,15 @@ public class BatterySaverStateMachine { mBatterySaverStickyBehaviourDisabled = mContext.getResources().getBoolean( com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled); + mDynamicPowerSavingsDefaultDisableThreshold = mContext.getResources().getInteger( + com.android.internal.R.integer.config_dynamicPowerSavingsDefaultDisableThreshold); } private boolean isBatterySaverEnabled() { return mBatterySaverController.isEnabled(); } - private boolean isAutoBatterySaverConfigured() { + private boolean isAutoBatterySaverConfiguredLocked() { return mSettingBatterySaverTriggerThreshold > 0; } @@ -165,6 +189,15 @@ public class BatterySaverStateMachine { cr.registerContentObserver(Settings.Global.getUriFor( Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL), false, mSettingsObserver, UserHandle.USER_SYSTEM); + cr.registerContentObserver(Settings.Global.getUriFor( + Global.AUTOMATIC_POWER_SAVER_MODE), + false, mSettingsObserver, UserHandle.USER_SYSTEM); + cr.registerContentObserver(Settings.Global.getUriFor( + Global.DYNAMIC_POWER_SAVINGS_ENABLED), + false, mSettingsObserver, UserHandle.USER_SYSTEM); + cr.registerContentObserver(Settings.Global.getUriFor( + Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD), + false, mSettingsObserver, UserHandle.USER_SYSTEM); synchronized (mLock) { @@ -202,11 +235,20 @@ public class BatterySaverStateMachine { Settings.Global.LOW_POWER_MODE, 0) != 0; final boolean lowPowerModeEnabledSticky = getGlobalSetting( Settings.Global.LOW_POWER_MODE_STICKY, 0) != 0; + final boolean dynamicPowerSavingsBatterySaver = getGlobalSetting( + Global.DYNAMIC_POWER_SAVINGS_ENABLED, 0) != 0; final int lowPowerModeTriggerLevel = getGlobalSetting( Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0); + final int automaticBatterySaver = getGlobalSetting( + Global.AUTOMATIC_POWER_SAVER_MODE, + Settings.Global.AUTOMATIC_POWER_SAVER_MODE_PERCENTAGE); + final int dynamicPowerSavingsDisableThreshold = getGlobalSetting( + Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, + mDynamicPowerSavingsDefaultDisableThreshold); setSettingsLocked(lowPowerModeEnabled, lowPowerModeEnabledSticky, - lowPowerModeTriggerLevel); + lowPowerModeTriggerLevel, automaticBatterySaver, dynamicPowerSavingsBatterySaver, + dynamicPowerSavingsDisableThreshold); } /** @@ -218,11 +260,16 @@ public class BatterySaverStateMachine { @GuardedBy("mLock") @VisibleForTesting void setSettingsLocked(boolean batterySaverEnabled, boolean batterySaverEnabledSticky, - int batterySaverTriggerThreshold) { + int batterySaverTriggerThreshold, int automaticBatterySaver, + boolean dynamicPowerSavingsBatterySaver, int dynamicPowerSavingsDisableThreshold) { if (DEBUG) { Slog.d(TAG, "setSettings: enabled=" + batterySaverEnabled + " sticky=" + batterySaverEnabledSticky - + " threshold=" + batterySaverTriggerThreshold); + + " threshold=" + batterySaverTriggerThreshold + + " automaticBatterySaver=" + automaticBatterySaver + + " dynamicPowerSavingsBatterySaver=" + dynamicPowerSavingsBatterySaver + + " dynamicPowerSavingsDisableThreshold=" + + dynamicPowerSavingsDisableThreshold); } mSettingsLoaded = true; @@ -232,14 +279,23 @@ public class BatterySaverStateMachine { mSettingBatterySaverEnabledSticky != batterySaverEnabledSticky; final boolean thresholdChanged = mSettingBatterySaverTriggerThreshold != batterySaverTriggerThreshold; - - if (!(enabledChanged || stickyChanged || thresholdChanged)) { + final boolean automaticModeChanged = mSettingAutomaticBatterySaver != automaticBatterySaver; + final boolean dynamicPowerSavingsThresholdChanged = + mDynamicPowerSavingsDisableThreshold != dynamicPowerSavingsDisableThreshold; + final boolean dynamicPowerSavingsBatterySaverChanged = + mDynamicPowerSavingsBatterySaver != dynamicPowerSavingsBatterySaver; + + if (!(enabledChanged || stickyChanged || thresholdChanged || automaticModeChanged + || dynamicPowerSavingsThresholdChanged || dynamicPowerSavingsBatterySaverChanged)) { return; } mSettingBatterySaverEnabled = batterySaverEnabled; mSettingBatterySaverEnabledSticky = batterySaverEnabledSticky; mSettingBatterySaverTriggerThreshold = batterySaverTriggerThreshold; + mSettingAutomaticBatterySaver = automaticBatterySaver; + mDynamicPowerSavingsDisableThreshold = dynamicPowerSavingsDisableThreshold; + mDynamicPowerSavingsBatterySaver = dynamicPowerSavingsBatterySaver; if (thresholdChanged) { // To avoid spamming the event log, we throttle logging here. @@ -299,12 +355,20 @@ public class BatterySaverStateMachine { + " mIsBatteryLevelLow=" + mIsBatteryLevelLow + " mBatterySaverSnoozing=" + mBatterySaverSnoozing + " mIsPowered=" + mIsPowered + + " mSettingAutomaticBatterySaver=" + mSettingAutomaticBatterySaver + " mSettingBatterySaverEnabledSticky=" + mSettingBatterySaverEnabledSticky); } if (!(mBootCompleted && mSettingsLoaded && mBatteryStatusSet)) { return; // Not fully initialized yet. } - if (!mIsBatteryLevelLow) { + final boolean percetageLow = + mSettingAutomaticBatterySaver + == Settings.Global.AUTOMATIC_POWER_SAVER_MODE_PERCENTAGE + && mIsBatteryLevelLow; + final boolean dynamicPowerSavingsLow = + mSettingAutomaticBatterySaver == Settings.Global.AUTOMATIC_POWER_SAVER_MODE_DYNAMIC + && mBatteryLevel <= mDynamicPowerSavingsDisableThreshold; + if (!percetageLow && !dynamicPowerSavingsLow) { updateSnoozingLocked(false, "Battery not low"); } if (mIsPowered) { @@ -319,17 +383,32 @@ public class BatterySaverStateMachine { BatterySaverController.REASON_STICKY_RESTORE, "Sticky restore"); - } else if (mIsBatteryLevelLow) { - if (!mBatterySaverSnoozing && isAutoBatterySaverConfigured()) { + } else if (mSettingAutomaticBatterySaver + == Settings.Global.AUTOMATIC_POWER_SAVER_MODE_PERCENTAGE + && isAutoBatterySaverConfiguredLocked()) { + if (mIsBatteryLevelLow && !mBatterySaverSnoozing) { enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ false, - BatterySaverController.REASON_AUTOMATIC_ON, - "Auto ON"); + BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_ON, + "Percentage Auto ON"); + } else { + // Battery not low + enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false, + BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_OFF, + "Percentage Auto OFF"); + } + } else if (mSettingAutomaticBatterySaver + == Settings.Global.AUTOMATIC_POWER_SAVER_MODE_DYNAMIC) { + if (mBatteryLevel >= mDynamicPowerSavingsDisableThreshold) { + enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false, + BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_OFF, + "Dynamic Power Savings Auto OFF"); + } else if (mDynamicPowerSavingsBatterySaver && !mBatterySaverSnoozing) { + enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ false, + BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON, + "Dynamic Power Savings Auto ON"); } - } else { // Battery not low - enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false, - BatterySaverController.REASON_AUTOMATIC_OFF, - "Auto OFF"); } + // do nothing if automatic battery saver mode = PERCENTAGE and low warning threshold = 0% } /** @@ -383,7 +462,15 @@ public class BatterySaverStateMachine { // When battery saver is disabled manually (while battery saver is enabled) // when the battery level is low, we "snooze" BS -- i.e. disable auto battery saver. // We resume auto-BS once the battery level is not low, or the device is plugged in. - if (isBatterySaverEnabled() && mIsBatteryLevelLow) { + final boolean percetageLow = + mSettingAutomaticBatterySaver + == Settings.Global.AUTOMATIC_POWER_SAVER_MODE_PERCENTAGE + && mIsBatteryLevelLow; + final boolean dynamicPowerSavingsLow = + mSettingAutomaticBatterySaver + == Settings.Global.AUTOMATIC_POWER_SAVER_MODE_DYNAMIC + && mBatteryLevel <= mDynamicPowerSavingsDisableThreshold; + if (isBatterySaverEnabled() && (percetageLow || dynamicPowerSavingsLow)) { updateSnoozingLocked(true, "Manual snooze"); } } diff --git a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java index fd04970d50fe..f31ca55d422e 100644 --- a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java +++ b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java @@ -115,7 +115,12 @@ public class BatterySaverStateMachineTest { mTarget.setSettingsLocked( mPersistedState.global.getOrDefault(Global.LOW_POWER_MODE, 0) != 0, mPersistedState.global.getOrDefault(Global.LOW_POWER_MODE_STICKY, 0) != 0, - mDevice.getLowPowerModeTriggerLevel()); + mDevice.getLowPowerModeTriggerLevel(), + mPersistedState.global.getOrDefault(Global.AUTOMATIC_POWER_SAVER_MODE, 0), + mPersistedState.global.getOrDefault( + Global.DYNAMIC_POWER_SAVINGS_ENABLED, 0) != 0, + mPersistedState.global.getOrDefault( + Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 100)); } public void putGlobalSetting(String key, int value) { @@ -174,6 +179,9 @@ public class BatterySaverStateMachineTest { when(mMockResources.getBoolean( com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled)) .thenReturn(false); + when(mMockResources.getInteger( + com.android.internal.R.integer.config_dynamicPowerSavingsDefaultDisableThreshold)) + .thenReturn(80); mPersistedState = new DevicePersistedState(); initDevice(); @@ -303,6 +311,7 @@ public class BatterySaverStateMachineTest { @Test public void testAutoBatterySaver() { mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50); + mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVER_MODE, 0); assertEquals(false, mDevice.batterySaverEnabled); assertEquals(100, mPersistedState.batteryLevel); @@ -515,6 +524,7 @@ public class BatterySaverStateMachineTest { .thenReturn(true); initDevice(); mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50); + mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVER_MODE, 0); mTarget.setBatterySaverEnabledManually(true); @@ -626,4 +636,123 @@ public class BatterySaverStateMachineTest { assertEquals(90, mPersistedState.batteryLevel); assertEquals(false, mPersistedState.batteryLow); } + + @Test + public void testAutoBatterySaver_smartBatterySaverEnabled() { + mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 50); + mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVER_MODE, 1); + mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_ENABLED, 0); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(100, mPersistedState.batteryLevel); + + mDevice.setBatteryLevel(90); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(90, mPersistedState.batteryLevel); + + mDevice.setBatteryLevel(51); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(51, mPersistedState.batteryLevel); + + // Hit the threshold. BS should be disabled since dynamic power savings still off + mDevice.setBatteryLevel(50); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(50, mPersistedState.batteryLevel); + + // dynamic power savings comes on, battery saver should turn on + mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_ENABLED, 1); + mDevice.setBatteryLevel(40); + + assertEquals(true, mDevice.batterySaverEnabled); + assertEquals(40, mPersistedState.batteryLevel); + + mDevice.setPowered(true); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(40, mPersistedState.batteryLevel); + + mDevice.setPowered(false); + + assertEquals(true, mDevice.batterySaverEnabled); + assertEquals(40, mPersistedState.batteryLevel); + + mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze. + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(40, mPersistedState.batteryLevel); + + mDevice.setBatteryLevel(30); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(30, mPersistedState.batteryLevel); + + // Plug in and out, snooze will reset. + mDevice.setPowered(true); + mDevice.setPowered(false); + + assertEquals(true, mDevice.batterySaverEnabled); + assertEquals(30, mPersistedState.batteryLevel); + + mDevice.setPowered(true); + mDevice.setBatteryLevel(60); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(60, mPersistedState.batteryLevel); + + mDevice.setPowered(false); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(60, mPersistedState.batteryLevel); + + mDevice.setBatteryLevel(40); + + assertEquals(true, mDevice.batterySaverEnabled); + assertEquals(40, mPersistedState.batteryLevel); + + mDevice.setBatteryLevel(70); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(70, mPersistedState.batteryLevel); + + // Bump up the threshold. + mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 71); + mDevice.setBatteryLevel(mPersistedState.batteryLevel); + + // changes are only registered if some battery level changed + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(70, mPersistedState.batteryLevel); + + mDevice.setBatteryLevel(69); + + assertEquals(true, mDevice.batterySaverEnabled); + assertEquals(69, mPersistedState.batteryLevel); + + // Then down. + mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 60); + mDevice.setBatteryLevel(mPersistedState.batteryLevel); + + // changes are only registered if battery level changed + assertEquals(true, mDevice.batterySaverEnabled); + assertEquals(69, mPersistedState.batteryLevel); + + mDevice.setBatteryLevel(68); + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(68, mPersistedState.batteryLevel); + + // Reboot in low state -> automatically enable BS. + mDevice.setPowered(false); + mDevice.setBatteryLevel(30); + mTarget.setBatterySaverEnabledManually(false); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(30, mPersistedState.batteryLevel); + + initDevice(); + + assertEquals(true, mDevice.batterySaverEnabled); + assertEquals(30, mPersistedState.batteryLevel); + } } |