Create APIs to interact with DynamicPowerSaver

This creates the PowerManager APIs that allow apps with the
appropriate permissions to interact with Dynamic Power Saver.

Bug: 111450127
Test: WIP
Change-Id: I5b9483fa0fba81a4ade622b1f3dbaec580b68a67
diff --git a/api/system-current.txt b/api/system-current.txt
index e0c58b4..93a9f52 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4109,8 +4109,12 @@
   }
 
   public final class PowerManager {
+    method public int getPowerSaveMode();
+    method public boolean setDynamicPowerSavings(boolean, int);
     method public boolean setPowerSaveMode(boolean);
     method public void userActivity(long, int, int);
+    field public static final int POWER_SAVER_MODE_DYNAMIC = 1; // 0x1
+    field public static final int POWER_SAVER_MODE_PERCENTAGE = 0; // 0x0
     field public static final int USER_ACTIVITY_EVENT_ACCESSIBILITY = 3; // 0x3
     field public static final int USER_ACTIVITY_EVENT_BUTTON = 1; // 0x1
     field public static final int USER_ACTIVITY_EVENT_OTHER = 0; // 0x0
diff --git a/api/test-current.txt b/api/test-current.txt
index 6213b17..a66c209 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -744,7 +744,11 @@
   }
 
   public final class PowerManager {
+    method public int getPowerSaveMode();
+    method public boolean setDynamicPowerSavings(boolean, int);
     method public boolean setPowerSaveMode(boolean);
+    field public static final int POWER_SAVER_MODE_DYNAMIC = 1; // 0x1
+    field public static final int POWER_SAVER_MODE_PERCENTAGE = 0; // 0x0
   }
 
   public class Process {
@@ -981,6 +985,9 @@
 
   public static final class Settings.Global extends android.provider.Settings.NameValueTable {
     field public static final java.lang.String AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES = "autofill_compat_mode_allowed_packages";
+    field public static final java.lang.String AUTOMATIC_POWER_SAVER_MODE = "automatic_power_saver_mode";
+    field public static final java.lang.String DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD = "dynamic_power_savings_disable_threshold";
+    field public static final java.lang.String DYNAMIC_POWER_SAVINGS_ENABLED = "dynamic_power_savings_enabled";
     field public static final java.lang.String HIDDEN_API_BLACKLIST_EXEMPTIONS = "hidden_api_blacklist_exemptions";
     field public static final java.lang.String LOCATION_GLOBAL_KILL_SWITCH = "location_global_kill_switch";
     field public static final java.lang.String LOW_POWER_MODE = "low_power";
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 7ceeb52..ca5b233 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -48,6 +48,8 @@
     boolean isPowerSaveMode();
     PowerSaveState getPowerSaveState(int serviceType);
     boolean setPowerSaveMode(boolean mode);
+    boolean setDynamicPowerSavings(boolean dynamicPowerSavingsEnabled, int disableThreshold);
+    int getPowerSaveMode();
     boolean isDeviceIdleMode();
     boolean isLightDeviceIdleMode();
 
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 27c281d..a307cd8 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import android.Manifest.permission;
 import android.annotation.IntDef;
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
@@ -1185,6 +1186,105 @@
     }
 
     /**
+     * Updates the current state of dynamic power savings and disable threshold. This is
+     * a signal to the system which an app can update to serve as an indicator that
+     * the user will be in a battery critical situation before being able to plug in.
+     * Only apps with the {@link android.Manifest.permission#POWER_SAVER} permission may do this.
+     * This is a device global state, not a per user 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
+     * their battery saver mode to "automatic". Note
+     * that this is NOT simply an on/off switch for 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>The provided threshold is the percentage the system should consider itself safe at given
+     * the current state of the device. The value is an integer representing a battery level.
+     *
+     * <p>The threshold is meant to set an explicit stopping point for dynamic power savings
+     * functionality so that the dynamic power savings itself remains a signal rather than becoming
+     * an on/off switch for a subset of features.
+     * @hide
+     *
+     * @param dynamicPowerSavingsEnabled A signal indicating to the system if it believes the
+     * dynamic power savings behaviors should be activated.
+     * @param disableThreshold When the suggesting app believes it would be safe to disable dynamic
+     * power savings behaviors.
+     * @return True if the update was allowed and succeeded.
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    @RequiresPermission(permission.POWER_SAVER)
+    public boolean setDynamicPowerSavings(boolean dynamicPowerSavingsEnabled,
+            int disableThreshold) {
+        try {
+            return mService.setDynamicPowerSavings(dynamicPowerSavingsEnabled, disableThreshold);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Indicates automatic battery saver toggling by the system will be based on percentage.
+     *
+     * @see PowerManager#getPowerSaveMode()
+     *
+     *  @hide
+     */
+    @SystemApi
+    @TestApi
+    public static final int POWER_SAVER_MODE_PERCENTAGE = 0;
+
+    /**
+     * Indicates automatic battery saver toggling by the system will be based on the state
+     * of the dynamic power savings signal.
+     *
+     * @see PowerManager#setDynamicPowerSavings(boolean, int)
+     * @see PowerManager#getPowerSaveMode()
+     *
+     *  @hide
+     */
+    @SystemApi
+    @TestApi
+    public static final int POWER_SAVER_MODE_DYNAMIC = 1;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = {
+        POWER_SAVER_MODE_PERCENTAGE,
+        POWER_SAVER_MODE_DYNAMIC
+
+    })
+    public @interface AutoPowerSaverMode{}
+
+
+    /**
+     * Returns the current battery saver control mode. Values it may return are defined in
+     * AutoPowerSaverMode. Note that this is a global device state, not a per user setting.
+     *
+     * @return The current value power saver mode for the system.
+     *
+     * @see AutoPowerSaverMode
+     * @see PowerManager#getPowerSaveMode()
+     * @hide
+     */
+    @AutoPowerSaverMode
+    @SystemApi
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.POWER_SAVER)
+    public int getPowerSaveMode() {
+        try {
+            return mService.getPowerSaveMode();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Get data about the battery saver mode for a specific service
      * @param serviceType unique key for the service, one of {@link ServiceType}
      * @return Battery saver state data.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 4b3fbe6..0402222 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11813,9 +11813,10 @@
          * 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
-         * {@link #AUTOMATIC_POWER_SAVER_MODE_PERCENTAGE}.
+         * {@link android.os.PowerManager.AutoPowerSaverMode#POWER_SAVER_MODE_PERCENTAGE}.
          *
          * @see #AUTOMATIC_POWER_SAVER_MODE
+         * @see android.os.PowerManager#getPowerSaveMode()
          * @hide
          */
         public static final String LOW_POWER_MODE_TRIGGER_LEVEL = "low_power_trigger_level";
@@ -11825,78 +11826,38 @@
                 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.
+         * savings trigger, or none. See {@link android.os.PowerManager.AutoPowerSaverMode} for
+         * accepted values.
          *
          *  @hide
          */
+        @TestApi
         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.
+         * The setting that backs the disable threshold for the setPowerSavingsWarning api in
+         * PowerManager
          *
-         * <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.
+         * @see android.os.PowerManager#setDynamicPowerSavings(boolean, int)
          * @hide
          */
+        @TestApi
         public static final String DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD =
                 "dynamic_power_savings_disable_threshold";
+        private static final Validator DYNAMIC_POWER_SAVINGS_VALIDATOR =
+                new SettingsValidators.InclusiveIntegerRangeValidator(0, 100);
 
         /**
-         * 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.
+         * The setting which backs the setDynamicPowerSavings api in PowerManager.
          *
-         * <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
+         * @see android.os.PowerManager#setDynamicPowerSavings(boolean, int)
          * @hide
          */
+        @TestApi
         public static final String DYNAMIC_POWER_SAVINGS_ENABLED = "dynamic_power_savings_enabled";
 
         /**
@@ -12822,6 +12783,8 @@
             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(DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD,
+                    DYNAMIC_POWER_SAVINGS_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/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index a1fbe0a..c7945bd02 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -324,6 +324,7 @@
         <permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
         <permission name="android.permission.MOVE_PACKAGE"/>
         <permission name="android.permission.PACKAGE_USAGE_STATS" />
+        <permission name="android.permission.POWER_SAVER" />
         <permission name="android.permission.READ_FRAME_BUFFER"/>
         <permission name="android.permission.READ_LOWPAN_CREDENTIAL"/>
         <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 822c39b..89690fb 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -83,6 +83,7 @@
     <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
     <uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
     <uses-permission android:name="android.permission.DEVICE_POWER" />
+    <uses-permission android:name="android.permission.POWER_SAVER" />
     <uses-permission android:name="android.permission.INSTALL_LOCATION_PROVIDER" />
     <uses-permission android:name="android.permission.BACKUP" />
     <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES" />
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 43a9c78..29d6237 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -4439,6 +4439,42 @@
         }
 
         @Override // Binder call
+        public boolean setDynamicPowerSavings(boolean dynamicPowerSavingsEnabled,
+                int disableThreshold) {
+            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.POWER_SAVER,
+                    "updateDynamicPowerSavings");
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                final ContentResolver resolver = mContext.getContentResolver();
+                boolean success = Settings.Global.putInt(resolver,
+                        Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD,
+                        disableThreshold);
+                if (success) {
+                    // abort updating if we weren't able to succeed on the threshold
+                    success &= Settings.Global.putInt(resolver,
+                            Settings.Global.DYNAMIC_POWER_SAVINGS_ENABLED,
+                            dynamicPowerSavingsEnabled ? 1 : 0);
+                }
+                return success;
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override // Binder call
+        public int getPowerSaveMode() {
+            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.POWER_SAVER, null);
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                return Settings.Global.getInt(mContext.getContentResolver(),
+                        Settings.Global.AUTOMATIC_POWER_SAVER_MODE,
+                        PowerManager.POWER_SAVER_MODE_PERCENTAGE);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override // Binder call
         public boolean isDeviceIdleMode() {
             final long ident = Binder.clearCallingIdentity();
             try {
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 6acaf0e..f262f6d 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.database.ContentObserver;
 import android.os.Handler;
+import android.os.PowerManager;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.provider.Settings.Global;
@@ -241,7 +242,7 @@
                 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
         final int automaticBatterySaver = getGlobalSetting(
                 Global.AUTOMATIC_POWER_SAVER_MODE,
-                Settings.Global.AUTOMATIC_POWER_SAVER_MODE_PERCENTAGE);
+                PowerManager.POWER_SAVER_MODE_PERCENTAGE);
         final int dynamicPowerSavingsDisableThreshold = getGlobalSetting(
                 Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD,
                 mDynamicPowerSavingsDefaultDisableThreshold);
@@ -343,6 +344,17 @@
         }
     }
 
+    @GuardedBy("mLock")
+    private boolean isBatteryLowLocked() {
+        final boolean percentageLow =
+                mSettingAutomaticBatterySaver == PowerManager.POWER_SAVER_MODE_PERCENTAGE
+                && mIsBatteryLevelLow;
+        final boolean dynamicPowerSavingsLow =
+                mSettingAutomaticBatterySaver == PowerManager.POWER_SAVER_MODE_DYNAMIC
+                && mBatteryLevel <= mDynamicPowerSavingsDisableThreshold;
+        return percentageLow || dynamicPowerSavingsLow;
+    }
+
     /**
      * Decide whether to auto-start / stop battery saver.
      */
@@ -361,14 +373,8 @@
         if (!(mBootCompleted && mSettingsLoaded && mBatteryStatusSet)) {
             return; // Not fully initialized yet.
         }
-        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) {
+
+        if (!isBatteryLowLocked()) {
             updateSnoozingLocked(false, "Battery not low");
         }
         if (mIsPowered) {
@@ -384,7 +390,7 @@
                     "Sticky restore");
 
         } else if (mSettingAutomaticBatterySaver
-                == Settings.Global.AUTOMATIC_POWER_SAVER_MODE_PERCENTAGE
+                == PowerManager.POWER_SAVER_MODE_PERCENTAGE
                 && isAutoBatterySaverConfiguredLocked()) {
             if (mIsBatteryLevelLow && !mBatterySaverSnoozing) {
                 enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ false,
@@ -397,21 +403,21 @@
                         "Percentage Auto OFF");
             }
         } else if (mSettingAutomaticBatterySaver
-                == Settings.Global.AUTOMATIC_POWER_SAVER_MODE_DYNAMIC) {
+                == PowerManager.POWER_SAVER_MODE_DYNAMIC) {
             if (mBatteryLevel >= mDynamicPowerSavingsDisableThreshold) {
                 enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false,
                         BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_OFF,
-                        "Dynamic Power Savings Auto OFF");
+                        "Dynamic Warning Auto OFF");
             } else if (mDynamicPowerSavingsBatterySaver && !mBatterySaverSnoozing) {
                 enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ false,
                         BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON,
-                        "Dynamic Power Savings Auto ON");
+                        "Dynamic Warning Auto ON");
             }
         }
         // do nothing if automatic battery saver mode = PERCENTAGE and low warning threshold = 0%
     }
 
-    /**
+  /**
      * {@link com.android.server.power.PowerManagerService} calls it when
      * {@link android.os.PowerManager#setPowerSaveMode} is called.
      *
@@ -462,15 +468,7 @@
                 // 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.
-                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)) {
+                if (isBatterySaverEnabled() && isBatteryLowLocked()) {
                     updateSnoozingLocked(true, "Manual snooze");
                 }
             }