Battery saver: new policy changes + SystemUI tweaks.

 - Service policy changes: allow the user to turn off (snooze)
   saver mode below the auto-trigger level.  Plugging in the
   device always exits saver mode.
 - Default trigger level is now 0 (never) instead of 15.
 - SystemUI now also listens to a new POWER_SAVE_MODE_CHANGING,
   since waiting for _CHANGED can take seconds.
 - Move shared feature description text into the framework so it
   can be shared.
 - Tweak dialog title + action strings.
 - Remove trigger-level from SystemUI, it no longer needs it.
 - Add the ability to turn off saver mode directly from the
   notification.
 - Migrate saver confirmation dialog to common system UI dialog
   helper, and add a few convenience methods.
 - Fix bug where the status bar area would be orange over the keyguard
   in SHADE_LOCKED mode.

Bug:16214395
Change-Id: I3d1ded1eec9e63e7d97469486f6a320e1bebbccd
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 085d2f9..296cdad 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -86,16 +86,13 @@
     <string name="battery_low_why">Settings</string>
 
     <!-- Battery saver confirmation dialog title [CHAR LIMIT=NONE]-->
-    <string name="battery_saver_confirmation_title">Start battery saver?</string>
+    <string name="battery_saver_confirmation_title">Turn on battery saver?</string>
 
     <!-- Battery saver confirmation dialog ok text [CHAR LIMIT=40]-->
-    <string name="battery_saver_confirmation_ok">Start</string>
+    <string name="battery_saver_confirmation_ok">Turn on</string>
 
     <!-- Battery saver notification action [CHAR LIMIT=NONE]-->
-    <string name="battery_saver_start_action">Start battery saver</string>
-
-    <!-- Battery saver confirmation dialog text [CHAR LIMIT=NONE]-->
-    <string name="battery_saver_confirmation_text">To help improve battery life, Battery saver will reduce your device’s performance.\n\nBattery saver will be disabled when your device is plugged in.</string>
+    <string name="battery_saver_start_action">Turn on battery saver</string>
 
     <!-- Name of the button that links to the Settings app. [CHAR LIMIT=NONE] -->
     <string name="status_bar_settings_settings_button">Settings</string>
@@ -719,10 +716,10 @@
     <string name="battery_saver_notification_title">Battery saver is on</string>
 
     <!-- Battery saver notification text. [CHAR LIMIT=60] -->
-    <string name="battery_saver_notification_text">Device performance is reduced.</string>
+    <string name="battery_saver_notification_text">Reduces performance and background data</string>
 
     <!-- Battery saver notification action text. [CHAR LIMIT=60] -->
-    <string name="battery_saver_notification_action_text">Open battery saver settings</string>
+    <string name="battery_saver_notification_action_text">Turn off battery saver</string>
 
     <!-- Battery level for expanded quick settings [CHAR LIMIT=2] -->
     <string name="battery_level_template"><xliff:g id="level" example="45">%d</xliff:g>%%</string>
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerDialogWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerDialogWarnings.java
index 2943494..79fadbd 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerDialogWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerDialogWarnings.java
@@ -48,7 +48,6 @@
     private int mBucket;
     private long mScreenOffTime;
     private boolean mSaver;
-    private int mSaverTriggerLevel;
 
     private AlertDialog mInvalidChargerDialog;
     private AlertDialog mLowBatteryDialog;
@@ -222,9 +221,4 @@
     public void showSaverMode(boolean mode) {
         mSaver = mode;
     }
-
-    @Override
-    public void setSaverTrigger(int level) {
-        mSaverTriggerLevel = level;
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index 186b570..9ffe0ef 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.power;
 
-import android.app.AlertDialog;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -25,9 +24,10 @@
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.DialogInterface.OnClickListener;
+import android.content.DialogInterface.OnDismissListener;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.media.AudioManager;
+import android.media.AudioAttributes;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Handler;
@@ -35,11 +35,10 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.Slog;
-import android.view.ContextThemeWrapper;
 import android.view.View;
-import android.view.WindowManager;
 
 import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
 
 import java.io.PrintWriter;
 
@@ -66,9 +65,14 @@
     private static final String ACTION_SHOW_FALLBACK_CHARGER = "PNW.chargerFallback";
     private static final String ACTION_SHOW_BATTERY_SETTINGS = "PNW.batterySettings";
     private static final String ACTION_START_SAVER = "PNW.startSaver";
+    private static final String ACTION_STOP_SAVER = "PNW.stopSaver";
+
+    private static final AudioAttributes AUDIO_ATTRIBUTES = new AudioAttributes.Builder()
+            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+            .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+            .build();
 
     private final Context mContext;
-    private final Context mLightContext;
     private final NotificationManager mNoMan;
     private final Handler mHandler = new Handler();
     private final PowerDialogWarnings mFallbackDialogs;
@@ -84,15 +88,13 @@
     private long mBucketDroppedNegativeTimeMs;
 
     private boolean mSaver;
-    private int mSaverTriggerLevel;
     private boolean mWarning;
     private boolean mPlaySound;
     private boolean mInvalidCharger;
+    private SystemUIDialog mSaverConfirmation;
 
     public PowerNotificationWarnings(Context context) {
         mContext = context;
-        mLightContext = new ContextThemeWrapper(mContext,
-                android.R.style.Theme_DeviceDefault_Light);
         mNoMan = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
         mFallbackDialogs = new PowerDialogWarnings(context);
         mReceiver.init();
@@ -105,6 +107,7 @@
         pw.print("mPlaySound="); pw.println(mPlaySound);
         pw.print("mInvalidCharger="); pw.println(mInvalidCharger);
         pw.print("mShowing="); pw.println(SHOWING_STRINGS[mShowing]);
+        pw.print("mSaverConfirmation="); pw.println(mSaverConfirmation != null ? "not null" : null);
     }
 
     @Override
@@ -123,12 +126,9 @@
     @Override
     public void showSaverMode(boolean mode) {
         mSaver = mode;
-        updateNotification();
-    }
-
-    @Override
-    public void setSaverTrigger(int level) {
-        mSaverTriggerLevel = level;
+        if (mSaver && mSaverConfirmation != null) {
+            mSaverConfirmation.dismiss();
+        }
         updateNotification();
     }
 
@@ -180,6 +180,7 @@
                 .setContentTitle(mContext.getString(R.string.battery_low_title))
                 .setContentText(mContext.getString(textRes, mBatteryLevel))
                 .setOngoing(true)
+                .setOnlyAlertOnce(true)
                 .setPriority(Notification.PRIORITY_MAX)
                 .setCategory(Notification.CATEGORY_SYSTEM)
                 .setVisibility(Notification.VISIBILITY_PUBLIC)
@@ -187,10 +188,12 @@
         if (hasBatterySettings()) {
             nb.setContentIntent(pendingBroadcast(ACTION_SHOW_BATTERY_SETTINGS));
         }
-        if (!mSaver && mSaverTriggerLevel <= 0) {
+        if (!mSaver) {
             nb.addAction(R.drawable.ic_power_saver,
                     mContext.getString(R.string.battery_saver_start_action),
                     pendingBroadcast(ACTION_START_SAVER));
+        } else {
+            addStopSaverAction(nb);
         }
         if (mPlaySound) {
             attachLowBatterySound(nb);
@@ -208,19 +211,28 @@
                 .setContentTitle(mContext.getString(R.string.battery_saver_notification_title))
                 .setContentText(mContext.getString(R.string.battery_saver_notification_text))
                 .setOngoing(true)
-                .setWhen(0)
                 .setShowWhen(false)
                 .setCategory(Notification.CATEGORY_SYSTEM)
                 .setVisibility(Notification.VISIBILITY_PUBLIC);
+        addStopSaverAction(nb);
         if (hasSaverSettings()) {
-            nb.addAction(0,
-                    mContext.getString(R.string.battery_saver_notification_action_text),
-                    pendingActivity(mOpenSaverSettings));
             nb.setContentIntent(pendingActivity(mOpenSaverSettings));
         }
         mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, nb.build(), UserHandle.CURRENT);
     }
 
+    private void addStopSaverAction(Notification.Builder nb) {
+        nb.addAction(R.drawable.ic_power_saver,
+                mContext.getString(R.string.battery_saver_notification_action_text),
+                pendingBroadcast(ACTION_STOP_SAVER));
+    }
+
+    private void dismissSaverNotification() {
+        if (mSaver) Slog.i(TAG, "dismissing saver notification");
+        mSaver = false;
+        updateNotification();
+    }
+
     private PendingIntent pendingActivity(Intent intent) {
         return PendingIntent.getActivityAsUser(mContext,
                 0, intent, 0, null, UserHandle.CURRENT);
@@ -307,8 +319,8 @@
             if (soundPath != null) {
                 final Uri soundUri = Uri.parse("file://" + soundPath);
                 if (soundUri != null) {
-                    b.setSound(soundUri, AudioManager.STREAM_SYSTEM);
-                    Slog.d(TAG, "playing sound " + soundUri);
+                    b.setSound(soundUri, AUDIO_ATTRIBUTES);
+                    if (DEBUG) Slog.d(TAG, "playing sound " + soundUri);
                 }
             }
         }
@@ -333,17 +345,21 @@
     }
 
     private void showStartSaverConfirmation() {
-        final AlertDialog d = new AlertDialog.Builder(mLightContext)
-                .setTitle(R.string.battery_saver_confirmation_title)
-                .setMessage(R.string.battery_saver_confirmation_text)
-                .setNegativeButton(android.R.string.cancel, null)
-                .setPositiveButton(R.string.battery_saver_confirmation_ok, mStartSaverMode)
-                .create();
-
-        d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
-        d.getWindow().getAttributes().privateFlags |=
-                WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+        if (mSaverConfirmation != null) return;
+        final SystemUIDialog d = new SystemUIDialog(mContext);
+        d.setTitle(R.string.battery_saver_confirmation_title);
+        d.setMessage(com.android.internal.R.string.battery_saver_description);
+        d.setNegativeButton(android.R.string.cancel, null);
+        d.setPositiveButton(R.string.battery_saver_confirmation_ok, mStartSaverMode);
+        d.setShowForAllUsers(true);
+        d.setOnDismissListener(new OnDismissListener() {
+            @Override
+            public void onDismiss(DialogInterface dialog) {
+                mSaverConfirmation = null;
+            }
+        });
         d.show();
+        mSaverConfirmation = d;
     }
 
     private void setSaverSetting(boolean mode) {
@@ -359,6 +375,7 @@
             filter.addAction(ACTION_SHOW_FALLBACK_CHARGER);
             filter.addAction(ACTION_SHOW_BATTERY_SETTINGS);
             filter.addAction(ACTION_START_SAVER);
+            filter.addAction(ACTION_STOP_SAVER);
             mContext.registerReceiver(this, filter, null, mHandler);
         }
 
@@ -378,6 +395,10 @@
             } else if (action.equals(ACTION_START_SAVER)) {
                 dismissLowBatteryNotification();
                 showStartSaverConfirmation();
+            } else if (action.equals(ACTION_STOP_SAVER)) {
+                dismissSaverNotification();
+                dismissLowBatteryNotification();
+                setSaverSetting(false);
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 1bb7edb..ccef8eb 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -22,13 +22,13 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.database.ContentObserver;
-import android.net.Uri;
 import android.os.BatteryManager;
 import android.os.Handler;
 import android.os.PowerManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.util.Log;
 import android.util.Slog;
 
 import com.android.systemui.SystemUI;
@@ -39,11 +39,9 @@
 
 public class PowerUI extends SystemUI {
     static final String TAG = "PowerUI";
-    static final boolean DEBUG = false;
-
+    static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     private final Handler mHandler = new Handler();
-    private final SettingsObserver mObserver = new SettingsObserver(mHandler);
     private final Receiver mReceiver = new Receiver();
 
     private PowerManager mPowerManager;
@@ -75,17 +73,12 @@
                 false, obs, UserHandle.USER_ALL);
         updateBatteryWarningLevels();
         mReceiver.init();
-        mObserver.init();
     }
 
     private void setSaverMode(boolean mode) {
         mWarnings.showSaverMode(mode);
     }
 
-    private void setSaverTrigger(int level) {
-        mWarnings.setSaverTrigger(level);
-    }
-
     void updateBatteryWarningLevels() {
         int critLevel = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_criticalBatteryWarningLevel);
@@ -143,6 +136,7 @@
             filter.addAction(Intent.ACTION_BATTERY_CHANGED);
             filter.addAction(Intent.ACTION_SCREEN_OFF);
             filter.addAction(Intent.ACTION_SCREEN_ON);
+            filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING);
             filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
             mContext.registerReceiver(this, filter, null, mHandler);
             updateSaverMode();
@@ -214,6 +208,8 @@
                 mScreenOffTime = -1;
             } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)) {
                 updateSaverMode();
+            } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGING.equals(action)) {
+                setSaverMode(intent.getBooleanExtra(PowerManager.EXTRA_POWER_SAVE_MODE, false));
             } else {
                 Slog.w(TAG, "unknown intent: " + intent);
             }
@@ -251,7 +247,6 @@
 
     public interface WarningsUI {
         void update(int batteryLevel, int bucket, long screenOffTime);
-        void setSaverTrigger(int level);
         void showSaverMode(boolean mode);
         void dismissLowBatteryWarning();
         void showLowBatteryWarning(boolean playSound);
@@ -261,29 +256,5 @@
         boolean isInvalidChargerWarningShowing();
         void dump(PrintWriter pw);
     }
-
-    private final class SettingsObserver extends ContentObserver {
-        private final Uri LOW_POWER_MODE_TRIGGER_LEVEL_URI =
-                Settings.Global.getUriFor(Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL);
-
-        public SettingsObserver(Handler handler) {
-            super(handler);
-        }
-
-        public void init() {
-            onChange(true, LOW_POWER_MODE_TRIGGER_LEVEL_URI);
-            final ContentResolver cr = mContext.getContentResolver();
-            cr.registerContentObserver(LOW_POWER_MODE_TRIGGER_LEVEL_URI, false, this);
-        }
-
-        @Override
-        public void onChange(boolean selfChange, Uri uri) {
-            if (LOW_POWER_MODE_TRIGGER_LEVEL_URI.equals(uri)) {
-                final int level = Settings.Global.getInt(mContext.getContentResolver(),
-                        Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
-                setSaverTrigger(level);
-            }
-        }
-    }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 06c7be2..2be3d5a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -2436,7 +2436,7 @@
         final boolean powerSave = mBatteryController.isPowerSave();
         final boolean anim = (mScreenOn == null || mScreenOn) && windowState != WINDOW_STATE_HIDDEN
                 && !powerSave;
-        if (powerSave && getBarState() != StatusBarState.KEYGUARD) {
+        if (powerSave && getBarState() == StatusBarState.SHADE) {
             mode = MODE_WARNING;
         }
         transitions.transitionTo(mode, anim);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
index 86a6622..d701b3c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
@@ -27,8 +27,12 @@
  */
 public class SystemUIDialog extends AlertDialog {
 
+    private final Context mContext;
+
     public SystemUIDialog(Context context) {
         super(context, R.style.Theme_SystemUI_Dialog);
+        mContext = context;
+
         getWindow().setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL);
         getWindow().addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
                 | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
@@ -36,4 +40,26 @@
         attrs.setTitle(getClass().getSimpleName());
         getWindow().setAttributes(attrs);
     }
+
+    public void setShowForAllUsers(boolean show) {
+        if (show) {
+            getWindow().getAttributes().privateFlags |=
+                    WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+        } else {
+            getWindow().getAttributes().privateFlags &=
+                    ~WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+        }
+    }
+
+    public void setMessage(int resId) {
+        setMessage(mContext.getString(resId));
+    }
+
+    public void setPositiveButton(int resId, OnClickListener onClick) {
+        setButton(BUTTON_POSITIVE, mContext.getString(resId), onClick);
+    }
+
+    public void setNegativeButton(int resId, OnClickListener onClick) {
+        setButton(BUTTON_NEGATIVE, mContext.getString(resId), onClick);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
index 1e65543..d1b69ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -47,6 +47,7 @@
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_BATTERY_CHANGED);
         filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
+        filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING);
         context.registerReceiver(this, filter);
 
         updatePowerSave();
@@ -86,6 +87,8 @@
             fireBatteryLevelChanged();
         } else if (action.equals(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)) {
             updatePowerSave();
+        } else if (action.equals(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING)) {
+            setPowerSave(intent.getBooleanExtra(PowerManager.EXTRA_POWER_SAVE_MODE, false));
         }
     }
 
@@ -94,7 +97,10 @@
     }
 
     private void updatePowerSave() {
-        final boolean powerSave = mPowerManager.isPowerSaveMode();
+        setPowerSave(mPowerManager.isPowerSaveMode());
+    }
+
+    private void setPowerSave(boolean powerSave) {
         if (powerSave == mPowerSave) return;
         mPowerSave = powerSave;
         if (DEBUG) Log.d(TAG, "Power save is " + (mPowerSave ? "on" : "off"));