blob: d860fc52b97c9dbbe47a193995124d1247ec905d [file] [log] [blame]
John Spurlock3332ba52014-03-10 17:44:07 -04001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.systemui.power;
18
John Spurlock3332ba52014-03-10 17:44:07 -040019import android.app.Notification;
20import android.app.NotificationManager;
21import android.app.PendingIntent;
22import android.content.BroadcastReceiver;
John Spurlock3332ba52014-03-10 17:44:07 -040023import android.content.Context;
John Spurlock3332ba52014-03-10 17:44:07 -040024import android.content.Intent;
25import android.content.IntentFilter;
John Spurlock1bb480a2014-08-02 17:12:43 -040026import android.media.AudioAttributes;
John Spurlock3332ba52014-03-10 17:44:07 -040027import android.os.Handler;
Geoffrey Pitsch4a7931d2016-09-15 13:11:47 -040028import android.os.Looper;
John Spurlock8d4e6cb2014-09-14 11:10:22 -040029import android.os.PowerManager;
John Spurlock3332ba52014-03-10 17:44:07 -040030import android.os.UserHandle;
Salvador Martineza6f7b252017-04-10 10:46:15 -070031import android.support.annotation.VisibleForTesting;
John Spurlock3332ba52014-03-10 17:44:07 -040032import android.util.Slog;
John Spurlock3332ba52014-03-10 17:44:07 -040033
Chris Wren5e6c0ff2017-01-05 12:57:06 -050034import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
Jason Monk58be7a62017-02-01 20:17:51 -050035import com.android.settingslib.Utils;
Makoto Onuki16a0dd22018-03-20 10:40:37 -070036import com.android.settingslib.fuelgauge.BatterySaverUtils;
Salvador Martinezeb9ab292018-01-19 17:50:24 -080037import com.android.settingslib.utils.PowerUtil;
John Spurlock3332ba52014-03-10 17:44:07 -040038import com.android.systemui.R;
Adrian Roose25c18d2016-06-17 15:59:49 -070039import com.android.systemui.SystemUI;
John Spurlock1bb480a2014-08-02 17:12:43 -040040import com.android.systemui.statusbar.phone.SystemUIDialog;
Dan Sandler8e032e12017-01-25 13:41:38 -050041import com.android.systemui.util.NotificationChannels;
John Spurlock3332ba52014-03-10 17:44:07 -040042
43import java.io.PrintWriter;
Elliott Hughes88d25512014-10-03 12:06:17 -070044import java.text.NumberFormat;
John Spurlock3332ba52014-03-10 17:44:07 -040045
46public class PowerNotificationWarnings implements PowerUI.WarningsUI {
47 private static final String TAG = PowerUI.TAG + ".Notification";
48 private static final boolean DEBUG = PowerUI.DEBUG;
49
Chris Wren5e6c0ff2017-01-05 12:57:06 -050050 private static final String TAG_BATTERY = "low_battery";
51 private static final String TAG_TEMPERATURE = "high_temp";
Makoto Onuki52c62952018-03-22 10:43:03 -070052 private static final String TAG_AUTO_SAVER = "auto_saver";
John Spurlock3332ba52014-03-10 17:44:07 -040053
54 private static final int SHOWING_NOTHING = 0;
55 private static final int SHOWING_WARNING = 1;
John Spurlock3332ba52014-03-10 17:44:07 -040056 private static final int SHOWING_INVALID_CHARGER = 3;
Makoto Onuki52c62952018-03-22 10:43:03 -070057 private static final int SHOWING_AUTO_SAVER_SUGGESTION = 4;
John Spurlock3332ba52014-03-10 17:44:07 -040058 private static final String[] SHOWING_STRINGS = {
59 "SHOWING_NOTHING",
60 "SHOWING_WARNING",
61 "SHOWING_SAVER",
62 "SHOWING_INVALID_CHARGER",
Makoto Onuki52c62952018-03-22 10:43:03 -070063 "SHOWING_AUTO_SAVER_SUGGESTION",
John Spurlock3332ba52014-03-10 17:44:07 -040064 };
65
John Spurlock3332ba52014-03-10 17:44:07 -040066 private static final String ACTION_SHOW_BATTERY_SETTINGS = "PNW.batterySettings";
67 private static final String ACTION_START_SAVER = "PNW.startSaver";
John Spurlock42bfc9a2014-10-29 11:13:01 -040068 private static final String ACTION_DISMISSED_WARNING = "PNW.dismissedWarning";
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -080069 private static final String ACTION_CLICKED_TEMP_WARNING = "PNW.clickedTempWarning";
70 private static final String ACTION_DISMISSED_TEMP_WARNING = "PNW.dismissedTempWarning";
Salvador Martineza6f7b252017-04-10 10:46:15 -070071 private static final String ACTION_CLICKED_THERMAL_SHUTDOWN_WARNING =
72 "PNW.clickedThermalShutdownWarning";
73 private static final String ACTION_DISMISSED_THERMAL_SHUTDOWN_WARNING =
74 "PNW.dismissedThermalShutdownWarning";
Makoto Onuki16a0dd22018-03-20 10:40:37 -070075 private static final String ACTION_SHOW_START_SAVER_CONFIRMATION =
76 BatterySaverUtils.ACTION_SHOW_START_SAVER_CONFIRMATION;
Makoto Onuki52c62952018-03-22 10:43:03 -070077 private static final String ACTION_SHOW_AUTO_SAVER_SUGGESTION =
78 BatterySaverUtils.ACTION_SHOW_AUTO_SAVER_SUGGESTION;
79 private static final String ACTION_DISMISS_AUTO_SAVER_SUGGESTION =
80 "PNW.dismissAutoSaverSuggestion";
81
82 private static final String ACTION_ENABLE_AUTO_SAVER =
83 "PNW.enableAutoSaver";
84 private static final String ACTION_AUTO_SAVER_NO_THANKS =
85 "PNW.autoSaverNoThanks";
86
87 private static final String SETTINGS_ACTION_OPEN_BATTERY_SAVER_SETTING =
88 "android.settings.BATTERY_SAVER_SETTINGS";
John Spurlock1bb480a2014-08-02 17:12:43 -040089
90 private static final AudioAttributes AUDIO_ATTRIBUTES = new AudioAttributes.Builder()
91 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
92 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
93 .build();
John Spurlock3332ba52014-03-10 17:44:07 -040094
95 private final Context mContext;
John Spurlock3332ba52014-03-10 17:44:07 -040096 private final NotificationManager mNoMan;
John Spurlock8d4e6cb2014-09-14 11:10:22 -040097 private final PowerManager mPowerMan;
Geoffrey Pitsch4a7931d2016-09-15 13:11:47 -040098 private final Handler mHandler = new Handler(Looper.getMainLooper());
John Spurlock3332ba52014-03-10 17:44:07 -040099 private final Receiver mReceiver = new Receiver();
100 private final Intent mOpenBatterySettings = settings(Intent.ACTION_POWER_USAGE_SUMMARY);
John Spurlock3332ba52014-03-10 17:44:07 -0400101
102 private int mBatteryLevel;
103 private int mBucket;
104 private long mScreenOffTime;
105 private int mShowing;
106
Salvador Martinezf9e47502018-01-04 13:45:48 -0800107 private long mWarningTriggerTimeMs;
Christoph Studer65fa0a92014-06-26 16:50:09 +0200108
Salvador Martinezf9e47502018-01-04 13:45:48 -0800109 private Estimate mEstimate;
Salvador Martinezbb902fc2018-01-22 19:46:55 -0800110 private long mLowWarningThreshold;
111 private long mSevereWarningThreshold;
John Spurlock3332ba52014-03-10 17:44:07 -0400112 private boolean mWarning;
Makoto Onuki52c62952018-03-22 10:43:03 -0700113 private boolean mShowAutoSaverSuggestion;
John Spurlock3332ba52014-03-10 17:44:07 -0400114 private boolean mPlaySound;
115 private boolean mInvalidCharger;
John Spurlock1bb480a2014-08-02 17:12:43 -0400116 private SystemUIDialog mSaverConfirmation;
Makoto Onuki52c62952018-03-22 10:43:03 -0700117 private SystemUIDialog mSaverEnabledConfirmation;
Salvador Martineza6f7b252017-04-10 10:46:15 -0700118 private boolean mHighTempWarning;
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800119 private SystemUIDialog mHighTempDialog;
Salvador Martineza6f7b252017-04-10 10:46:15 -0700120 private SystemUIDialog mThermalShutdownDialog;
John Spurlock3332ba52014-03-10 17:44:07 -0400121
Jason Monkd819c312017-08-11 12:53:36 -0400122 public PowerNotificationWarnings(Context context) {
John Spurlock3332ba52014-03-10 17:44:07 -0400123 mContext = context;
Jason Monkd819c312017-08-11 12:53:36 -0400124 mNoMan = mContext.getSystemService(NotificationManager.class);
John Spurlock8d4e6cb2014-09-14 11:10:22 -0400125 mPowerMan = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
John Spurlock3332ba52014-03-10 17:44:07 -0400126 mReceiver.init();
127 }
128
129 @Override
130 public void dump(PrintWriter pw) {
John Spurlock3332ba52014-03-10 17:44:07 -0400131 pw.print("mWarning="); pw.println(mWarning);
132 pw.print("mPlaySound="); pw.println(mPlaySound);
133 pw.print("mInvalidCharger="); pw.println(mInvalidCharger);
134 pw.print("mShowing="); pw.println(SHOWING_STRINGS[mShowing]);
John Spurlock1bb480a2014-08-02 17:12:43 -0400135 pw.print("mSaverConfirmation="); pw.println(mSaverConfirmation != null ? "not null" : null);
Makoto Onuki52c62952018-03-22 10:43:03 -0700136 pw.print("mSaverEnabledConfirmation=");
137 pw.println(mSaverEnabledConfirmation != null ? "not null" : null);
Salvador Martineza6f7b252017-04-10 10:46:15 -0700138 pw.print("mHighTempWarning="); pw.println(mHighTempWarning);
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800139 pw.print("mHighTempDialog="); pw.println(mHighTempDialog != null ? "not null" : null);
Salvador Martineza6f7b252017-04-10 10:46:15 -0700140 pw.print("mThermalShutdownDialog=");
141 pw.println(mThermalShutdownDialog != null ? "not null" : null);
John Spurlock3332ba52014-03-10 17:44:07 -0400142 }
143
Makoto Onuki52c62952018-03-22 10:43:03 -0700144 private int getLowBatteryAutoTriggerDefaultLevel() {
145 return mContext.getResources().getInteger(
146 com.android.internal.R.integer.config_lowBatteryAutoTriggerDefaultLevel);
147 }
148
John Spurlock3332ba52014-03-10 17:44:07 -0400149 @Override
150 public void update(int batteryLevel, int bucket, long screenOffTime) {
151 mBatteryLevel = batteryLevel;
Christoph Studer65fa0a92014-06-26 16:50:09 +0200152 if (bucket >= 0) {
Salvador Martinezf9e47502018-01-04 13:45:48 -0800153 mWarningTriggerTimeMs = 0;
Christoph Studer65fa0a92014-06-26 16:50:09 +0200154 } else if (bucket < mBucket) {
Salvador Martinezf9e47502018-01-04 13:45:48 -0800155 mWarningTriggerTimeMs = System.currentTimeMillis();
Christoph Studer65fa0a92014-06-26 16:50:09 +0200156 }
John Spurlock3332ba52014-03-10 17:44:07 -0400157 mBucket = bucket;
158 mScreenOffTime = screenOffTime;
John Spurlock3332ba52014-03-10 17:44:07 -0400159 }
160
Salvador Martinezf9e47502018-01-04 13:45:48 -0800161 @Override
162 public void updateEstimate(Estimate estimate) {
163 mEstimate = estimate;
Salvador Martinezbb902fc2018-01-22 19:46:55 -0800164 if (estimate.estimateMillis <= mLowWarningThreshold) {
Salvador Martinezf9e47502018-01-04 13:45:48 -0800165 mWarningTriggerTimeMs = System.currentTimeMillis();
166 }
167 }
168
Salvador Martinezbb902fc2018-01-22 19:46:55 -0800169 @Override
170 public void updateThresholds(long lowThreshold, long severeThreshold) {
171 mLowWarningThreshold = lowThreshold;
172 mSevereWarningThreshold = severeThreshold;
173 }
174
John Spurlock3332ba52014-03-10 17:44:07 -0400175 private void updateNotification() {
John Spurlock86c3de82014-08-19 13:37:44 -0400176 if (DEBUG) Slog.d(TAG, "updateNotification mWarning=" + mWarning + " mPlaySound="
Jason Monkc06fbb12016-01-08 14:12:18 -0500177 + mPlaySound + " mInvalidCharger=" + mInvalidCharger);
John Spurlock3332ba52014-03-10 17:44:07 -0400178 if (mInvalidCharger) {
John Spurlock3332ba52014-03-10 17:44:07 -0400179 showInvalidChargerNotification();
180 mShowing = SHOWING_INVALID_CHARGER;
181 } else if (mWarning) {
John Spurlock3332ba52014-03-10 17:44:07 -0400182 showWarningNotification();
183 mShowing = SHOWING_WARNING;
Makoto Onuki52c62952018-03-22 10:43:03 -0700184 } else if (mShowAutoSaverSuggestion) {
185 showAutoSaverSuggestionNotification();
186 mShowing = SHOWING_AUTO_SAVER_SUGGESTION;
John Spurlock3332ba52014-03-10 17:44:07 -0400187 } else {
Chris Wren5e6c0ff2017-01-05 12:57:06 -0500188 mNoMan.cancelAsUser(TAG_BATTERY, SystemMessage.NOTE_BAD_CHARGER, UserHandle.ALL);
189 mNoMan.cancelAsUser(TAG_BATTERY, SystemMessage.NOTE_POWER_LOW, UserHandle.ALL);
Makoto Onuki52c62952018-03-22 10:43:03 -0700190 mNoMan.cancelAsUser(TAG_AUTO_SAVER,
191 SystemMessage.NOTE_AUTO_SAVER_SUGGESTION, UserHandle.ALL);
John Spurlock3332ba52014-03-10 17:44:07 -0400192 mShowing = SHOWING_NOTHING;
193 }
194 }
195
196 private void showInvalidChargerNotification() {
Geoffrey Pitsch1dc93bc2017-01-31 16:38:11 -0500197 final Notification.Builder nb =
198 new Notification.Builder(mContext, NotificationChannels.ALERTS)
199 .setSmallIcon(R.drawable.ic_power_low)
200 .setWhen(0)
201 .setShowWhen(false)
202 .setOngoing(true)
203 .setContentTitle(mContext.getString(R.string.invalid_charger_title))
204 .setContentText(mContext.getString(R.string.invalid_charger_text))
205 .setColor(mContext.getColor(
206 com.android.internal.R.color.system_notification_accent_color));
Julia Reynolds037d8082018-03-18 15:25:19 -0400207 SystemUI.overrideNotificationAppName(mContext, nb, false);
John Spurlock3332ba52014-03-10 17:44:07 -0400208 final Notification n = nb.build();
Chris Wren5e6c0ff2017-01-05 12:57:06 -0500209 mNoMan.cancelAsUser(TAG_BATTERY, SystemMessage.NOTE_POWER_LOW, UserHandle.ALL);
210 mNoMan.notifyAsUser(TAG_BATTERY, SystemMessage.NOTE_BAD_CHARGER, n, UserHandle.ALL);
John Spurlock3332ba52014-03-10 17:44:07 -0400211 }
212
Salvador Martinezf9e47502018-01-04 13:45:48 -0800213 protected void showWarningNotification() {
Salvador Martinezbb902fc2018-01-22 19:46:55 -0800214 final String percentage = NumberFormat.getPercentInstance()
215 .format((double) mBatteryLevel / 100.0);
Beverly334bc5f2017-07-31 10:37:17 -0400216
Salvador Martinezf9e47502018-01-04 13:45:48 -0800217 // get standard notification copy
218 String title = mContext.getString(R.string.battery_low_title);
219 String contentText = mContext.getString(R.string.battery_low_percent_format, percentage);
220
221 // override notification copy if hybrid notification enabled
222 if (mEstimate != null) {
Salvador Martinezeb9ab292018-01-19 17:50:24 -0800223 contentText = getHybridContentString(percentage);
Salvador Martinezf9e47502018-01-04 13:45:48 -0800224 }
225
Geoffrey Pitsch1dc93bc2017-01-31 16:38:11 -0500226 final Notification.Builder nb =
Beverly334bc5f2017-07-31 10:37:17 -0400227 new Notification.Builder(mContext, NotificationChannels.BATTERY)
Geoffrey Pitsch1dc93bc2017-01-31 16:38:11 -0500228 .setSmallIcon(R.drawable.ic_power_low)
229 // Bump the notification when the bucket dropped.
Salvador Martinezf9e47502018-01-04 13:45:48 -0800230 .setWhen(mWarningTriggerTimeMs)
Geoffrey Pitsch1dc93bc2017-01-31 16:38:11 -0500231 .setShowWhen(false)
Salvador Martinezf9e47502018-01-04 13:45:48 -0800232 .setContentText(contentText)
Salvador Martinez086ab742018-04-03 13:05:39 -0700233 .setContentTitle(title)
Geoffrey Pitsch1dc93bc2017-01-31 16:38:11 -0500234 .setOnlyAlertOnce(true)
235 .setDeleteIntent(pendingBroadcast(ACTION_DISMISSED_WARNING))
Salvador Martinez086ab742018-04-03 13:05:39 -0700236 .setStyle(new Notification.BigTextStyle().bigText(contentText))
Salvador Martinezf9e47502018-01-04 13:45:48 -0800237 .setVisibility(Notification.VISIBILITY_PUBLIC);
John Spurlock3332ba52014-03-10 17:44:07 -0400238 if (hasBatterySettings()) {
239 nb.setContentIntent(pendingBroadcast(ACTION_SHOW_BATTERY_SETTINGS));
240 }
Salvador Martinezf9e47502018-01-04 13:45:48 -0800241 // Make the notification red if the percentage goes below a certain amount or the time
242 // remaining estimate is disabled
Salvador Martinezbb902fc2018-01-22 19:46:55 -0800243 if (mEstimate == null || mBucket < 0
244 || mEstimate.estimateMillis < mSevereWarningThreshold) {
Salvador Martinezf9e47502018-01-04 13:45:48 -0800245 nb.setColor(Utils.getColorAttr(mContext, android.R.attr.colorError));
246 }
Jason Monkc06fbb12016-01-08 14:12:18 -0500247 nb.addAction(0,
248 mContext.getString(R.string.battery_saver_start_action),
249 pendingBroadcast(ACTION_START_SAVER));
Beverly334bc5f2017-07-31 10:37:17 -0400250 nb.setOnlyAlertOnce(!mPlaySound);
251 mPlaySound = false;
Julia Reynolds037d8082018-03-18 15:25:19 -0400252 SystemUI.overrideNotificationAppName(mContext, nb, false);
Chris Wren5e6c0ff2017-01-05 12:57:06 -0500253 final Notification n = nb.build();
254 mNoMan.cancelAsUser(TAG_BATTERY, SystemMessage.NOTE_BAD_CHARGER, UserHandle.ALL);
255 mNoMan.notifyAsUser(TAG_BATTERY, SystemMessage.NOTE_POWER_LOW, n, UserHandle.ALL);
John Spurlock3332ba52014-03-10 17:44:07 -0400256 }
257
Makoto Onuki52c62952018-03-22 10:43:03 -0700258 private void showAutoSaverSuggestionNotification() {
259 final Notification.Builder nb =
260 new Notification.Builder(mContext, NotificationChannels.HINTS)
261 .setSmallIcon(R.drawable.ic_power_saver)
262 .setWhen(0)
263 .setShowWhen(false)
264 .setContentTitle(mContext.getString(R.string.auto_saver_title))
265 .setContentText(mContext.getString(R.string.auto_saver_text,
266 getLowBatteryAutoTriggerDefaultLevel()));
267 nb.setContentIntent(pendingBroadcast(ACTION_ENABLE_AUTO_SAVER));
268 nb.setDeleteIntent(pendingBroadcast(ACTION_DISMISS_AUTO_SAVER_SUGGESTION));
269 nb.addAction(0,
270 mContext.getString(R.string.no_auto_saver_action),
271 pendingBroadcast(ACTION_AUTO_SAVER_NO_THANKS));
272
273 SystemUI.overrideNotificationAppName(mContext, nb, false);
274
275 final Notification n = nb.build();
276 mNoMan.notifyAsUser(
277 TAG_AUTO_SAVER, SystemMessage.NOTE_AUTO_SAVER_SUGGESTION, n, UserHandle.ALL);
278 }
279
Salvador Martinezeb9ab292018-01-19 17:50:24 -0800280 private String getHybridContentString(String percentage) {
281 return PowerUtil.getBatteryRemainingStringFormatted(
282 mContext,
283 mEstimate.estimateMillis,
284 percentage,
285 mEstimate.isBasedOnUsage);
Salvador Martinezf9e47502018-01-04 13:45:48 -0800286 }
287
John Spurlock3332ba52014-03-10 17:44:07 -0400288 private PendingIntent pendingBroadcast(String action) {
Makoto Onuki52c62952018-03-22 10:43:03 -0700289 return PendingIntent.getBroadcastAsUser(mContext, 0,
290 new Intent(action).setPackage(mContext.getPackageName()), 0, UserHandle.CURRENT);
John Spurlock3332ba52014-03-10 17:44:07 -0400291 }
292
293 private static Intent settings(String action) {
294 return new Intent(action).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
295 | Intent.FLAG_ACTIVITY_MULTIPLE_TASK
296 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
297 | Intent.FLAG_ACTIVITY_NO_HISTORY
298 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
299 }
300
301 @Override
302 public boolean isInvalidChargerWarningShowing() {
303 return mInvalidCharger;
304 }
305
306 @Override
Salvador Martineza6f7b252017-04-10 10:46:15 -0700307 public void dismissHighTemperatureWarning() {
308 if (!mHighTempWarning) {
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800309 return;
310 }
Salvador Martineza6f7b252017-04-10 10:46:15 -0700311 mHighTempWarning = false;
312 dismissHighTemperatureWarningInternal();
Andrew Sapperstein97bfa0f2017-01-24 16:38:50 -0800313 }
314
315 /**
Salvador Martineza6f7b252017-04-10 10:46:15 -0700316 * Internal only version of {@link #dismissHighTemperatureWarning()} that simply dismisses
Andrew Sapperstein97bfa0f2017-01-24 16:38:50 -0800317 * the notification. As such, the notification will not show again until
Salvador Martineza6f7b252017-04-10 10:46:15 -0700318 * {@link #dismissHighTemperatureWarning()} is called.
Andrew Sapperstein97bfa0f2017-01-24 16:38:50 -0800319 */
Salvador Martineza6f7b252017-04-10 10:46:15 -0700320 private void dismissHighTemperatureWarningInternal() {
Andrew Sapperstein97bfa0f2017-01-24 16:38:50 -0800321 mNoMan.cancelAsUser(TAG_TEMPERATURE, SystemMessage.NOTE_HIGH_TEMP, UserHandle.ALL);
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800322 }
323
324 @Override
Salvador Martineza6f7b252017-04-10 10:46:15 -0700325 public void showHighTemperatureWarning() {
326 if (mHighTempWarning) {
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800327 return;
328 }
Salvador Martineza6f7b252017-04-10 10:46:15 -0700329 mHighTempWarning = true;
Geoffrey Pitsch1dc93bc2017-01-31 16:38:11 -0500330 final Notification.Builder nb =
331 new Notification.Builder(mContext, NotificationChannels.ALERTS)
332 .setSmallIcon(R.drawable.ic_device_thermostat_24)
333 .setWhen(0)
334 .setShowWhen(false)
335 .setContentTitle(mContext.getString(R.string.high_temp_title))
336 .setContentText(mContext.getString(R.string.high_temp_notif_message))
337 .setVisibility(Notification.VISIBILITY_PUBLIC)
338 .setContentIntent(pendingBroadcast(ACTION_CLICKED_TEMP_WARNING))
339 .setDeleteIntent(pendingBroadcast(ACTION_DISMISSED_TEMP_WARNING))
Jason Monk58be7a62017-02-01 20:17:51 -0500340 .setColor(Utils.getColorAttr(mContext, android.R.attr.colorError));
Julia Reynolds037d8082018-03-18 15:25:19 -0400341 SystemUI.overrideNotificationAppName(mContext, nb, false);
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800342 final Notification n = nb.build();
Chris Wren5e6c0ff2017-01-05 12:57:06 -0500343 mNoMan.notifyAsUser(TAG_TEMPERATURE, SystemMessage.NOTE_HIGH_TEMP, n, UserHandle.ALL);
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800344 }
345
Salvador Martineza6f7b252017-04-10 10:46:15 -0700346 private void showHighTemperatureDialog() {
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800347 if (mHighTempDialog != null) return;
348 final SystemUIDialog d = new SystemUIDialog(mContext);
Andrew Sappersteine26dc3d2017-01-04 11:25:20 -0800349 d.setIconAttribute(android.R.attr.alertDialogIcon);
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800350 d.setTitle(R.string.high_temp_title);
351 d.setMessage(R.string.high_temp_dialog_message);
352 d.setPositiveButton(com.android.internal.R.string.ok, null);
353 d.setShowForAllUsers(true);
354 d.setOnDismissListener(dialog -> mHighTempDialog = null);
355 d.show();
356 mHighTempDialog = d;
357 }
358
Salvador Martineza6f7b252017-04-10 10:46:15 -0700359 @VisibleForTesting
360 void dismissThermalShutdownWarning() {
361 mNoMan.cancelAsUser(TAG_TEMPERATURE, SystemMessage.NOTE_THERMAL_SHUTDOWN, UserHandle.ALL);
362 }
363
364 private void showThermalShutdownDialog() {
365 if (mThermalShutdownDialog != null) return;
366 final SystemUIDialog d = new SystemUIDialog(mContext);
367 d.setIconAttribute(android.R.attr.alertDialogIcon);
368 d.setTitle(R.string.thermal_shutdown_title);
369 d.setMessage(R.string.thermal_shutdown_dialog_message);
370 d.setPositiveButton(com.android.internal.R.string.ok, null);
371 d.setShowForAllUsers(true);
372 d.setOnDismissListener(dialog -> mThermalShutdownDialog = null);
373 d.show();
374 mThermalShutdownDialog = d;
375 }
376
377 @Override
378 public void showThermalShutdownWarning() {
379 final Notification.Builder nb =
380 new Notification.Builder(mContext, NotificationChannels.ALERTS)
381 .setSmallIcon(R.drawable.ic_device_thermostat_24)
382 .setWhen(0)
383 .setShowWhen(false)
384 .setContentTitle(mContext.getString(R.string.thermal_shutdown_title))
385 .setContentText(mContext.getString(R.string.thermal_shutdown_message))
386 .setVisibility(Notification.VISIBILITY_PUBLIC)
387 .setContentIntent(pendingBroadcast(ACTION_CLICKED_THERMAL_SHUTDOWN_WARNING))
388 .setDeleteIntent(
389 pendingBroadcast(ACTION_DISMISSED_THERMAL_SHUTDOWN_WARNING))
390 .setColor(Utils.getColorAttr(mContext, android.R.attr.colorError));
Julia Reynolds037d8082018-03-18 15:25:19 -0400391 SystemUI.overrideNotificationAppName(mContext, nb, false);
Salvador Martineza6f7b252017-04-10 10:46:15 -0700392 final Notification n = nb.build();
393 mNoMan.notifyAsUser(
394 TAG_TEMPERATURE, SystemMessage.NOTE_THERMAL_SHUTDOWN, n, UserHandle.ALL);
395 }
396
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800397 @Override
John Spurlock3332ba52014-03-10 17:44:07 -0400398 public void updateLowBatteryWarning() {
399 updateNotification();
John Spurlock3332ba52014-03-10 17:44:07 -0400400 }
401
402 @Override
403 public void dismissLowBatteryWarning() {
John Spurlock3ff2de62014-06-16 13:32:48 -0400404 if (DEBUG) Slog.d(TAG, "dismissing low battery warning: level=" + mBatteryLevel);
John Spurlock3332ba52014-03-10 17:44:07 -0400405 dismissLowBatteryNotification();
John Spurlock3332ba52014-03-10 17:44:07 -0400406 }
407
408 private void dismissLowBatteryNotification() {
John Spurlock3ff2de62014-06-16 13:32:48 -0400409 if (mWarning) Slog.i(TAG, "dismissing low battery notification");
John Spurlock3332ba52014-03-10 17:44:07 -0400410 mWarning = false;
411 updateNotification();
412 }
413
414 private boolean hasBatterySettings() {
415 return mOpenBatterySettings.resolveActivity(mContext.getPackageManager()) != null;
416 }
417
John Spurlock3332ba52014-03-10 17:44:07 -0400418 @Override
419 public void showLowBatteryWarning(boolean playSound) {
420 Slog.i(TAG,
421 "show low battery warning: level=" + mBatteryLevel
Beverly334bc5f2017-07-31 10:37:17 -0400422 + " [" + mBucket + "] playSound=" + playSound);
John Spurlock3332ba52014-03-10 17:44:07 -0400423 mPlaySound = playSound;
424 mWarning = true;
425 updateNotification();
John Spurlock3332ba52014-03-10 17:44:07 -0400426 }
427
John Spurlock3332ba52014-03-10 17:44:07 -0400428 @Override
429 public void dismissInvalidChargerWarning() {
John Spurlockeb44a7d2014-06-12 13:00:55 -0400430 dismissInvalidChargerNotification();
John Spurlockeb44a7d2014-06-12 13:00:55 -0400431 }
432
433 private void dismissInvalidChargerNotification() {
John Spurlock3ff2de62014-06-16 13:32:48 -0400434 if (mInvalidCharger) Slog.i(TAG, "dismissing invalid charger notification");
John Spurlock3332ba52014-03-10 17:44:07 -0400435 mInvalidCharger = false;
436 updateNotification();
437 }
438
439 @Override
440 public void showInvalidChargerWarning() {
441 mInvalidCharger = true;
442 updateNotification();
443 }
444
Makoto Onuki52c62952018-03-22 10:43:03 -0700445 private void showAutoSaverSuggestion() {
446 mShowAutoSaverSuggestion = true;
447 updateNotification();
448 }
449
450 private void dismissAutoSaverSuggestion() {
451 mShowAutoSaverSuggestion = false;
452 updateNotification();
453 }
454
John Spurlockecbc5e82014-10-22 09:05:51 -0400455 @Override
456 public void userSwitched() {
457 updateNotification();
458 }
459
John Spurlock3332ba52014-03-10 17:44:07 -0400460 private void showStartSaverConfirmation() {
John Spurlock1bb480a2014-08-02 17:12:43 -0400461 if (mSaverConfirmation != null) return;
462 final SystemUIDialog d = new SystemUIDialog(mContext);
463 d.setTitle(R.string.battery_saver_confirmation_title);
464 d.setMessage(com.android.internal.R.string.battery_saver_description);
465 d.setNegativeButton(android.R.string.cancel, null);
Makoto Onuki52c62952018-03-22 10:43:03 -0700466 d.setPositiveButton(R.string.battery_saver_confirmation_ok,
467 (dialog, which) -> setSaverMode(true, false));
John Spurlock1bb480a2014-08-02 17:12:43 -0400468 d.setShowForAllUsers(true);
Makoto Onuki52c62952018-03-22 10:43:03 -0700469 d.setOnDismissListener((dialog) -> mSaverConfirmation = null);
John Spurlock3332ba52014-03-10 17:44:07 -0400470 d.show();
John Spurlock1bb480a2014-08-02 17:12:43 -0400471 mSaverConfirmation = d;
John Spurlock3332ba52014-03-10 17:44:07 -0400472 }
473
Makoto Onuki52c62952018-03-22 10:43:03 -0700474 private void showAutoSaverEnabledConfirmation() {
475 if (mSaverEnabledConfirmation != null) return;
476
477 // Open the Battery Saver setting page.
478 final Intent actionBatterySaverSetting =
479 new Intent(SETTINGS_ACTION_OPEN_BATTERY_SAVER_SETTING)
480 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
481
482 final SystemUIDialog d = new SystemUIDialog(mContext);
483 d.setTitle(R.string.auto_saver_enabled_title);
484 d.setMessage(mContext.getString(R.string.auto_saver_enabled_text,
485 getLowBatteryAutoTriggerDefaultLevel()));
486
Makoto Onuki41d5ccf2018-04-03 11:46:02 -0700487 // "Got it". Just close the dialog. Automatic battery has been enabled already.
488 d.setPositiveButton(R.string.auto_saver_okay_action,
489 (dialog, which) -> onAutoSaverEnabledConfirmationClosed());
490
491 // "Settings" -> Opens the battery saver settings activity.
492 d.setNeutralButton(R.string.open_saver_setting_action, (dialog, which) -> {
493 mContext.startActivity(actionBatterySaverSetting);
494 onAutoSaverEnabledConfirmationClosed();
495 });
Makoto Onuki52c62952018-03-22 10:43:03 -0700496 d.setShowForAllUsers(true);
Makoto Onuki41d5ccf2018-04-03 11:46:02 -0700497 d.setOnDismissListener((dialog) -> onAutoSaverEnabledConfirmationClosed());
Makoto Onuki52c62952018-03-22 10:43:03 -0700498 d.show();
499 mSaverEnabledConfirmation = d;
500 }
501
Makoto Onuki41d5ccf2018-04-03 11:46:02 -0700502 private void onAutoSaverEnabledConfirmationClosed() {
503 mSaverEnabledConfirmation = null;
504 }
Makoto Onuki52c62952018-03-22 10:43:03 -0700505
Makoto Onuki16a0dd22018-03-20 10:40:37 -0700506 private void setSaverMode(boolean mode, boolean needFirstTimeWarning) {
507 BatterySaverUtils.setPowerSaveMode(mContext, mode, needFirstTimeWarning);
John Spurlock3332ba52014-03-10 17:44:07 -0400508 }
509
Makoto Onuki52c62952018-03-22 10:43:03 -0700510 private void scheduleAutoBatterySaver() {
511 int autoTriggerThreshold = mContext.getResources().getInteger(
512 com.android.internal.R.integer.config_lowBatteryWarningLevel);
513 if (autoTriggerThreshold == 0) {
514 autoTriggerThreshold = 15;
515 }
516
Makoto Onuki59727732018-04-04 12:44:05 -0700517 BatterySaverUtils.ensureAutoBatterySaver(mContext, autoTriggerThreshold);
Makoto Onuki52c62952018-03-22 10:43:03 -0700518 showAutoSaverEnabledConfirmation();
519 }
520
John Spurlock3332ba52014-03-10 17:44:07 -0400521 private final class Receiver extends BroadcastReceiver {
522
523 public void init() {
524 IntentFilter filter = new IntentFilter();
John Spurlock3332ba52014-03-10 17:44:07 -0400525 filter.addAction(ACTION_SHOW_BATTERY_SETTINGS);
526 filter.addAction(ACTION_START_SAVER);
John Spurlock42bfc9a2014-10-29 11:13:01 -0400527 filter.addAction(ACTION_DISMISSED_WARNING);
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800528 filter.addAction(ACTION_CLICKED_TEMP_WARNING);
529 filter.addAction(ACTION_DISMISSED_TEMP_WARNING);
Salvador Martineza6f7b252017-04-10 10:46:15 -0700530 filter.addAction(ACTION_CLICKED_THERMAL_SHUTDOWN_WARNING);
531 filter.addAction(ACTION_DISMISSED_THERMAL_SHUTDOWN_WARNING);
Makoto Onuki16a0dd22018-03-20 10:40:37 -0700532 filter.addAction(ACTION_SHOW_START_SAVER_CONFIRMATION);
Makoto Onuki52c62952018-03-22 10:43:03 -0700533 filter.addAction(ACTION_SHOW_AUTO_SAVER_SUGGESTION);
534 filter.addAction(ACTION_ENABLE_AUTO_SAVER);
535 filter.addAction(ACTION_AUTO_SAVER_NO_THANKS);
Makoto Onuki5ac8d5e2018-04-13 15:53:57 -0700536 filter.addAction(ACTION_DISMISS_AUTO_SAVER_SUGGESTION);
John Spurlock05e07052015-06-01 10:56:42 -0400537 mContext.registerReceiverAsUser(this, UserHandle.ALL, filter,
Makoto Onuki16a0dd22018-03-20 10:40:37 -0700538 android.Manifest.permission.DEVICE_POWER, mHandler);
John Spurlock3332ba52014-03-10 17:44:07 -0400539 }
540
541 @Override
542 public void onReceive(Context context, Intent intent) {
543 final String action = intent.getAction();
John Spurlockeb44a7d2014-06-12 13:00:55 -0400544 Slog.i(TAG, "Received " + action);
John Spurlock86c3de82014-08-19 13:37:44 -0400545 if (action.equals(ACTION_SHOW_BATTERY_SETTINGS)) {
John Spurlock3332ba52014-03-10 17:44:07 -0400546 dismissLowBatteryNotification();
547 mContext.startActivityAsUser(mOpenBatterySettings, UserHandle.CURRENT);
548 } else if (action.equals(ACTION_START_SAVER)) {
Makoto Onuki16a0dd22018-03-20 10:40:37 -0700549 setSaverMode(true, true);
550 dismissLowBatteryNotification();
551 } else if (action.equals(ACTION_SHOW_START_SAVER_CONFIRMATION)) {
John Spurlock3332ba52014-03-10 17:44:07 -0400552 dismissLowBatteryNotification();
553 showStartSaverConfirmation();
John Spurlock42bfc9a2014-10-29 11:13:01 -0400554 } else if (action.equals(ACTION_DISMISSED_WARNING)) {
555 dismissLowBatteryWarning();
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800556 } else if (ACTION_CLICKED_TEMP_WARNING.equals(action)) {
Salvador Martineza6f7b252017-04-10 10:46:15 -0700557 dismissHighTemperatureWarningInternal();
558 showHighTemperatureDialog();
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800559 } else if (ACTION_DISMISSED_TEMP_WARNING.equals(action)) {
Salvador Martineza6f7b252017-04-10 10:46:15 -0700560 dismissHighTemperatureWarningInternal();
561 } else if (ACTION_CLICKED_THERMAL_SHUTDOWN_WARNING.equals(action)) {
562 dismissThermalShutdownWarning();
563 showThermalShutdownDialog();
564 } else if (ACTION_DISMISSED_THERMAL_SHUTDOWN_WARNING.equals(action)) {
565 dismissThermalShutdownWarning();
Makoto Onuki52c62952018-03-22 10:43:03 -0700566 } else if (ACTION_SHOW_AUTO_SAVER_SUGGESTION.equals(action)) {
567 showAutoSaverSuggestion();
568 } else if (ACTION_DISMISS_AUTO_SAVER_SUGGESTION.equals(action)) {
569 dismissAutoSaverSuggestion();
570 } else if (ACTION_ENABLE_AUTO_SAVER.equals(action)) {
571 dismissAutoSaverSuggestion();
572 scheduleAutoBatterySaver();
573 } else if (ACTION_AUTO_SAVER_NO_THANKS.equals(action)) {
574 dismissAutoSaverSuggestion();
575 BatterySaverUtils.suppressAutoBatterySaver(context);
John Spurlock3332ba52014-03-10 17:44:07 -0400576 }
577 }
578 }
John Spurlock3332ba52014-03-10 17:44:07 -0400579}