diff options
10 files changed, 221 insertions, 27 deletions
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index a013d3d66d3b..c2ad77f50acc 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -7793,6 +7793,14 @@ public final class Settings { "low_power_warning_acknowledged"; /** + * 0 (default) Auto battery saver suggestion has not been suppressed. 1) it has been + * suppressed. + * @hide + */ + public static final String SUPPRESS_AUTO_BATTERY_SAVER_SUGGESTION = + "suppress_auto_battery_saver_suggestion"; + + /** * This are the settings to be backed up. * * NOTE: Settings are backed up and restored in the order they appear diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 55c17b9b2af4..098973ce7135 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1095,6 +1095,9 @@ <!-- Display low battery warning when battery level dips to this value --> <integer name="config_lowBatteryWarningLevel">15</integer> + <!-- The default suggested battery % at which we enable battery saver automatically. --> + <integer name="config_lowBatteryAutoTriggerDefaultLevel">15</integer> + <!-- Close low battery warning when battery level reaches the lowBatteryWarningLevel plus this --> <integer name="config_lowBatteryCloseWarningBump">5</integer> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 75f80137da03..45da1ccb70b2 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3312,4 +3312,6 @@ <java-symbol type="string" name="notification_app_name_system" /> <java-symbol type="string" name="notification_app_name_settings" /> + <java-symbol type="integer" name="config_lowBatteryAutoTriggerDefaultLevel" /> + </resources> diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index a504ab9dda2d..0d6b24ac1abc 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -585,7 +585,8 @@ public class SettingsBackupTest { Settings.Secure.PARENTAL_CONTROL_REDIRECT_URL, Settings.Secure.BLUETOOTH_ON_WHILE_DRIVING, Settings.Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, - Settings.Secure.LOW_POWER_WARNING_ACKNOWLEDGED); + Settings.Secure.LOW_POWER_WARNING_ACKNOWLEDGED, + Settings.Secure.SUPPRESS_AUTO_BATTERY_SAVER_SUGGESTION); @Test public void systemSettingsBackedUpOrBlacklisted() { diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java index e2c7747e3231..28833a349372 100644 --- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java @@ -20,7 +20,9 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.os.PowerManager; +import android.provider.Settings.Global; import android.provider.Settings.Secure; +import android.support.annotation.VisibleForTesting; import android.util.Log; /** @@ -34,10 +36,27 @@ public class BatterySaverUtils { private static final boolean DEBUG = false; - // Broadcast action for SystemUI to show the battery saver confirmation dialog. + private static final String SYSUI_PACKAGE = "com.android.systemui"; + + /** Broadcast action for SystemUI to show the battery saver confirmation dialog. */ public static final String ACTION_SHOW_START_SAVER_CONFIRMATION = "PNW.startSaverConfirmation"; /** + * Broadcast action for SystemUI to show the notification that suggests turning on + * automatic battery saver. + */ + public static final String ACTION_SHOW_AUTO_SAVER_SUGGESTION + = "PNW.autoSaverSuggestion"; + + /** + * We show the auto battery saver suggestion notification when the user manually enables + * battery saver for the START_NTH time through the END_NTH time. + * (We won't show it for END_NTH + 1 time and after.) + */ + private static final int AUTO_SAVER_SUGGESTION_START_NTH = 4; + private static final int AUTO_SAVER_SUGGESTION_END_NTH = 8; + + /** * Enable / disable battery saver by user request. * - If it's the first time and needFirstTimeWarning, show the first time dialog. * - If it's 4th time through 8th time, show the schedule suggestion notification. @@ -62,11 +81,17 @@ public class BatterySaverUtils { if (context.getSystemService(PowerManager.class).setPowerSaveMode(enable)) { if (enable) { - Secure.putInt(cr, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, - Secure.getInt(cr, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, 0) + 1); + final int count = + Secure.getInt(cr, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, 0) + 1; + Secure.putInt(cr, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, count); - // TODO If enabling, and the count is between 4 and 8 (inclusive), then - // show the "battery saver schedule suggestion" notification. + if ((count >= AUTO_SAVER_SUGGESTION_START_NTH) + && (count <= AUTO_SAVER_SUGGESTION_END_NTH) + && Global.getInt(cr, Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0) == 0 + && Secure.getInt(cr, + Secure.SUPPRESS_AUTO_BATTERY_SAVER_SUGGESTION, 0) == 0) { + showAutoBatterySaverSuggestion(context); + } } return true; @@ -79,13 +104,34 @@ public class BatterySaverUtils { Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 0) != 0) { return false; // Already shown. } - final Intent i = new Intent(ACTION_SHOW_START_SAVER_CONFIRMATION); - context.sendBroadcast(i); - + context.sendBroadcast(getSystemUiBroadcast(ACTION_SHOW_START_SAVER_CONFIRMATION)); return true; } + private static void showAutoBatterySaverSuggestion(Context context) { + context.sendBroadcast(getSystemUiBroadcast(ACTION_SHOW_AUTO_SAVER_SUGGESTION)); + } + + private static Intent getSystemUiBroadcast(String action) { + final Intent i = new Intent(action); + i.setFlags(Intent.FLAG_RECEIVER_FOREGROUND); + i.setPackage(SYSUI_PACKAGE); + return i; + } + private static void setBatterySaverConfirmationAcknowledged(Context context) { Secure.putInt(context.getContentResolver(), Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 1); } + + public static void suppressAutoBatterySaver(Context context) { + Secure.putInt(context.getContentResolver(), + Secure.SUPPRESS_AUTO_BATTERY_SAVER_SUGGESTION, 1); + } + + public static void scheduleAutoBatterySaver(Context context, int level) { + if (Global.getInt(context.getContentResolver(), Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0) + == 0) { + Global.putInt(context.getContentResolver(), Global.LOW_POWER_MODE_TRIGGER_LEVEL, level); + } + } } diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 131b35cb0109..6efb15cb77a4 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2095,6 +2095,8 @@ <string name="notification_channel_general">General Messages</string> <!-- Title for the notification channel for problems with storage (i.e. low disk). [CHAR LIMIT=NONE] --> <string name="notification_channel_storage">Storage</string> + <!-- Title for the notification channel for hints and suggestions. [CHAR LIMIT=NONE] --> + <string name="notification_channel_hints">Hints</string> <!-- App label of the instant apps notification [CHAR LIMIT=60] --> <string name="instant_apps">Instant Apps</string> @@ -2185,4 +2187,25 @@ <string-array name="recents_onboarding_blacklisted_packages" translatable="false"> </string-array> + <!-- The title of the notification to suggest enabling automatic battery saver. [CHAR LIMIT=NONE]--> + <string name="auto_saver_title">Tap to schedule Battery Saver</string> + + <!-- The content of the notification to suggest enabling automatic battery saver. [CHAR LIMIT=NONE]--> + <string name="auto_saver_text">Turn on automatically when battery is at <xliff:g id="percentage">%d</xliff:g>%%</string> + + <!-- An action on the notification to suggest enabling automatic battery saver: Do not turn on automatic battery saver. [CHAR LIMIT=NONE]--> + <string name="no_auto_saver_action">No thanks</string> + + <!-- The title of the dialog that tells that scheduled (i.e. automatic) battery saver has been turned on. [CHAR LIMIT=NONE]--> + <string name="auto_saver_enabled_title">Battery Saver schedule turned on</string> + + <!-- The content of the dialog that tells that scheduled (i.e. automatic) battery saver has been turned on. [CHAR LIMIT=NONE]--> + <string name="auto_saver_enabled_text">Battery Saver will turn on automatically once battery goes below <xliff:g id="percentage">%d</xliff:g>%%.</string> + + <!-- An action on the dialog that tells that scheduled (i.e. automatic) battery saver: open the battery saver setting. [CHAR LIMIT=NONE]--> + <string name="open_saver_setting_action">Settings</string> + + <!-- An action on the dialog that tells that scheduled (i.e. automatic) battery saver: user acknowledges and closes the dialog. [CHAR LIMIT=NONE]--> + <string name="auto_saver_okay_action">Got it</string> + </resources> diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java index 8d931579f1cf..49b00ce13233 100644 --- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java +++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java @@ -21,9 +21,6 @@ import android.app.NotificationManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; 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.AudioAttributes; @@ -52,15 +49,18 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { private static final String TAG_BATTERY = "low_battery"; private static final String TAG_TEMPERATURE = "high_temp"; + private static final String TAG_AUTO_SAVER = "auto_saver"; private static final int SHOWING_NOTHING = 0; private static final int SHOWING_WARNING = 1; private static final int SHOWING_INVALID_CHARGER = 3; + private static final int SHOWING_AUTO_SAVER_SUGGESTION = 4; private static final String[] SHOWING_STRINGS = { "SHOWING_NOTHING", "SHOWING_WARNING", "SHOWING_SAVER", "SHOWING_INVALID_CHARGER", + "SHOWING_AUTO_SAVER_SUGGESTION", }; private static final String ACTION_SHOW_BATTERY_SETTINGS = "PNW.batterySettings"; @@ -74,6 +74,18 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { "PNW.dismissedThermalShutdownWarning"; private static final String ACTION_SHOW_START_SAVER_CONFIRMATION = BatterySaverUtils.ACTION_SHOW_START_SAVER_CONFIRMATION; + private static final String ACTION_SHOW_AUTO_SAVER_SUGGESTION = + BatterySaverUtils.ACTION_SHOW_AUTO_SAVER_SUGGESTION; + private static final String ACTION_DISMISS_AUTO_SAVER_SUGGESTION = + "PNW.dismissAutoSaverSuggestion"; + + private static final String ACTION_ENABLE_AUTO_SAVER = + "PNW.enableAutoSaver"; + private static final String ACTION_AUTO_SAVER_NO_THANKS = + "PNW.autoSaverNoThanks"; + + private static final String SETTINGS_ACTION_OPEN_BATTERY_SAVER_SETTING = + "android.settings.BATTERY_SAVER_SETTINGS"; private static final AudioAttributes AUDIO_ATTRIBUTES = new AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) @@ -98,9 +110,11 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { private long mLowWarningThreshold; private long mSevereWarningThreshold; private boolean mWarning; + private boolean mShowAutoSaverSuggestion; private boolean mPlaySound; private boolean mInvalidCharger; private SystemUIDialog mSaverConfirmation; + private SystemUIDialog mSaverEnabledConfirmation; private boolean mHighTempWarning; private SystemUIDialog mHighTempDialog; private SystemUIDialog mThermalShutdownDialog; @@ -119,12 +133,19 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { pw.print("mInvalidCharger="); pw.println(mInvalidCharger); pw.print("mShowing="); pw.println(SHOWING_STRINGS[mShowing]); pw.print("mSaverConfirmation="); pw.println(mSaverConfirmation != null ? "not null" : null); + pw.print("mSaverEnabledConfirmation="); + pw.println(mSaverEnabledConfirmation != null ? "not null" : null); pw.print("mHighTempWarning="); pw.println(mHighTempWarning); pw.print("mHighTempDialog="); pw.println(mHighTempDialog != null ? "not null" : null); pw.print("mThermalShutdownDialog="); pw.println(mThermalShutdownDialog != null ? "not null" : null); } + private int getLowBatteryAutoTriggerDefaultLevel() { + return mContext.getResources().getInteger( + com.android.internal.R.integer.config_lowBatteryAutoTriggerDefaultLevel); + } + @Override public void update(int batteryLevel, int bucket, long screenOffTime) { mBatteryLevel = batteryLevel; @@ -151,7 +172,6 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { mSevereWarningThreshold = severeThreshold; } - private void updateNotification() { if (DEBUG) Slog.d(TAG, "updateNotification mWarning=" + mWarning + " mPlaySound=" + mPlaySound + " mInvalidCharger=" + mInvalidCharger); @@ -161,9 +181,14 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { } else if (mWarning) { showWarningNotification(); mShowing = SHOWING_WARNING; + } else if (mShowAutoSaverSuggestion) { + showAutoSaverSuggestionNotification(); + mShowing = SHOWING_AUTO_SAVER_SUGGESTION; } else { mNoMan.cancelAsUser(TAG_BATTERY, SystemMessage.NOTE_BAD_CHARGER, UserHandle.ALL); mNoMan.cancelAsUser(TAG_BATTERY, SystemMessage.NOTE_POWER_LOW, UserHandle.ALL); + mNoMan.cancelAsUser(TAG_AUTO_SAVER, + SystemMessage.NOTE_AUTO_SAVER_SUGGESTION, UserHandle.ALL); mShowing = SHOWING_NOTHING; } } @@ -229,6 +254,28 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { mNoMan.notifyAsUser(TAG_BATTERY, SystemMessage.NOTE_POWER_LOW, n, UserHandle.ALL); } + private void showAutoSaverSuggestionNotification() { + final Notification.Builder nb = + new Notification.Builder(mContext, NotificationChannels.HINTS) + .setSmallIcon(R.drawable.ic_power_saver) + .setWhen(0) + .setShowWhen(false) + .setContentTitle(mContext.getString(R.string.auto_saver_title)) + .setContentText(mContext.getString(R.string.auto_saver_text, + getLowBatteryAutoTriggerDefaultLevel())); + nb.setContentIntent(pendingBroadcast(ACTION_ENABLE_AUTO_SAVER)); + nb.setDeleteIntent(pendingBroadcast(ACTION_DISMISS_AUTO_SAVER_SUGGESTION)); + nb.addAction(0, + mContext.getString(R.string.no_auto_saver_action), + pendingBroadcast(ACTION_AUTO_SAVER_NO_THANKS)); + + SystemUI.overrideNotificationAppName(mContext, nb, false); + + final Notification n = nb.build(); + mNoMan.notifyAsUser( + TAG_AUTO_SAVER, SystemMessage.NOTE_AUTO_SAVER_SUGGESTION, n, UserHandle.ALL); + } + private String getHybridContentString(String percentage) { return PowerUtil.getBatteryRemainingStringFormatted( mContext, @@ -238,8 +285,8 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { } private PendingIntent pendingBroadcast(String action) { - return PendingIntent.getBroadcastAsUser(mContext, - 0, new Intent(action), 0, UserHandle.CURRENT); + return PendingIntent.getBroadcastAsUser(mContext, 0, + new Intent(action).setPackage(mContext.getPackageName()), 0, UserHandle.CURRENT); } private static Intent settings(String action) { @@ -394,6 +441,16 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { updateNotification(); } + private void showAutoSaverSuggestion() { + mShowAutoSaverSuggestion = true; + updateNotification(); + } + + private void dismissAutoSaverSuggestion() { + mShowAutoSaverSuggestion = false; + updateNotification(); + } + @Override public void userSwitched() { updateNotification(); @@ -405,22 +462,53 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { 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, mStartSaverModeNoConfirmation); + d.setPositiveButton(R.string.battery_saver_confirmation_ok, + (dialog, which) -> setSaverMode(true, false)); d.setShowForAllUsers(true); - d.setOnDismissListener(new OnDismissListener() { - @Override - public void onDismiss(DialogInterface dialog) { - mSaverConfirmation = null; - } - }); + d.setOnDismissListener((dialog) -> mSaverConfirmation = null); d.show(); mSaverConfirmation = d; } + private void showAutoSaverEnabledConfirmation() { + if (mSaverEnabledConfirmation != null) return; + + // Open the Battery Saver setting page. + final Intent actionBatterySaverSetting = + new Intent(SETTINGS_ACTION_OPEN_BATTERY_SAVER_SETTING) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + final SystemUIDialog d = new SystemUIDialog(mContext); + d.setTitle(R.string.auto_saver_enabled_title); + d.setMessage(mContext.getString(R.string.auto_saver_enabled_text, + getLowBatteryAutoTriggerDefaultLevel())); + + // Negative == "got it". Just close the dialog. Battery saver has already been enabled. + d.setNegativeButton(R.string.auto_saver_okay_action, null); + d.setPositiveButton(R.string.open_saver_setting_action, (dialog, which) -> + mContext.startActivity(actionBatterySaverSetting)); + d.setShowForAllUsers(true); + d.setOnDismissListener((dialog) -> mSaverEnabledConfirmation = null); + d.show(); + mSaverEnabledConfirmation = d; + } + + private void setSaverMode(boolean mode, boolean needFirstTimeWarning) { BatterySaverUtils.setPowerSaveMode(mContext, mode, needFirstTimeWarning); } + private void scheduleAutoBatterySaver() { + int autoTriggerThreshold = mContext.getResources().getInteger( + com.android.internal.R.integer.config_lowBatteryWarningLevel); + if (autoTriggerThreshold == 0) { + autoTriggerThreshold = 15; + } + + BatterySaverUtils.scheduleAutoBatterySaver(mContext, autoTriggerThreshold); + showAutoSaverEnabledConfirmation(); + } + private final class Receiver extends BroadcastReceiver { public void init() { @@ -433,6 +521,9 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { filter.addAction(ACTION_CLICKED_THERMAL_SHUTDOWN_WARNING); filter.addAction(ACTION_DISMISSED_THERMAL_SHUTDOWN_WARNING); filter.addAction(ACTION_SHOW_START_SAVER_CONFIRMATION); + filter.addAction(ACTION_SHOW_AUTO_SAVER_SUGGESTION); + filter.addAction(ACTION_ENABLE_AUTO_SAVER); + filter.addAction(ACTION_AUTO_SAVER_NO_THANKS); mContext.registerReceiverAsUser(this, UserHandle.ALL, filter, android.Manifest.permission.DEVICE_POWER, mHandler); } @@ -462,10 +553,17 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { showThermalShutdownDialog(); } else if (ACTION_DISMISSED_THERMAL_SHUTDOWN_WARNING.equals(action)) { dismissThermalShutdownWarning(); + } else if (ACTION_SHOW_AUTO_SAVER_SUGGESTION.equals(action)) { + showAutoSaverSuggestion(); + } else if (ACTION_DISMISS_AUTO_SAVER_SUGGESTION.equals(action)) { + dismissAutoSaverSuggestion(); + } else if (ACTION_ENABLE_AUTO_SAVER.equals(action)) { + dismissAutoSaverSuggestion(); + scheduleAutoBatterySaver(); + } else if (ACTION_AUTO_SAVER_NO_THANKS.equals(action)) { + dismissAutoSaverSuggestion(); + BatterySaverUtils.suppressAutoBatterySaver(context); } } } - - private final OnClickListener mStartSaverModeNoConfirmation = - (dialog, which) -> setSaverMode(true, false); } diff --git a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java index fc932c306fd3..1cbdfe81869d 100644 --- a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java +++ b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java @@ -37,6 +37,7 @@ public class NotificationChannels extends SystemUI { public static String STORAGE = "DSK"; public static String TVPIP = "TPP"; public static String BATTERY = "BAT"; + public static String HINTS = "HNT"; @VisibleForTesting static void createAll(Context context) { @@ -73,6 +74,12 @@ public class NotificationChannels extends SystemUI { : NotificationManager.IMPORTANCE_LOW); storage.setBypassDnd(true); + final NotificationChannel hint = new NotificationChannel( + HINTS, + context.getString(R.string.notification_channel_hints), + NotificationManager.IMPORTANCE_DEFAULT); + // No need to bypass DND. + nm.createNotificationChannels(Arrays.asList( alerts, general, @@ -80,7 +87,8 @@ public class NotificationChannels extends SystemUI { createScreenshotChannel( context.getString(R.string.notification_channel_screenshot), nm.getNotificationChannel(SCREENSHOTS_LEGACY)), - batteryChannel + batteryChannel, + hint )); // Delete older SS channel if present. diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java index 80dc2c97e1e0..50b4f3f15d8a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/util/ChannelsTest.java @@ -60,7 +60,8 @@ public class ChannelsTest extends SysuiTestCase { NotificationChannels.SCREENSHOTS_HEADSUP, NotificationChannels.STORAGE, NotificationChannels.GENERAL, - NotificationChannels.BATTERY + NotificationChannels.BATTERY, + NotificationChannels.HINTS )); NotificationChannels.createAll(mContext); ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class); diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto index 608970f59a66..f9af31c96c92 100644 --- a/proto/src/system_messages.proto +++ b/proto/src/system_messages.proto @@ -208,6 +208,10 @@ message SystemMessage { // Package: android NOTE_ZEN_UPGRADE = 48; + // Notification to suggest automatic battery saver. + // Package: android + NOTE_AUTO_SAVER_SUGGESTION = 49; + // ADD_NEW_IDS_ABOVE_THIS_LINE // Legacy IDs with arbitrary values appear below // Legacy IDs existed as stable non-conflicting constants prior to the O release |