summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/provider/Settings.java32
-rw-r--r--core/proto/android/providers/settings/global.proto10
-rw-r--r--core/proto/android/server/powermanagerservice.proto8
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java22
-rw-r--r--services/core/java/com/android/server/power/batterysaver/BatterySaverController.java1
-rw-r--r--services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java125
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java (renamed from services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java)238
7 files changed, 376 insertions, 60 deletions
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 39c4266e4cf8..3fac9385e31f 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -12053,6 +12053,31 @@ public final class Settings {
public static final String LOW_POWER_MODE_STICKY = "low_power_sticky";
/**
+ * When a device is unplugged from a changer (or is rebooted), do not re-activate battery
+ * saver even if {@link #LOW_POWER_MODE_STICKY} is 1, if the battery level is equal to or
+ * above this threshold.
+ *
+ * @hide
+ */
+ public static final String LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL =
+ "low_power_sticky_auto_disable_level";
+
+ private static final Validator LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL_VALIDATOR =
+ new SettingsValidators.InclusiveIntegerRangeValidator(0, 100);
+
+ /**
+ * Whether sticky battery saver should be deactivated once the battery level has reached the
+ * threshold specified by {@link #LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL}.
+ *
+ * @hide
+ */
+ public static final String LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED =
+ "low_power_sticky_auto_disable_enabled";
+
+ private static final Validator LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED_VALIDATOR =
+ new SettingsValidators.DiscreteValueValidator(new String[] {"0", "1"});
+
+ /**
* Battery level [1-100] at which low power mode automatically turns 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
@@ -12064,7 +12089,6 @@ public final class Settings {
*/
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);
@@ -13055,6 +13079,8 @@ public final class Settings {
ENCODED_SURROUND_OUTPUT,
ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS,
LOW_POWER_MODE_TRIGGER_LEVEL,
+ LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED,
+ LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL,
BLUETOOTH_ON,
PRIVATE_DNS_MODE,
PRIVATE_DNS_SPECIFIER,
@@ -13093,6 +13119,10 @@ public final class Settings {
VALIDATORS.put(ENCODED_SURROUND_OUTPUT, ENCODED_SURROUND_OUTPUT_VALIDATOR);
VALIDATORS.put(ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS,
ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS_VALIDATOR);
+ VALIDATORS.put(LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL,
+ LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL_VALIDATOR);
+ VALIDATORS.put(LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED,
+ LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED_VALIDATOR);
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);
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index cc5aa20258ce..30362cc01a51 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -528,6 +528,16 @@ message GlobalSettingsProto {
// 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];
+ // If 1, battery saver (low_power_mode) will be re-activated after the device is
+ // unplugged from a charger or rebooted.
+ optional SettingProto sticky_enabled = 5;
+ // Whether sticky battery saver should be deactivated once the battery level has reached the
+ // threshold specified by sticky_disable_level.
+ optional SettingProto sticky_auto_disable_enabled = 6;
+ // When a device is unplugged from a changer (or is rebooted), do not re-activate battery
+ // saver even if {@link #LOW_POWER_MODE_STICKY} is 1, if the battery level is equal to or
+ // above this threshold.
+ optional SettingProto sticky_auto_disable_level = 7;
}
optional LowPowerMode low_power_mode = 70;
diff --git a/core/proto/android/server/powermanagerservice.proto b/core/proto/android/server/powermanagerservice.proto
index cee556a7b67f..af0a942dea2f 100644
--- a/core/proto/android/server/powermanagerservice.proto
+++ b/core/proto/android/server/powermanagerservice.proto
@@ -350,4 +350,12 @@ message BatterySaverStateMachineProto {
// The value of Global.LOW_POWER_MODE_TRIGGER_LEVEL. This is a cached value, so it could
// be slightly different from what's in GlobalSettingsProto.LowPowerMode.
optional int32 setting_battery_saver_trigger_threshold = 11;
+
+ // The value of Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED. This is a cached value, so
+ // it could be slightly different from what's in GlobalSettingsProto.LowPowerMode.
+ optional bool setting_battery_saver_sticky_auto_disable_enabled = 12;
+
+ // The value of Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL. This is a cached value, so it
+ // could be slightly different from what's in GlobalSettingsProto.LowPowerMode.
+ optional int32 setting_battery_saver_sticky_auto_disable_threshold = 13;
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 18bdb20ad0a6..7bbf3ee1f870 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -19,7 +19,6 @@ package com.android.providers.settings;
import android.annotation.NonNull;
import android.os.UserHandle;
import android.provider.Settings;
-import android.provider.Settings.Global;
import android.providers.settings.GlobalSettingsProto;
import android.providers.settings.SecureSettingsProto;
import android.providers.settings.SettingProto;
@@ -397,7 +396,7 @@ class SettingsProtoDumpUtil {
p.end(certPinToken);
dumpSetting(s, p,
- Global.CHAINED_BATTERY_ATTRIBUTION_ENABLED,
+ Settings.Global.CHAINED_BATTERY_ATTRIBUTION_ENABLED,
GlobalSettingsProto.CHAINED_BATTERY_ATTRIBUTION_ENABLED);
dumpSetting(s, p,
Settings.Global.COMPATIBILITY_MODE,
@@ -734,7 +733,7 @@ class SettingsProtoDumpUtil {
Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
GlobalSettingsProto.HEADS_UP_NOTIFICATIONS_ENABLED);
dumpSetting(s, p,
- Global.HIDDEN_API_BLACKLIST_EXEMPTIONS,
+ Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS,
GlobalSettingsProto.HIDDEN_API_BLACKLIST_EXEMPTIONS);
final long inetCondToken = p.start(GlobalSettingsProto.INET_CONDITION);
@@ -829,6 +828,15 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.Global.AUTOMATIC_POWER_SAVER_MODE,
GlobalSettingsProto.LowPowerMode.AUTOMATIC_POWER_SAVER_MODE);
+ dumpSetting(s, p,
+ Settings.Global.LOW_POWER_MODE_STICKY,
+ GlobalSettingsProto.LowPowerMode.STICKY_ENABLED);
+ dumpSetting(s, p,
+ Settings.Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED,
+ GlobalSettingsProto.LowPowerMode.STICKY_AUTO_DISABLE_ENABLED);
+ dumpSetting(s, p,
+ Settings.Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL,
+ GlobalSettingsProto.LowPowerMode.STICKY_AUTO_DISABLE_LEVEL);
p.end(lpmToken);
dumpSetting(s, p,
@@ -879,7 +887,7 @@ class SettingsProtoDumpUtil {
p.end(multiSimToken);
dumpSetting(s, p,
- Global.NATIVE_FLAGS_HEALTH_CHECK_ENABLED,
+ Settings.Global.NATIVE_FLAGS_HEALTH_CHECK_ENABLED,
GlobalSettingsProto.NATIVE_FLAGS_HEALTH_CHECK_ENABLED);
final long netstatsToken = p.start(GlobalSettingsProto.NETSTATS);
@@ -1259,10 +1267,10 @@ class SettingsProtoDumpUtil {
final long soundTriggerToken = p.start(GlobalSettingsProto.SOUND_TRIGGER);
dumpSetting(s, p,
- Global.MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY,
+ Settings.Global.MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY,
GlobalSettingsProto.SoundTrigger.MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY);
dumpSetting(s, p,
- Global.SOUND_TRIGGER_DETECTION_SERVICE_OP_TIMEOUT,
+ Settings.Global.SOUND_TRIGGER_DETECTION_SERVICE_OP_TIMEOUT,
GlobalSettingsProto.SoundTrigger.DETECTION_SERVICE_OP_TIMEOUT_MS);
p.end(soundTriggerToken);
@@ -1558,7 +1566,7 @@ class SettingsProtoDumpUtil {
GlobalSettingsProto.ZRAM_ENABLED);
dumpSetting(s, p,
- Global.APP_OPS_CONSTANTS,
+ Settings.Global.APP_OPS_CONSTANTS,
GlobalSettingsProto.APP_OPS_CONSTANTS);
p.end(token);
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 1d74350de978..ab2807a9a8a8 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
@@ -104,6 +104,7 @@ public class BatterySaverController implements BatterySaverPolicyListener {
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;
+ public static final int REASON_STICKY_RESTORE_OFF = 13;
/**
* 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 b7f28da499e9..404e450ccf14 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
@@ -28,7 +28,6 @@ import android.os.Handler;
import android.os.PowerManager;
import android.os.UserHandle;
import android.provider.Settings;
-import android.provider.Settings.Global;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
@@ -85,42 +84,56 @@ public class BatterySaverStateMachine {
@GuardedBy("mLock")
private boolean mIsBatteryLevelLow;
- /** Previously known value of Global.LOW_POWER_MODE. */
+ /** Previously known value of Settings.Global.LOW_POWER_MODE. */
@GuardedBy("mLock")
private boolean mSettingBatterySaverEnabled;
- /** Previously known value of Global.LOW_POWER_MODE_STICKY. */
+ /** Previously known value of Settings.Global.LOW_POWER_MODE_STICKY. */
@GuardedBy("mLock")
private boolean mSettingBatterySaverEnabledSticky;
/** Config flag to track if battery saver's sticky behaviour is disabled. */
private final boolean mBatterySaverStickyBehaviourDisabled;
+ /**
+ * Whether or not to end sticky battery saver upon reaching a level specified by
+ * {@link #mSettingBatterySaverStickyAutoDisableThreshold}.
+ */
+ @GuardedBy("mLock")
+ private boolean mSettingBatterySaverStickyAutoDisableEnabled;
+
+ /**
+ * The battery level at which to end sticky battery saver. Only useful if
+ * {@link #mSettingBatterySaverStickyAutoDisableEnabled} is {@code true}.
+ */
+ @GuardedBy("mLock")
+ private int mSettingBatterySaverStickyAutoDisableThreshold;
+
/** 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.
+ * Previously known value of Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL.
* (Currently only used in dumpsys.)
*/
@GuardedBy("mLock")
private int mSettingBatterySaverTriggerThreshold;
- /** Previously known value of Global.AUTOMATIC_POWER_SAVER_MODE. */
+ /** Previously known value of Settings.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.
+ * Corresponds to Settings.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.
+ * Updates when Settings.Global.DYNAMIC_POWER_SAVINGS_ENABLED changes.
*/
@GuardedBy("mLock")
private boolean mDynamicPowerSavingsBatterySaver;
@@ -181,7 +194,7 @@ public class BatterySaverStateMachine {
Slog.d(TAG, "onBootCompleted");
}
// Just booted. We don't want LOW_POWER_MODE to be persisted, so just always clear it.
- putGlobalSetting(Global.LOW_POWER_MODE, 0);
+ putGlobalSetting(Settings.Global.LOW_POWER_MODE, 0);
// This is called with the power manager lock held. Don't do anything that may call to
// upper services. (e.g. don't call into AM directly)
@@ -199,13 +212,19 @@ public class BatterySaverStateMachine {
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
false, mSettingsObserver, UserHandle.USER_SYSTEM);
cr.registerContentObserver(Settings.Global.getUriFor(
- Global.AUTOMATIC_POWER_SAVER_MODE),
+ Settings.Global.AUTOMATIC_POWER_SAVER_MODE),
+ false, mSettingsObserver, UserHandle.USER_SYSTEM);
+ cr.registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.DYNAMIC_POWER_SAVINGS_ENABLED),
+ false, mSettingsObserver, UserHandle.USER_SYSTEM);
+ cr.registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD),
false, mSettingsObserver, UserHandle.USER_SYSTEM);
cr.registerContentObserver(Settings.Global.getUriFor(
- Global.DYNAMIC_POWER_SAVINGS_ENABLED),
+ Settings.Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED),
false, mSettingsObserver, UserHandle.USER_SYSTEM);
cr.registerContentObserver(Settings.Global.getUriFor(
- Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD),
+ Settings.Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL),
false, mSettingsObserver, UserHandle.USER_SYSTEM);
synchronized (mLock) {
@@ -239,25 +258,31 @@ public class BatterySaverStateMachine {
}
@GuardedBy("mLock")
- void refreshSettingsLocked() {
+ private void refreshSettingsLocked() {
final boolean lowPowerModeEnabled = getGlobalSetting(
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;
+ Settings.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,
+ final int automaticBatterySaverMode = getGlobalSetting(
+ Settings.Global.AUTOMATIC_POWER_SAVER_MODE,
PowerManager.POWER_SAVER_MODE_PERCENTAGE);
final int dynamicPowerSavingsDisableThreshold = getGlobalSetting(
- Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD,
+ Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD,
mDynamicPowerSavingsDefaultDisableThreshold);
+ final boolean isStickyAutoDisableEnabled = getGlobalSetting(
+ Settings.Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED, 0) != 0;
+ final int stickyAutoDisableThreshold = getGlobalSetting(
+ Settings.Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL, 90);
setSettingsLocked(lowPowerModeEnabled, lowPowerModeEnabledSticky,
- lowPowerModeTriggerLevel, automaticBatterySaver, dynamicPowerSavingsBatterySaver,
- dynamicPowerSavingsDisableThreshold);
+ lowPowerModeTriggerLevel,
+ isStickyAutoDisableEnabled, stickyAutoDisableThreshold,
+ automaticBatterySaverMode,
+ dynamicPowerSavingsBatterySaver, dynamicPowerSavingsDisableThreshold);
}
/**
@@ -269,12 +294,16 @@ public class BatterySaverStateMachine {
@GuardedBy("mLock")
@VisibleForTesting
void setSettingsLocked(boolean batterySaverEnabled, boolean batterySaverEnabledSticky,
- int batterySaverTriggerThreshold, int automaticBatterySaver,
+ int batterySaverTriggerThreshold,
+ boolean isStickyAutoDisableEnabled, int stickyAutoDisableThreshold,
+ int automaticBatterySaver,
boolean dynamicPowerSavingsBatterySaver, int dynamicPowerSavingsDisableThreshold) {
if (DEBUG) {
Slog.d(TAG, "setSettings: enabled=" + batterySaverEnabled
+ " sticky=" + batterySaverEnabledSticky
+ " threshold=" + batterySaverTriggerThreshold
+ + " stickyAutoDisableEnabled=" + isStickyAutoDisableEnabled
+ + " stickyAutoDisableThreshold=" + stickyAutoDisableThreshold
+ " automaticBatterySaver=" + automaticBatterySaver
+ " dynamicPowerSavingsBatterySaver=" + dynamicPowerSavingsBatterySaver
+ " dynamicPowerSavingsDisableThreshold="
@@ -283,11 +312,19 @@ public class BatterySaverStateMachine {
mSettingsLoaded = true;
+ // Set sensible limits.
+ stickyAutoDisableThreshold = Math.max(stickyAutoDisableThreshold,
+ batterySaverTriggerThreshold);
+
final boolean enabledChanged = mSettingBatterySaverEnabled != batterySaverEnabled;
final boolean stickyChanged =
mSettingBatterySaverEnabledSticky != batterySaverEnabledSticky;
final boolean thresholdChanged
= mSettingBatterySaverTriggerThreshold != batterySaverTriggerThreshold;
+ final boolean stickyAutoDisableEnabledChanged =
+ mSettingBatterySaverStickyAutoDisableEnabled != isStickyAutoDisableEnabled;
+ final boolean stickyAutoDisableThresholdChanged =
+ mSettingBatterySaverStickyAutoDisableThreshold != stickyAutoDisableThreshold;
final boolean automaticModeChanged = mSettingAutomaticBatterySaver != automaticBatterySaver;
final boolean dynamicPowerSavingsThresholdChanged =
mDynamicPowerSavingsDisableThreshold != dynamicPowerSavingsDisableThreshold;
@@ -295,6 +332,7 @@ public class BatterySaverStateMachine {
mDynamicPowerSavingsBatterySaver != dynamicPowerSavingsBatterySaver;
if (!(enabledChanged || stickyChanged || thresholdChanged || automaticModeChanged
+ || stickyAutoDisableEnabledChanged || stickyAutoDisableThresholdChanged
|| dynamicPowerSavingsThresholdChanged || dynamicPowerSavingsBatterySaverChanged)) {
return;
}
@@ -302,6 +340,8 @@ public class BatterySaverStateMachine {
mSettingBatterySaverEnabled = batterySaverEnabled;
mSettingBatterySaverEnabledSticky = batterySaverEnabledSticky;
mSettingBatterySaverTriggerThreshold = batterySaverTriggerThreshold;
+ mSettingBatterySaverStickyAutoDisableEnabled = isStickyAutoDisableEnabled;
+ mSettingBatterySaverStickyAutoDisableThreshold = stickyAutoDisableThreshold;
mSettingAutomaticBatterySaver = automaticBatterySaver;
mDynamicPowerSavingsDisableThreshold = dynamicPowerSavingsDisableThreshold;
mDynamicPowerSavingsBatterySaver = dynamicPowerSavingsBatterySaver;
@@ -376,7 +416,9 @@ public class BatterySaverStateMachine {
+ " mBatterySaverSnoozing=" + mBatterySaverSnoozing
+ " mIsPowered=" + mIsPowered
+ " mSettingAutomaticBatterySaver=" + mSettingAutomaticBatterySaver
- + " mSettingBatterySaverEnabledSticky=" + mSettingBatterySaverEnabledSticky);
+ + " mSettingBatterySaverEnabledSticky=" + mSettingBatterySaverEnabledSticky
+ + " mSettingBatterySaverStickyAutoDisableEnabled="
+ + mSettingBatterySaverStickyAutoDisableEnabled);
}
if (!(mBootCompleted && mSettingsLoaded && mBatteryStatusSet)) {
return; // Not fully initialized yet.
@@ -392,10 +434,15 @@ public class BatterySaverStateMachine {
"Plugged in");
} else if (mSettingBatterySaverEnabledSticky && !mBatterySaverStickyBehaviourDisabled) {
- // Re-enable BS.
- enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ true,
- BatterySaverController.REASON_STICKY_RESTORE,
- "Sticky restore");
+ if (mSettingBatterySaverStickyAutoDisableEnabled
+ && mBatteryLevel >= mSettingBatterySaverStickyAutoDisableThreshold) {
+ setStickyActive(false);
+ } else {
+ // Re-enable BS.
+ enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ true,
+ BatterySaverController.REASON_STICKY_RESTORE,
+ "Sticky restore");
+ }
} else if (mSettingAutomaticBatterySaver
== PowerManager.POWER_SAVER_MODE_PERCENTAGE
@@ -483,12 +530,10 @@ public class BatterySaverStateMachine {
}
mSettingBatterySaverEnabled = enable;
- putGlobalSetting(Global.LOW_POWER_MODE, enable ? 1 : 0);
+ putGlobalSetting(Settings.Global.LOW_POWER_MODE, enable ? 1 : 0);
if (manual) {
- mSettingBatterySaverEnabledSticky = !mBatterySaverStickyBehaviourDisabled && enable;
- putGlobalSetting(Global.LOW_POWER_MODE_STICKY,
- mSettingBatterySaverEnabledSticky ? 1 : 0);
+ setStickyActive(!mBatterySaverStickyBehaviourDisabled && enable);
}
mBatterySaverController.enableBatterySaver(enable, intReason);
@@ -506,7 +551,8 @@ public class BatterySaverStateMachine {
}
}
- private void triggerDynamicModeNotification() {
+ @VisibleForTesting
+ void triggerDynamicModeNotification() {
NotificationManager manager = mContext.getSystemService(NotificationManager.class);
ensureNotificationChannelExists(manager);
@@ -553,14 +599,20 @@ public class BatterySaverStateMachine {
mBatterySaverSnoozing = snoozing;
}
+ private void setStickyActive(boolean active) {
+ mSettingBatterySaverEnabledSticky = active;
+ putGlobalSetting(Settings.Global.LOW_POWER_MODE_STICKY,
+ mSettingBatterySaverEnabledSticky ? 1 : 0);
+ }
+
@VisibleForTesting
protected void putGlobalSetting(String key, int value) {
- Global.putInt(mContext.getContentResolver(), key, value);
+ Settings.Global.putInt(mContext.getContentResolver(), key, value);
}
@VisibleForTesting
protected int getGlobalSetting(String key, int defValue) {
- return Global.getInt(mContext.getContentResolver(), key, defValue);
+ return Settings.Global.getInt(mContext.getContentResolver(), key, defValue);
}
public void dump(PrintWriter pw) {
@@ -597,6 +649,10 @@ public class BatterySaverStateMachine {
pw.println(mSettingBatterySaverEnabled);
pw.print(" mSettingBatterySaverEnabledSticky=");
pw.println(mSettingBatterySaverEnabledSticky);
+ pw.print(" mSettingBatterySaverStickyAutoDisableEnabled=");
+ pw.println(mSettingBatterySaverStickyAutoDisableEnabled);
+ pw.print(" mSettingBatterySaverStickyAutoDisableThreshold=");
+ pw.println(mSettingBatterySaverStickyAutoDisableThreshold);
pw.print(" mSettingBatterySaverTriggerThreshold=");
pw.println(mSettingBatterySaverTriggerThreshold);
pw.print(" mBatterySaverStickyBehaviourDisabled=");
@@ -628,6 +684,13 @@ public class BatterySaverStateMachine {
mSettingBatterySaverEnabledSticky);
proto.write(BatterySaverStateMachineProto.SETTING_BATTERY_SAVER_TRIGGER_THRESHOLD,
mSettingBatterySaverTriggerThreshold);
+ proto.write(
+ BatterySaverStateMachineProto.SETTING_BATTERY_SAVER_STICKY_AUTO_DISABLE_ENABLED,
+ mSettingBatterySaverStickyAutoDisableEnabled);
+ proto.write(
+ BatterySaverStateMachineProto
+ .SETTING_BATTERY_SAVER_STICKY_AUTO_DISABLE_THRESHOLD,
+ mSettingBatterySaverStickyAutoDisableThreshold);
proto.end(token);
}
diff --git a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java b/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
index f31ca55d422e..5009d64b94d4 100644
--- a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
@@ -19,51 +19,41 @@ import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import android.app.NotificationManager;
import android.content.ContentResolver;
+import android.content.Context;
import android.content.res.Resources;
import android.provider.Settings.Global;
-import android.test.mock.MockContext;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.google.common.base.Objects;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.HashMap;
+import java.util.Objects;
/**
- atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
+ * atest com.android.server.power.batterysaver.BatterySaverStateMachineTest
*/
@SmallTest
@RunWith(AndroidJUnit4.class)
public class BatterySaverStateMachineTest {
- private MyMockContext mMockContext;
+ private Context mMockContext;
private ContentResolver mMockContextResolver;
private BatterySaverController mMockBatterySaverController;
+ private NotificationManager mMockNotificationManager;
private Device mDevice;
private TestableBatterySaverStateMachine mTarget;
private Resources mMockResources;
- private class MyMockContext extends MockContext {
- @Override
- public ContentResolver getContentResolver() {
- return mMockContextResolver;
- }
-
- @Override
- public Resources getResources() {
- return mMockResources;
- }
- }
-
private DevicePersistedState mPersistedState;
private class DevicePersistedState {
@@ -116,6 +106,10 @@ public class BatterySaverStateMachineTest {
mPersistedState.global.getOrDefault(Global.LOW_POWER_MODE, 0) != 0,
mPersistedState.global.getOrDefault(Global.LOW_POWER_MODE_STICKY, 0) != 0,
mDevice.getLowPowerModeTriggerLevel(),
+ mPersistedState.global.getOrDefault(
+ Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED, 0) != 0,
+ mPersistedState.global.getOrDefault(
+ Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL, 90),
mPersistedState.global.getOrDefault(Global.AUTOMATIC_POWER_SAVER_MODE, 0),
mPersistedState.global.getOrDefault(
Global.DYNAMIC_POWER_SAVINGS_ENABLED, 0) != 0,
@@ -137,13 +131,13 @@ public class BatterySaverStateMachineTest {
* Test target class.
*/
private class TestableBatterySaverStateMachine extends BatterySaverStateMachine {
- public TestableBatterySaverStateMachine() {
+ TestableBatterySaverStateMachine() {
super(new Object(), mMockContext, mMockBatterySaverController);
}
@Override
protected void putGlobalSetting(String key, int value) {
- if (Objects.equal(mPersistedState.global.get(key), value)) {
+ if (Objects.equals(mPersistedState.global.get(key), value)) {
return;
}
mDevice.putGlobalSetting(key, value);
@@ -163,15 +157,25 @@ public class BatterySaverStateMachineTest {
void runOnBgThreadLazy(Runnable r, int delayMillis) {
r.run();
}
+
+ @Override
+ void triggerDynamicModeNotification() {
+ // Do nothing
+ }
}
@Before
public void setUp() {
- mMockContext = new MyMockContext();
+ mMockContext = mock(Context.class);
mMockContextResolver = mock(ContentResolver.class);
mMockBatterySaverController = mock(BatterySaverController.class);
+ mMockNotificationManager = mock(NotificationManager.class);
mMockResources = mock(Resources.class);
+ doReturn(mMockContextResolver).when(mMockContext).getContentResolver();
+ doReturn(mMockResources).when(mMockContext).getResources();
+ doReturn(mMockNotificationManager).when(mMockContext)
+ .getSystemService(NotificationManager.class);
doAnswer((inv) -> mDevice.batterySaverEnabled = inv.getArgument(0))
.when(mMockBatterySaverController).enableBatterySaver(anyBoolean(), anyInt());
when(mMockBatterySaverController.isEnabled())
@@ -446,8 +450,9 @@ public class BatterySaverStateMachineTest {
}
@Test
- public void testAutoBatterySaver_withSticky() {
+ public void testAutoBatterySaver_withSticky_withAutoOffDisabled() {
mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
+ mDevice.putGlobalSetting(Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED, 0);
mTarget.setBatterySaverEnabledManually(true);
@@ -518,6 +523,197 @@ public class BatterySaverStateMachineTest {
}
@Test
+ public void testAutoBatterySaver_withSticky_withAutoOffEnabled() {
+ mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
+ mDevice.putGlobalSetting(Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED, 1);
+ mDevice.putGlobalSetting(Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL, 90);
+
+ // Scenario 1: User turns BS on manually above the threshold, it shouldn't turn off even
+ // with battery level change above threshold.
+ mDevice.setBatteryLevel(100);
+ mTarget.setBatterySaverEnabledManually(true);
+
+ assertEquals(true, mDevice.batterySaverEnabled);
+ assertEquals(100, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
+ mDevice.setBatteryLevel(95);
+
+ assertEquals(true, mDevice.batterySaverEnabled); // Stays on.
+ assertEquals(95, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
+ // Scenario 2: User turns BS on manually above the threshold then charges device. BS
+ // shouldn't turn back on.
+ mDevice.setPowered(true);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(95, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
+ mDevice.setBatteryLevel(97);
+ mDevice.setPowered(false);
+
+ assertEquals(false, mDevice.batterySaverEnabled); // Sticky BS no longer enabled.
+ assertEquals(97, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
+ // Scenario 3: User turns BS on manually above the threshold. Device drains below
+ // threshold and then charged to below threshold. Sticky BS should activate.
+ mTarget.setBatterySaverEnabledManually(true);
+ mDevice.setBatteryLevel(30);
+
+ assertEquals(true, mDevice.batterySaverEnabled);
+ assertEquals(30, mPersistedState.batteryLevel);
+ assertEquals(true, mPersistedState.batteryLow);
+
+ mDevice.setPowered(true);
+ mDevice.setBatteryLevel(80);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(80, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
+ mDevice.setPowered(false);
+
+ assertEquals(true, mDevice.batterySaverEnabled); // Still enabled.
+ assertEquals(80, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
+ mDevice.setBatteryLevel(30);
+
+ assertEquals(true, mDevice.batterySaverEnabled);
+ assertEquals(30, mPersistedState.batteryLevel);
+ assertEquals(true, mPersistedState.batteryLow);
+
+ // Scenario 4: User turns BS on manually above the threshold. Device drains below
+ // threshold and is eventually charged to above threshold. Sticky BS should turn off.
+ mDevice.setPowered(true);
+ mDevice.setBatteryLevel(90);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(90, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
+ mDevice.setPowered(false);
+
+ assertEquals(false, mDevice.batterySaverEnabled); // Sticky BS no longer enabled.
+ assertEquals(90, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
+ // Scenario 5: User turns BS on manually below threshold and charges to below threshold.
+ // Sticky BS should activate.
+ mDevice.setBatteryLevel(70);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(70, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
+ mTarget.setBatterySaverEnabledManually(true);
+
+ assertEquals(true, mDevice.batterySaverEnabled);
+ assertEquals(70, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
+ mDevice.setPowered(true);
+ mDevice.setBatteryLevel(80);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(80, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
+ mDevice.setPowered(false);
+
+ assertEquals(true, mDevice.batterySaverEnabled); // Sticky BS still on.
+ assertEquals(80, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
+ // Scenario 6: User turns BS on manually below threshold and eventually charges to above
+ // threshold. Sticky BS should turn off.
+
+ mDevice.setPowered(true);
+ mDevice.setBatteryLevel(95);
+ mDevice.setPowered(false);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(95, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
+ // Scenario 7: User turns BS on above threshold and then reboots device. Sticky BS
+ // shouldn't activate.
+ mTarget.setBatterySaverEnabledManually(true);
+ mPersistedState.batteryLevel = 93;
+
+ initDevice();
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(93, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
+ // Scenario 8: User turns BS on below threshold and then reboots device without charging.
+ // Sticky BS should activate.
+ mDevice.setBatteryLevel(75);
+ mTarget.setBatterySaverEnabledManually(true);
+ assertEquals(true, mDevice.batterySaverEnabled);
+ assertEquals(75, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
+ initDevice();
+
+ assertEquals(true, mDevice.batterySaverEnabled);
+ assertEquals(75, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
+ // Scenario 9: User turns BS on below threshold and then reboots device after charging
+ // above threshold. Sticky BS shouldn't activate.
+ mDevice.setBatteryLevel(80);
+ mTarget.setBatterySaverEnabledManually(true);
+ mPersistedState.batteryLevel = 100;
+
+ initDevice();
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(100, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
+ // Scenario 10: Somehow autoDisableLevel is set to a value below lowPowerModeTriggerLevel
+ // and then user enables manually above both thresholds, discharges below
+ // autoDisableLevel and then charges up to between autoDisableLevel and
+ // lowPowerModeTriggerLevel. Sticky BS shouldn't activate, but BS should still be on
+ // because the level is below lowPowerModeTriggerLevel.
+ mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 75);
+ mDevice.putGlobalSetting(Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED, 1);
+ mDevice.putGlobalSetting(Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL, 60);
+ initDevice();
+
+ mDevice.setBatteryLevel(90);
+ mTarget.setBatterySaverEnabledManually(true);
+
+ assertEquals(true, mDevice.batterySaverEnabled);
+ assertEquals(90, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
+ mDevice.setBatteryLevel(50);
+
+ assertEquals(true, mDevice.batterySaverEnabled);
+ assertEquals(50, mPersistedState.batteryLevel);
+ assertEquals(true, mPersistedState.batteryLow);
+
+ mDevice.setPowered(true);
+ mDevice.setBatteryLevel(65);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(65, mPersistedState.batteryLevel);
+ assertEquals(true, mPersistedState.batteryLow);
+
+ mDevice.setPowered(false);
+
+ assertEquals(true, mDevice.batterySaverEnabled);
+ assertEquals(65, mPersistedState.batteryLevel);
+ assertEquals(true, mPersistedState.batteryLow);
+ }
+
+ @Test
public void testAutoBatterySaver_withStickyDisabled() {
when(mMockResources.getBoolean(
com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled))