diff options
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); +    }  }  |