From 1bb480a3a4ce2ce63c5d09fa7f5cc38ec160ebf4 Mon Sep 17 00:00:00 2001 From: John Spurlock Date: Sat, 2 Aug 2014 17:12:43 -0400 Subject: 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 --- core/java/android/os/PowerManager.java | 13 ++++ core/res/AndroidManifest.xml | 1 + core/res/res/values/strings.xml | 3 + core/res/res/values/symbols.xml | 1 + packages/SystemUI/res/values/strings.xml | 13 ++-- .../systemui/power/PowerDialogWarnings.java | 6 -- .../systemui/power/PowerNotificationWarnings.java | 83 ++++++++++++++-------- .../src/com/android/systemui/power/PowerUI.java | 39 ++-------- .../systemui/statusbar/phone/PhoneStatusBar.java | 2 +- .../systemui/statusbar/phone/SystemUIDialog.java | 26 +++++++ .../statusbar/policy/BatteryController.java | 8 ++- .../android/server/power/PowerManagerService.java | 53 ++++++++++++-- 12 files changed, 163 insertions(+), 85 deletions(-) diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index dda6d27d3edd..6334f76fd7ea 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -715,6 +715,19 @@ public final class PowerManager { public static final String ACTION_POWER_SAVE_MODE_CHANGED = "android.os.action.POWER_SAVE_MODE_CHANGED"; + /** + * Intent that is broadcast when the state of {@link #isPowerSaveMode()} is about to change. + * This broadcast is only sent to registered receivers. + * + * @hide + */ + @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_POWER_SAVE_MODE_CHANGING + = "android.os.action.POWER_SAVE_MODE_CHANGING"; + + /** @hide */ + public static final String EXTRA_POWER_SAVE_MODE = "mode"; + /** * A wake lock is a mechanism to indicate that your application needs * to have the device stay on. diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index d7aea398411c..2a96580b1410 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -75,6 +75,7 @@ + diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 195851fe137c..8e626e3da103 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -4878,4 +4878,7 @@ 12세미만의 청소년이 시청하기에 부적절한 내용이 포함되어 있어 보호자의 시청지도가 필요한 등급을 말한다. 15세미만의 청소년이 시청하기에 부적절한 내용이 포함되어 있어 보호자의 시청지도가 필요한 등급을 말한다. 19세미만의 청소년이 시청하기에 부적절한 내용이 포함되어 있어 청소년이 시청할 수 없는 등급을 말한다. + + + To help improve battery life, battery saver will reduce your device’s performance and restrict background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging. diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index ccd7005e4d1d..5c8926ec14d2 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1894,6 +1894,7 @@ + diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 085d2f9953ba..296cdad40d6e 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -86,16 +86,13 @@ Settings - Start battery saver? + Turn on battery saver? - Start + Turn on - Start battery saver - - - 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. + Turn on battery saver Settings @@ -719,10 +716,10 @@ Battery saver is on - Device performance is reduced. + Reduces performance and background data - Open battery saver settings + Turn off battery saver %d%% diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerDialogWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerDialogWarnings.java index 294349457a9d..79fadbdb675a 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 @@ public class PowerDialogWarnings implements PowerUI.WarningsUI { private int mBucket; private long mScreenOffTime; private boolean mSaver; - private int mSaverTriggerLevel; private AlertDialog mInvalidChargerDialog; private AlertDialog mLowBatteryDialog; @@ -222,9 +221,4 @@ public class PowerDialogWarnings implements PowerUI.WarningsUI { 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 186b570ad5cf..9ffe0ef9dba2 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.ContentResolver; 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.SystemClock; 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 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { 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 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { 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 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { 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 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { @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 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { .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 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { 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 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { .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 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { 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 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { } 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 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { 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 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { } 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 1bb7edb5c1bc..ccef8eb543ee 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.Context; 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 @@ import java.util.Arrays; 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 @@ public class PowerUI extends SystemUI { 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 @@ public class PowerUI extends SystemUI { 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 @@ public class PowerUI extends SystemUI { 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 class PowerUI extends SystemUI { 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 @@ public class PowerUI extends SystemUI { 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 06c7be26bce7..2be3d5a75fd5 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 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, 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 86a662241d5e..d701b3c57476 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 @@ import android.view.WindowManager; */ 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 @@ public class SystemUIDialog extends AlertDialog { 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 1e655437ee1a..d1b69aba6528 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 @@ public class BatteryController extends BroadcastReceiver { 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 @@ public class BatteryController extends BroadcastReceiver { 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 @@ public class BatteryController extends BroadcastReceiver { } 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")); diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 8c52fadb7fc8..d1182e97c960 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -422,6 +422,9 @@ public final class PowerManagerService extends com.android.server.SystemService // Current state of whether the settings are allowing auto low power mode. private boolean mAutoLowPowerModeEnabled; + // The user turned off low power mode below the trigger level + private boolean mAutoLowPowerModeSnoozing; + // True if the battery level is currently considered low. private boolean mBatteryLevelLow; @@ -650,9 +653,23 @@ public final class PowerManagerService extends com.android.server.SystemService final boolean lowPowerModeEnabled = Settings.Global.getInt(resolver, Settings.Global.LOW_POWER_MODE, 0) != 0; final boolean autoLowPowerModeEnabled = Settings.Global.getInt(resolver, - Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 15) != 0; + 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; + } + } mLowPowerModeSetting = lowPowerModeEnabled; mAutoLowPowerModeEnabled = autoLowPowerModeEnabled; updateLowPowerModeLocked(); @@ -662,8 +679,25 @@ public final class PowerManagerService extends com.android.server.SystemService } void updateLowPowerModeLocked() { - final boolean lowPowerModeEnabled = !mIsPowered - && (mLowPowerModeSetting || (mAutoLowPowerModeEnabled && mBatteryLevelLow)); + if (mIsPowered && mLowPowerModeSetting) { + if (DEBUG_SPEW) { + Slog.d(TAG, "updateLowPowerModeLocked: powered, turning setting off"); + } + // Turn setting off if powered + 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; if (mLowPowerModeEnabled != lowPowerModeEnabled) { mLowPowerModeEnabled = lowPowerModeEnabled; powerHintInternal(POWER_HINT_LOW_POWER_MODE, lowPowerModeEnabled ? 1 : 0); @@ -672,6 +706,10 @@ public final class PowerManagerService extends com.android.server.SystemService BackgroundThread.getHandler().post(new Runnable() { @Override public void run() { + Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING) + .putExtra(PowerManager.EXTRA_POWER_SAVE_MODE, mLowPowerModeEnabled) + .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + mContext.sendBroadcast(intent); ArrayList listeners; synchronized (mLock) { listeners = new ArrayList( @@ -680,7 +718,7 @@ public final class PowerManagerService extends com.android.server.SystemService for (int i=0; i