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
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index f840792..4b3fbe6 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11811,14 +11811,93 @@
 
         /**
          * 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 @@
             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 72892fa..7de8020 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -332,6 +332,18 @@
     }
     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 @@
         // 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 @@
 
     // 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 6ae183b..26f3370 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 6276884..4eb723e 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 727f399..8c91c37 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -124,6 +124,7 @@
                     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 @@
                     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,