Saver: PowerManager call to set low power mode.

- Add an explicit power manager call to set the low power mode state,
  instead of trying manage everything around a single setting.
- When low-power mode is triggered by falling below the configured
  threshold, it does not update the setting.
- The "is-enabled" api returns setting || below configured trigger.
- Move the snooze management into the new api call.
- Callers (sysui + settings) updated to use the api instead of the
  setting.
- Handles the case where the level does an unpowered leap out of the
  low battery level. (Possible if powered in-between while the device
  is off)

Bug:17460535
Change-Id: Ic030504c9cad9868a7137abbe837b170da37852b
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 658180b..182dbee 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -42,6 +42,7 @@
     void nap(long time);
     boolean isInteractive();
     boolean isPowerSaveMode();
+    boolean setPowerSaveMode(boolean mode);
 
     void reboot(boolean confirm, String reason, boolean wait);
     void shutdown(boolean confirm, boolean wait);
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 18b2082..3b6ce53 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -796,6 +796,23 @@
     }
 
     /**
+     * Set the current power save mode.
+     *
+     * @return True if the set was allowed.
+     *
+     * @see #isPowerSaveMode()
+     *
+     * @hide
+     */
+    public boolean setPowerSaveMode(boolean mode) {
+        try {
+            return mService.setPowerSaveMode(mode);
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    /**
      * Intent that is broadcast when the state of {@link #isPowerSaveMode()} changes.
      * This broadcast is only sent to registered receivers.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index 4c7f8ec..f184ad2 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -31,6 +31,7 @@
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Handler;
+import android.os.PowerManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -72,6 +73,7 @@
 
     private final Context mContext;
     private final NotificationManager mNoMan;
+    private final PowerManager mPowerMan;
     private final Handler mHandler = new Handler();
     private final Receiver mReceiver = new Receiver();
     private final Intent mOpenBatterySettings = settings(Intent.ACTION_POWER_USAGE_SUMMARY);
@@ -93,6 +95,7 @@
     public PowerNotificationWarnings(Context context, PhoneStatusBar phoneStatusBar) {
         mContext = context;
         mNoMan = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+        mPowerMan = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
         mReceiver.init();
     }
 
@@ -356,9 +359,8 @@
         mSaverConfirmation = d;
     }
 
-    private void setSaverSetting(boolean mode) {
-        final int val = mode ? 1 : 0;
-        Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.LOW_POWER_MODE, val);
+    private void setSaverMode(boolean mode) {
+        mPowerMan.setPowerSaveMode(mode);
     }
 
     private final class Receiver extends BroadcastReceiver {
@@ -384,7 +386,7 @@
             } else if (action.equals(ACTION_STOP_SAVER)) {
                 dismissSaverNotification();
                 dismissLowBatteryNotification();
-                setSaverSetting(false);
+                setSaverMode(false);
             }
         }
     }
@@ -395,7 +397,7 @@
             AsyncTask.execute(new Runnable() {
                 @Override
                 public void run() {
-                    setSaverSetting(true);
+                    setSaverMode(true);
                 }
             });
         }
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index eeebe04..c79a6d6 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -416,9 +416,9 @@
     private boolean mLowPowerModeSetting;
 
     // Current state of whether the settings are allowing auto low power mode.
-    private boolean mAutoLowPowerModeEnabled;
+    private boolean mAutoLowPowerModeConfigured;
 
-   // The user turned off low power mode below the trigger level
+    // The user turned off low power mode below the trigger level
     private boolean mAutoLowPowerModeSnoozing;
 
     // True if the battery level is currently considered low.
@@ -659,26 +659,12 @@
 
         final boolean lowPowerModeEnabled = Settings.Global.getInt(resolver,
                 Settings.Global.LOW_POWER_MODE, 0) != 0;
-        final boolean autoLowPowerModeEnabled = Settings.Global.getInt(resolver,
+        final boolean autoLowPowerModeConfigured = Settings.Global.getInt(resolver,
                 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0) != 0;
         if (lowPowerModeEnabled != mLowPowerModeSetting
-                || autoLowPowerModeEnabled != mAutoLowPowerModeEnabled) {
-            if (lowPowerModeEnabled != mLowPowerModeSetting) {
-                if (!mAutoLowPowerModeSnoozing && !lowPowerModeEnabled && !mIsPowered
-                        && mAutoLowPowerModeEnabled) {
-                    if (DEBUG_SPEW) {
-                        Slog.d(TAG, "updateSettingsLocked: snoozing low power mode");
-                    }
-                    mAutoLowPowerModeSnoozing = true;
-                } else if (mAutoLowPowerModeSnoozing && lowPowerModeEnabled) {
-                    if (DEBUG_SPEW) {
-                        Slog.d(TAG, "updateSettingsLocked: no longer snoozing low power mode");
-                    }
-                    mAutoLowPowerModeSnoozing = true;
-                }
-            }
+                || autoLowPowerModeConfigured != mAutoLowPowerModeConfigured) {
             mLowPowerModeSetting = lowPowerModeEnabled;
-            mAutoLowPowerModeEnabled = autoLowPowerModeEnabled;
+            mAutoLowPowerModeConfigured = autoLowPowerModeConfigured;
             updateLowPowerModeLocked();
         }
 
@@ -694,21 +680,14 @@
             Settings.Global.putInt(mContext.getContentResolver(),
                     Settings.Global.LOW_POWER_MODE, 0);
             mLowPowerModeSetting = false;
-        } else if (!mIsPowered && mAutoLowPowerModeEnabled && !mAutoLowPowerModeSnoozing
-                && mBatteryLevelLow && !mLowPowerModeSetting) {
-            if (DEBUG_SPEW) {
-                Slog.d(TAG, "updateLowPowerModeLocked: trigger level reached, turning setting on");
-            }
-            // Turn setting on if trigger level is enabled, and we're now below it
-            Settings.Global.putInt(mContext.getContentResolver(),
-                    Settings.Global.LOW_POWER_MODE, 1);
-            mLowPowerModeSetting = true;
         }
-        final boolean lowPowerModeEnabled = mLowPowerModeSetting;
+        final boolean autoLowPowerModeEnabled = !mIsPowered && mAutoLowPowerModeConfigured
+                && !mAutoLowPowerModeSnoozing && mBatteryLevelLow;
+        final boolean lowPowerModeEnabled = mLowPowerModeSetting || autoLowPowerModeEnabled;
+
         if (mLowPowerModeEnabled != lowPowerModeEnabled) {
             mLowPowerModeEnabled = lowPowerModeEnabled;
             powerHintInternal(POWER_HINT_LOW_POWER, lowPowerModeEnabled ? 1 : 0);
-            mLowPowerModeEnabled = lowPowerModeEnabled;
             BackgroundThread.getHandler().post(new Runnable() {
                 @Override
                 public void run() {
@@ -2083,6 +2062,35 @@
         }
     }
 
+    private boolean setLowPowerModeInternal(boolean mode) {
+        synchronized (mLock) {
+            if (DEBUG) Slog.d(TAG, "setLowPowerModeInternal " + mode + " mIsPowered=" + mIsPowered);
+            if (mIsPowered) {
+                return false;
+            }
+            Settings.Global.putInt(mContext.getContentResolver(),
+                    Settings.Global.LOW_POWER_MODE, mode ? 1 : 0);
+            mLowPowerModeSetting = mode;
+
+            if (mAutoLowPowerModeConfigured && mBatteryLevelLow) {
+                if (mode && mAutoLowPowerModeSnoozing) {
+                    if (DEBUG_SPEW) {
+                        Slog.d(TAG, "setLowPowerModeInternal: clearing low power mode snooze");
+                    }
+                    mAutoLowPowerModeSnoozing = false;
+                } else if (!mode && !mAutoLowPowerModeSnoozing) {
+                    if (DEBUG_SPEW) {
+                        Slog.d(TAG, "setLowPowerModeInternal: snoozing low power mode");
+                    }
+                    mAutoLowPowerModeSnoozing = true;
+                }
+            }
+
+            updateLowPowerModeLocked();
+            return true;
+        }
+    }
+
     private void handleBatteryStateChangedLocked() {
         mDirty |= DIRTY_BATTERY_STATE;
         updatePowerStateLocked();
@@ -2347,7 +2355,7 @@
             pw.println("  mDreamsActivateOnDockSetting=" + mDreamsActivateOnDockSetting);
             pw.println("  mDozeAfterScreenOffConfig=" + mDozeAfterScreenOffConfig);
             pw.println("  mLowPowerModeSetting=" + mLowPowerModeSetting);
-            pw.println("  mAutoLowPowerModeEnabled=" + mAutoLowPowerModeEnabled);
+            pw.println("  mAutoLowPowerModeConfigured=" + mAutoLowPowerModeConfigured);
             pw.println("  mAutoLowPowerModeSnoozing=" + mAutoLowPowerModeSnoozing);
             pw.println("  mMinimumScreenOffTimeoutConfig=" + mMinimumScreenOffTimeoutConfig);
             pw.println("  mMaximumScreenDimDurationConfig=" + mMaximumScreenDimDurationConfig);
@@ -2963,6 +2971,18 @@
             }
         }
 
+        @Override // Binder call
+        public boolean setPowerSaveMode(boolean mode) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.DEVICE_POWER, null);
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                return setLowPowerModeInternal(mode);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
         /**
          * Reboots the device.
          *
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
index 17d990b..22265a3 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
@@ -38,6 +38,11 @@
     }
 
     @Override
+    public boolean setPowerSaveMode(boolean mode) throws RemoteException {
+        return false;
+    }
+
+    @Override
     public IBinder asBinder() {
         // pass for now.
         return null;