blob: e27c25efd88f7e88dde7cbbcfc40e6849498040b [file] [log] [blame]
Joe Onorato10523b4d2010-10-25 10:42:46 -07001/*
2 * Copyright (C) 2008 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
Joe Onorato10523b4d2010-10-25 10:42:46 -070019import android.content.BroadcastReceiver;
Dianne Hackborn14272302014-06-10 23:13:02 -070020import android.content.ContentResolver;
Joe Onorato10523b4d2010-10-25 10:42:46 -070021import android.content.Context;
Joe Onorato10523b4d2010-10-25 10:42:46 -070022import android.content.Intent;
23import android.content.IntentFilter;
Adam Lesinski1aab3fa2017-07-31 13:42:00 -070024import android.content.pm.ActivityInfo;
25import android.content.res.Configuration;
Andrew Sappersteine3352562017-01-20 15:41:03 -080026import android.content.res.Resources;
Dianne Hackborn14272302014-06-10 23:13:02 -070027import android.database.ContentObserver;
Joe Onorato4ca7f1e2010-10-27 15:32:23 -070028import android.os.BatteryManager;
Joe Onorato10523b4d2010-10-25 10:42:46 -070029import android.os.Handler;
Todd Poynorfb95e122017-10-04 13:00:32 -070030import android.os.IBinder;
31import android.os.IThermalEventListener;
32import android.os.IThermalService;
Daniel Sandlerdea64622013-09-23 16:05:57 -040033import android.os.PowerManager;
Todd Poynorfb95e122017-10-04 13:00:32 -070034import android.os.RemoteException;
35import android.os.ServiceManager;
Daniel Sandlerdea64622013-09-23 16:05:57 -040036import android.os.SystemClock;
Todd Poynorfb95e122017-10-04 13:00:32 -070037import android.os.Temperature;
Dianne Hackborn14272302014-06-10 23:13:02 -070038import android.os.UserHandle;
Joe Onorato10523b4d2010-10-25 10:42:46 -070039import android.provider.Settings;
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -080040import android.text.format.DateUtils;
John Spurlock1bb480a2014-08-02 17:12:43 -040041import android.util.Log;
Daniel Sandlerdea64622013-09-23 16:05:57 -040042import android.util.Slog;
Jason Monkd819c312017-08-11 12:53:36 -040043
44import com.android.internal.annotations.VisibleForTesting;
Salvador Martinez110f9a12018-01-31 09:57:17 -080045import com.android.settingslib.utils.ThreadUtils;
Jason Monkd819c312017-08-11 12:53:36 -040046import com.android.systemui.Dependency;
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -080047import com.android.systemui.R;
Joe Onorato10523b4d2010-10-25 10:42:46 -070048import com.android.systemui.SystemUI;
Jason Monk2a6ea9c2017-01-26 11:14:51 -050049import com.android.systemui.statusbar.phone.StatusBar;
Jason Monkd819c312017-08-11 12:53:36 -040050
John Spurlockde84f0e2013-06-12 12:41:00 -040051import java.io.FileDescriptor;
52import java.io.PrintWriter;
Salvador Martinezfd38aa52018-03-28 23:56:59 -070053import java.time.Duration;
John Spurlockde84f0e2013-06-12 12:41:00 -040054import java.util.Arrays;
Salvador Martinez7ad2c172019-02-11 16:09:28 -080055import java.util.concurrent.Future;
John Spurlockde84f0e2013-06-12 12:41:00 -040056
Joe Onorato10523b4d2010-10-25 10:42:46 -070057public class PowerUI extends SystemUI {
58 static final String TAG = "PowerUI";
John Spurlock1bb480a2014-08-02 17:12:43 -040059 static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -080060 private static final long TEMPERATURE_INTERVAL = 30 * DateUtils.SECOND_IN_MILLIS;
Andrew Sappersteina6ed7f82017-02-01 17:13:08 -080061 private static final long TEMPERATURE_LOGGING_INTERVAL = DateUtils.HOUR_IN_MILLIS;
62 private static final int MAX_RECENT_TEMPS = 125; // TEMPERATURE_LOGGING_INTERVAL plus a buffer
Salvador Martinezf9e47502018-01-04 13:45:48 -080063 static final long THREE_HOURS_IN_MILLIS = DateUtils.HOUR_IN_MILLIS * 3;
Salvador Martinezfd38aa52018-03-28 23:56:59 -070064 private static final int CHARGE_CYCLE_PERCENT_RESET = 45;
65 private static final long SIX_HOURS_MILLIS = Duration.ofHours(6).toMillis();
Joe Onorato10523b4d2010-10-25 10:42:46 -070066
John Spurlocked452c52014-03-06 12:02:31 -050067 private final Handler mHandler = new Handler();
Amin Shaikh2f6c45c2018-04-16 14:00:09 -040068 @VisibleForTesting
69 final Receiver mReceiver = new Receiver();
Joe Onorato4ca7f1e2010-10-27 15:32:23 -070070
John Spurlock3332ba52014-03-10 17:44:07 -040071 private PowerManager mPowerManager;
72 private WarningsUI mWarnings;
Adam Lesinski1aab3fa2017-07-31 13:42:00 -070073 private final Configuration mLastConfiguration = new Configuration();
Salvador Martinezf9e47502018-01-04 13:45:48 -080074 private long mTimeRemaining = Long.MAX_VALUE;
John Spurlocked452c52014-03-06 12:02:31 -050075 private int mPlugType = 0;
76 private int mInvalidCharger = 0;
Salvador Martinezf9e47502018-01-04 13:45:48 -080077 private EnhancedEstimates mEnhancedEstimates;
Salvador Martinez926f0712018-07-03 18:07:07 -070078 private Estimate mLastEstimate;
Salvador Martinez36307962018-02-08 14:29:08 -080079 private boolean mLowWarningShownThisChargeCycle;
80 private boolean mSevereWarningShownThisChargeCycle;
Salvador Martinez7ad2c172019-02-11 16:09:28 -080081 private Future mLastShowWarningTask;
Sherry Huangce02ed32019-01-17 20:37:29 +080082 private boolean mEnableSkinTemperatureWarning;
83 private boolean mEnableUsbTemperatureAlarm;
Joe Onorato4ca7f1e2010-10-27 15:32:23 -070084
John Spurlocked452c52014-03-06 12:02:31 -050085 private int mLowBatteryAlertCloseLevel;
86 private final int[] mLowBatteryReminderLevels = new int[2];
Joe Onorato10523b4d2010-10-25 10:42:46 -070087
Daniel Sandlerdea64622013-09-23 16:05:57 -040088 private long mScreenOffTime = -1;
89
Wei Wangbf05e602018-11-21 11:46:48 -080090 @VisibleForTesting IThermalService mThermalService;
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -080091
Salvador Martinezfd38aa52018-03-28 23:56:59 -070092 @VisibleForTesting int mBatteryLevel = 100;
Salvador Martinez36307962018-02-08 14:29:08 -080093 @VisibleForTesting int mBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN;
94
Joe Onorato10523b4d2010-10-25 10:42:46 -070095 public void start() {
John Spurlock3332ba52014-03-10 17:44:07 -040096 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
97 mScreenOffTime = mPowerManager.isScreenOn() ? -1 : SystemClock.elapsedRealtime();
Jason Monkd819c312017-08-11 12:53:36 -040098 mWarnings = Dependency.get(WarningsUI.class);
Salvador Martinezf9e47502018-01-04 13:45:48 -080099 mEnhancedEstimates = Dependency.get(EnhancedEstimates.class);
Adam Lesinski1aab3fa2017-07-31 13:42:00 -0700100 mLastConfiguration.setTo(mContext.getResources().getConfiguration());
Daniel Sandlerdea64622013-09-23 16:05:57 -0400101
Dianne Hackborn14272302014-06-10 23:13:02 -0700102 ContentObserver obs = new ContentObserver(mHandler) {
103 @Override
104 public void onChange(boolean selfChange) {
105 updateBatteryWarningLevels();
106 }
107 };
108 final ContentResolver resolver = mContext.getContentResolver();
109 resolver.registerContentObserver(Settings.Global.getUriFor(
110 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
111 false, obs, UserHandle.USER_ALL);
112 updateBatteryWarningLevels();
John Spurlock3332ba52014-03-10 17:44:07 -0400113 mReceiver.init();
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800114
Salvador Martineza6f7b252017-04-10 10:46:15 -0700115 // Check to see if we need to let the user know that the phone previously shut down due
116 // to the temperature being too high.
117 showThermalShutdownDialog();
118
Sherry Huangce02ed32019-01-17 20:37:29 +0800119 initTemperature();
John Spurlock3332ba52014-03-10 17:44:07 -0400120 }
Dianne Hackborn14272302014-06-10 23:13:02 -0700121
Adam Lesinski1aab3fa2017-07-31 13:42:00 -0700122 @Override
123 protected void onConfigurationChanged(Configuration newConfig) {
124 final int mask = ActivityInfo.CONFIG_MCC | ActivityInfo.CONFIG_MNC;
125
126 // Safe to modify mLastConfiguration here as it's only updated by the main thread (here).
127 if ((mLastConfiguration.updateFrom(newConfig) & mask) != 0) {
Sherry Huangce02ed32019-01-17 20:37:29 +0800128 mHandler.post(this::initTemperature);
Adam Lesinski1aab3fa2017-07-31 13:42:00 -0700129 }
130 }
131
Dianne Hackborn14272302014-06-10 23:13:02 -0700132 void updateBatteryWarningLevels() {
133 int critLevel = mContext.getResources().getInteger(
134 com.android.internal.R.integer.config_criticalBatteryWarningLevel);
Makoto Onuki16a0dd22018-03-20 10:40:37 -0700135 int warnLevel = mContext.getResources().getInteger(
Dianne Hackborn14272302014-06-10 23:13:02 -0700136 com.android.internal.R.integer.config_lowBatteryWarningLevel);
Makoto Onuki4a9036b2018-01-11 14:48:20 -0800137
Dianne Hackborn14272302014-06-10 23:13:02 -0700138 if (warnLevel < critLevel) {
139 warnLevel = critLevel;
140 }
141
142 mLowBatteryReminderLevels[0] = warnLevel;
143 mLowBatteryReminderLevels[1] = critLevel;
144 mLowBatteryAlertCloseLevel = mLowBatteryReminderLevels[0]
145 + mContext.getResources().getInteger(
146 com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
147 }
148
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700149 /**
150 * Buckets the battery level.
151 *
152 * The code in this function is a little weird because I couldn't comprehend
153 * the bucket going up when the battery level was going down. --joeo
154 *
155 * 1 means that the battery is "ok"
156 * 0 means that the battery is between "ok" and what we should warn about.
157 * less than 0 means that the battery is low
158 */
159 private int findBatteryLevelBucket(int level) {
160 if (level >= mLowBatteryAlertCloseLevel) {
161 return 1;
162 }
Dianne Hackborn14272302014-06-10 23:13:02 -0700163 if (level > mLowBatteryReminderLevels[0]) {
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700164 return 0;
165 }
166 final int N = mLowBatteryReminderLevels.length;
167 for (int i=N-1; i>=0; i--) {
168 if (level <= mLowBatteryReminderLevels[i]) {
169 return -1-i;
170 }
171 }
172 throw new RuntimeException("not possible!");
173 }
174
Amin Shaikh2f6c45c2018-04-16 14:00:09 -0400175 @VisibleForTesting
176 final class Receiver extends BroadcastReceiver {
John Spurlock3332ba52014-03-10 17:44:07 -0400177
178 public void init() {
179 // Register for Intent broadcasts for...
180 IntentFilter filter = new IntentFilter();
Amin Shaikh2f6c45c2018-04-16 14:00:09 -0400181 filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
John Spurlock3332ba52014-03-10 17:44:07 -0400182 filter.addAction(Intent.ACTION_BATTERY_CHANGED);
183 filter.addAction(Intent.ACTION_SCREEN_OFF);
184 filter.addAction(Intent.ACTION_SCREEN_ON);
John Spurlockecbc5e82014-10-22 09:05:51 -0400185 filter.addAction(Intent.ACTION_USER_SWITCHED);
John Spurlock3332ba52014-03-10 17:44:07 -0400186 mContext.registerReceiver(this, filter, null, mHandler);
John Spurlock3332ba52014-03-10 17:44:07 -0400187 }
188
Joe Onorato10523b4d2010-10-25 10:42:46 -0700189 @Override
190 public void onReceive(Context context, Intent intent) {
191 String action = intent.getAction();
Amin Shaikh2f6c45c2018-04-16 14:00:09 -0400192 if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)) {
193 ThreadUtils.postOnBackgroundThread(() -> {
194 if (mPowerManager.isPowerSaveMode()) {
195 mWarnings.dismissLowBatteryWarning();
196 }
197 });
198 } else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700199 final int oldBatteryLevel = mBatteryLevel;
200 mBatteryLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 100);
201 final int oldBatteryStatus = mBatteryStatus;
202 mBatteryStatus = intent.getIntExtra(BatteryManager.EXTRA_STATUS,
203 BatteryManager.BATTERY_STATUS_UNKNOWN);
204 final int oldPlugType = mPlugType;
205 mPlugType = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 1);
206 final int oldInvalidCharger = mInvalidCharger;
207 mInvalidCharger = intent.getIntExtra(BatteryManager.EXTRA_INVALID_CHARGER, 0);
208
209 final boolean plugged = mPlugType != 0;
210 final boolean oldPlugged = oldPlugType != 0;
211
212 int oldBucket = findBatteryLevelBucket(oldBatteryLevel);
213 int bucket = findBatteryLevelBucket(mBatteryLevel);
214
Daniel Sandler71986622011-07-26 13:06:49 -0400215 if (DEBUG) {
Daniel Sandlerdea64622013-09-23 16:05:57 -0400216 Slog.d(TAG, "buckets ....." + mLowBatteryAlertCloseLevel
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700217 + " .. " + mLowBatteryReminderLevels[0]
218 + " .. " + mLowBatteryReminderLevels[1]);
Daniel Sandlerdea64622013-09-23 16:05:57 -0400219 Slog.d(TAG, "level " + oldBatteryLevel + " --> " + mBatteryLevel);
220 Slog.d(TAG, "status " + oldBatteryStatus + " --> " + mBatteryStatus);
221 Slog.d(TAG, "plugType " + oldPlugType + " --> " + mPlugType);
222 Slog.d(TAG, "invalidCharger " + oldInvalidCharger + " --> " + mInvalidCharger);
223 Slog.d(TAG, "bucket " + oldBucket + " --> " + bucket);
224 Slog.d(TAG, "plugged " + oldPlugged + " --> " + plugged);
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700225 }
226
John Spurlocked452c52014-03-06 12:02:31 -0500227 mWarnings.update(mBatteryLevel, bucket, mScreenOffTime);
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700228 if (oldInvalidCharger == 0 && mInvalidCharger != 0) {
Daniel Sandlerdea64622013-09-23 16:05:57 -0400229 Slog.d(TAG, "showing invalid charger warning");
John Spurlocked452c52014-03-06 12:02:31 -0500230 mWarnings.showInvalidChargerWarning();
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700231 return;
232 } else if (oldInvalidCharger != 0 && mInvalidCharger == 0) {
John Spurlocked452c52014-03-06 12:02:31 -0500233 mWarnings.dismissInvalidChargerWarning();
234 } else if (mWarnings.isInvalidChargerWarningShowing()) {
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700235 // if invalid charger is showing, don't show low battery
236 return;
237 }
238
Salvador Martinezf9e47502018-01-04 13:45:48 -0800239 // Show the correct version of low battery warning if needed
Salvador Martinez7ad2c172019-02-11 16:09:28 -0800240 if (mLastShowWarningTask != null) {
241 mLastShowWarningTask.cancel(true);
242 }
243 mLastShowWarningTask = ThreadUtils.postOnBackgroundThread(() -> {
Salvador Martinez926f0712018-07-03 18:07:07 -0700244 maybeShowBatteryWarning(
245 oldBatteryLevel, plugged, oldPlugged, oldBucket, bucket);
Salvador Martinez110f9a12018-01-31 09:57:17 -0800246 });
Beverly334bc5f2017-07-31 10:37:17 -0400247
Daniel Sandlerdea64622013-09-23 16:05:57 -0400248 } else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
249 mScreenOffTime = SystemClock.elapsedRealtime();
250 } else if (Intent.ACTION_SCREEN_ON.equals(action)) {
251 mScreenOffTime = -1;
John Spurlockecbc5e82014-10-22 09:05:51 -0400252 } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
253 mWarnings.userSwitched();
Joe Onorato10523b4d2010-10-25 10:42:46 -0700254 } else {
Daniel Sandlerdea64622013-09-23 16:05:57 -0400255 Slog.w(TAG, "unknown intent: " + intent);
Joe Onorato10523b4d2010-10-25 10:42:46 -0700256 }
257 }
Salvador Martinezf9e47502018-01-04 13:45:48 -0800258 }
259
Salvador Martinez926f0712018-07-03 18:07:07 -0700260 protected void maybeShowBatteryWarning(int oldBatteryLevel, boolean plugged, boolean oldPlugged,
261 int oldBucket, int bucket) {
Salvador Martinezf9e47502018-01-04 13:45:48 -0800262 boolean isPowerSaver = mPowerManager.isPowerSaveMode();
263 // only play SFX when the dialog comes up or the bucket changes
264 final boolean playSound = bucket != oldBucket || oldPlugged;
Salvador Martinezfd38aa52018-03-28 23:56:59 -0700265 final boolean hybridEnabled = mEnhancedEstimates.isHybridNotificationEnabled();
266 if (hybridEnabled) {
Salvador Martinez926f0712018-07-03 18:07:07 -0700267 Estimate estimate = mLastEstimate;
268 if (estimate == null || mBatteryLevel != oldBatteryLevel) {
269 estimate = mEnhancedEstimates.getEstimate();
270 mLastEstimate = estimate;
271 }
Salvador Martinez7ad2c172019-02-11 16:09:28 -0800272 // Turbo is not always booted once SysUI is running so we have to make sure we actually
Salvador Martinezf9e47502018-01-04 13:45:48 -0800273 // get data back
274 if (estimate != null) {
275 mTimeRemaining = estimate.estimateMillis;
276 mWarnings.updateEstimate(estimate);
Salvador Martinezbb902fc2018-01-22 19:46:55 -0800277 mWarnings.updateThresholds(mEnhancedEstimates.getLowWarningThreshold(),
278 mEnhancedEstimates.getSevereWarningThreshold());
Salvador Martinezfd38aa52018-03-28 23:56:59 -0700279
280 // if we are now over 45% battery & 6 hours remaining we can trigger hybrid
281 // notification again
282 if (mBatteryLevel >= CHARGE_CYCLE_PERCENT_RESET
283 && mTimeRemaining > SIX_HOURS_MILLIS) {
284 mLowWarningShownThisChargeCycle = false;
285 mSevereWarningShownThisChargeCycle = false;
286 }
Salvador Martinezf9e47502018-01-04 13:45:48 -0800287 }
288 }
289
Salvador Martinez36307962018-02-08 14:29:08 -0800290 if (shouldShowLowBatteryWarning(plugged, oldPlugged, oldBucket, bucket,
291 mTimeRemaining, isPowerSaver, mBatteryStatus)) {
Salvador Martinezf9e47502018-01-04 13:45:48 -0800292 mWarnings.showLowBatteryWarning(playSound);
Salvador Martinez36307962018-02-08 14:29:08 -0800293
Salvador Martinezfd38aa52018-03-28 23:56:59 -0700294 // mark if we've already shown a warning this cycle. This will prevent the notification
295 // trigger from spamming users by only showing low/critical warnings once per cycle
296 if (hybridEnabled) {
Salvador Martinez88b0d502018-10-01 11:31:43 -0700297 if (mTimeRemaining <= mEnhancedEstimates.getSevereWarningThreshold()
298 || mBatteryLevel <= mLowBatteryReminderLevels[1]) {
Salvador Martinezfd38aa52018-03-28 23:56:59 -0700299 mSevereWarningShownThisChargeCycle = true;
Salvador Martinez88b0d502018-10-01 11:31:43 -0700300 mLowWarningShownThisChargeCycle = true;
Salvador Martinezfd38aa52018-03-28 23:56:59 -0700301 } else {
302 mLowWarningShownThisChargeCycle = true;
303 }
Salvador Martinez36307962018-02-08 14:29:08 -0800304 }
Salvador Martinezf9e47502018-01-04 13:45:48 -0800305 } else if (shouldDismissLowBatteryWarning(plugged, oldBucket, bucket, mTimeRemaining,
306 isPowerSaver)) {
307 mWarnings.dismissLowBatteryWarning();
308 } else {
309 mWarnings.updateLowBatteryWarning();
310 }
311 }
312
313 @VisibleForTesting
314 boolean shouldShowLowBatteryWarning(boolean plugged, boolean oldPlugged, int oldBucket,
Salvador Martinezfd38aa52018-03-28 23:56:59 -0700315 int bucket, long timeRemaining, boolean isPowerSaver, int batteryStatus) {
316 if (mEnhancedEstimates.isHybridNotificationEnabled()) {
317 // triggering logic when enhanced estimate is available
318 return isEnhancedTrigger(plugged, timeRemaining, isPowerSaver, batteryStatus);
319 }
320 // legacy triggering logic
Salvador Martinezf9e47502018-01-04 13:45:48 -0800321 return !plugged
322 && !isPowerSaver
Salvador Martinezfd38aa52018-03-28 23:56:59 -0700323 && (((bucket < oldBucket || oldPlugged) && bucket < 0))
324 && batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN;
Salvador Martinezf9e47502018-01-04 13:45:48 -0800325 }
326
Salvador Martinezf9e47502018-01-04 13:45:48 -0800327 @VisibleForTesting
328 boolean shouldDismissLowBatteryWarning(boolean plugged, int oldBucket, int bucket,
329 long timeRemaining, boolean isPowerSaver) {
Salvador Martinezc25604b2018-08-03 14:07:44 -0700330 final boolean hybridEnabled = mEnhancedEstimates.isHybridNotificationEnabled();
331 final boolean hybridWouldDismiss = hybridEnabled
Salvador Martinezbb902fc2018-01-22 19:46:55 -0800332 && timeRemaining > mEnhancedEstimates.getLowWarningThreshold();
Salvador Martinezf9e47502018-01-04 13:45:48 -0800333 final boolean standardWouldDismiss = (bucket > oldBucket && bucket > 0);
Salvador Martinezc25604b2018-08-03 14:07:44 -0700334 return (isPowerSaver && !hybridEnabled)
Salvador Martinezf9e47502018-01-04 13:45:48 -0800335 || plugged
336 || (standardWouldDismiss && (!mEnhancedEstimates.isHybridNotificationEnabled()
337 || hybridWouldDismiss));
338 }
Joe Onorato10523b4d2010-10-25 10:42:46 -0700339
Salvador Martinezfd38aa52018-03-28 23:56:59 -0700340 private boolean isEnhancedTrigger(boolean plugged, long timeRemaining, boolean isPowerSaver,
341 int batteryStatus) {
Salvador Martinezc25604b2018-08-03 14:07:44 -0700342 if (plugged || batteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) {
Salvador Martinez36307962018-02-08 14:29:08 -0800343 return false;
344 }
Salvador Martinezfd38aa52018-03-28 23:56:59 -0700345 int warnLevel = mLowBatteryReminderLevels[0];
346 int critLevel = mLowBatteryReminderLevels[1];
Salvador Martinez36307962018-02-08 14:29:08 -0800347
Salvador Martinezc25604b2018-08-03 14:07:44 -0700348 // Only show the low warning once per charge cycle & no battery saver
349 final boolean canShowWarning = !mLowWarningShownThisChargeCycle && !isPowerSaver
Salvador Martinezfd38aa52018-03-28 23:56:59 -0700350 && (timeRemaining < mEnhancedEstimates.getLowWarningThreshold()
Salvador Martinez7ad2c172019-02-11 16:09:28 -0800351 || mBatteryLevel <= warnLevel);
Salvador Martinez36307962018-02-08 14:29:08 -0800352
Salvador Martinezfd38aa52018-03-28 23:56:59 -0700353 // Only show the severe warning once per charge cycle
354 final boolean canShowSevereWarning = !mSevereWarningShownThisChargeCycle
355 && (timeRemaining < mEnhancedEstimates.getSevereWarningThreshold()
Salvador Martinez7ad2c172019-02-11 16:09:28 -0800356 || mBatteryLevel <= critLevel);
Salvador Martinez36307962018-02-08 14:29:08 -0800357
Salvador Martinez7ad2c172019-02-11 16:09:28 -0800358 final boolean canShow = canShowWarning || canShowSevereWarning;
359 if (DEBUG) {
360 Slog.d(TAG, "Enhanced trigger is: " + canShow + "\nwith values: "
361 + " mLowWarningShownThisChargeCycle: " + mLowWarningShownThisChargeCycle
362 + " mSevereWarningShownThisChargeCycle: " + mSevereWarningShownThisChargeCycle
363 + " mEnhancedEstimates.timeremaining: " + timeRemaining
364 + " mBatteryLevel: " + mBatteryLevel
365 + " canShowWarning: " + canShowWarning
366 + " canShowSevereWarning: " + canShowSevereWarning
367 + " plugged: " + plugged
368 + " batteryStatus: " + batteryStatus
369 + " isPowerSaver: " + isPowerSaver);
370 }
Salvador Martinez36307962018-02-08 14:29:08 -0800371 return canShowWarning || canShowSevereWarning;
372 }
373
Sherry Huangce02ed32019-01-17 20:37:29 +0800374 private void initTemperature() {
Andrew Sappersteine3352562017-01-20 15:41:03 -0800375 ContentResolver resolver = mContext.getContentResolver();
376 Resources resources = mContext.getResources();
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800377
Sherry Huangce02ed32019-01-17 20:37:29 +0800378 mEnableSkinTemperatureWarning = Settings.Global.getInt(resolver,
379 Settings.Global.SHOW_TEMPERATURE_WARNING,
380 resources.getInteger(R.integer.config_showTemperatureWarning)) != 0;
381 mEnableUsbTemperatureAlarm = Settings.Global.getInt(resolver,
382 Settings.Global.SHOW_USB_TEMPERATURE_ALARM,
383 resources.getInteger(R.integer.config_showUsbPortAlarm)) != 0;
Adam Lesinski1aab3fa2017-07-31 13:42:00 -0700384
Todd Poynorfb95e122017-10-04 13:00:32 -0700385 if (mThermalService == null) {
386 // Enable push notifications of throttling from vendor thermal
387 // management subsystem via thermalservice, in addition to our
388 // usual polling, to react to temperature jumps more quickly.
Wei Wangbf05e602018-11-21 11:46:48 -0800389 IBinder b = ServiceManager.getService(Context.THERMAL_SERVICE);
Todd Poynorfb95e122017-10-04 13:00:32 -0700390
391 if (b != null) {
392 mThermalService = IThermalService.Stub.asInterface(b);
Sherry Huangce02ed32019-01-17 20:37:29 +0800393 registerThermalEventListener();
Todd Poynorfb95e122017-10-04 13:00:32 -0700394 } else {
395 Slog.w(TAG, "cannot find thermalservice, no throttling push notifications");
396 }
397 }
Sherry Huangce02ed32019-01-17 20:37:29 +0800398 }
Todd Poynorfb95e122017-10-04 13:00:32 -0700399
Sherry Huangce02ed32019-01-17 20:37:29 +0800400 @VisibleForTesting
401 void registerThermalEventListener() {
402 try {
403 if (mEnableSkinTemperatureWarning) {
404 mThermalService.registerThermalEventListenerWithType(
405 new ThermalEventSkinListener(), Temperature.TYPE_SKIN);
406 }
407 if (mEnableUsbTemperatureAlarm) {
408 mThermalService.registerThermalEventListenerWithType(
409 new ThermalEventUsbListener(), Temperature.TYPE_USB_PORT);
410 }
411 } catch (RemoteException e) {
412 Slog.e(TAG, "Failed to register thermal callback.", e);
413 }
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800414 }
415
Salvador Martineza6f7b252017-04-10 10:46:15 -0700416 private void showThermalShutdownDialog() {
417 if (mPowerManager.getLastShutdownReason()
418 == PowerManager.SHUTDOWN_REASON_THERMAL_SHUTDOWN) {
419 mWarnings.showThermalShutdownWarning();
420 }
421 }
422
Joe Onorato10523b4d2010-10-25 10:42:46 -0700423 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700424 pw.print("mLowBatteryAlertCloseLevel=");
425 pw.println(mLowBatteryAlertCloseLevel);
426 pw.print("mLowBatteryReminderLevels=");
427 pw.println(Arrays.toString(mLowBatteryReminderLevels));
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700428 pw.print("mBatteryLevel=");
429 pw.println(Integer.toString(mBatteryLevel));
430 pw.print("mBatteryStatus=");
431 pw.println(Integer.toString(mBatteryStatus));
432 pw.print("mPlugType=");
433 pw.println(Integer.toString(mPlugType));
434 pw.print("mInvalidCharger=");
435 pw.println(Integer.toString(mInvalidCharger));
Daniel Sandlerdea64622013-09-23 16:05:57 -0400436 pw.print("mScreenOffTime=");
437 pw.print(mScreenOffTime);
438 if (mScreenOffTime >= 0) {
439 pw.print(" (");
440 pw.print(SystemClock.elapsedRealtime() - mScreenOffTime);
441 pw.print(" ago)");
442 }
443 pw.println();
444 pw.print("soundTimeout=");
445 pw.println(Settings.Global.getInt(mContext.getContentResolver(),
446 Settings.Global.LOW_BATTERY_SOUND_TIMEOUT, 0));
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700447 pw.print("bucket: ");
448 pw.println(Integer.toString(findBatteryLevelBucket(mBatteryLevel)));
Sherry Huangce02ed32019-01-17 20:37:29 +0800449 pw.print("mEnableSkinTemperatureWarning=");
450 pw.println(mEnableSkinTemperatureWarning);
451 pw.print("mEnableUsbTemperatureAlarm=");
452 pw.println(mEnableUsbTemperatureAlarm);
John Spurlocked452c52014-03-06 12:02:31 -0500453 mWarnings.dump(pw);
454 }
455
456 public interface WarningsUI {
457 void update(int batteryLevel, int bucket, long screenOffTime);
Sherry Huangce02ed32019-01-17 20:37:29 +0800458
Salvador Martinezf9e47502018-01-04 13:45:48 -0800459 void updateEstimate(Estimate estimate);
Sherry Huangce02ed32019-01-17 20:37:29 +0800460
Salvador Martinezbb902fc2018-01-22 19:46:55 -0800461 void updateThresholds(long lowThreshold, long severeThreshold);
Sherry Huangce02ed32019-01-17 20:37:29 +0800462
John Spurlocked452c52014-03-06 12:02:31 -0500463 void dismissLowBatteryWarning();
Sherry Huangce02ed32019-01-17 20:37:29 +0800464
John Spurlocked452c52014-03-06 12:02:31 -0500465 void showLowBatteryWarning(boolean playSound);
Sherry Huangce02ed32019-01-17 20:37:29 +0800466
John Spurlocked452c52014-03-06 12:02:31 -0500467 void dismissInvalidChargerWarning();
Sherry Huangce02ed32019-01-17 20:37:29 +0800468
John Spurlocked452c52014-03-06 12:02:31 -0500469 void showInvalidChargerWarning();
Sherry Huangce02ed32019-01-17 20:37:29 +0800470
John Spurlocked452c52014-03-06 12:02:31 -0500471 void updateLowBatteryWarning();
Sherry Huangce02ed32019-01-17 20:37:29 +0800472
John Spurlocked452c52014-03-06 12:02:31 -0500473 boolean isInvalidChargerWarningShowing();
Sherry Huangce02ed32019-01-17 20:37:29 +0800474
Salvador Martineza6f7b252017-04-10 10:46:15 -0700475 void dismissHighTemperatureWarning();
Sherry Huangce02ed32019-01-17 20:37:29 +0800476
Salvador Martineza6f7b252017-04-10 10:46:15 -0700477 void showHighTemperatureWarning();
Sherry Huangce02ed32019-01-17 20:37:29 +0800478
479 /**
480 * Display USB overheat alarm
481 */
482 void showUsbHighTemperatureAlarm();
483
Salvador Martineza6f7b252017-04-10 10:46:15 -0700484 void showThermalShutdownWarning();
Sherry Huangce02ed32019-01-17 20:37:29 +0800485
John Spurlocked452c52014-03-06 12:02:31 -0500486 void dump(PrintWriter pw);
Sherry Huangce02ed32019-01-17 20:37:29 +0800487
John Spurlockecbc5e82014-10-22 09:05:51 -0400488 void userSwitched();
Joe Onorato10523b4d2010-10-25 10:42:46 -0700489 }
Joe Onorato10523b4d2010-10-25 10:42:46 -0700490
Sherry Huangce02ed32019-01-17 20:37:29 +0800491 // Thermal event received from thermal service manager subsystem
492 @VisibleForTesting
493 final class ThermalEventSkinListener extends IThermalEventListener.Stub {
Wei Wangbad7c202018-11-01 11:57:39 -0700494 @Override public void notifyThrottling(Temperature temp) {
Sherry Huangce02ed32019-01-17 20:37:29 +0800495 int status = temp.getStatus();
496
497 if (status >= Temperature.THROTTLING_EMERGENCY) {
498 StatusBar statusBar = getComponent(StatusBar.class);
499 if (statusBar != null && !statusBar.isDeviceInVrMode()) {
500 mWarnings.showHighTemperatureWarning();
501 Slog.d(TAG, "ThermalEventSkinListener: notifyThrottling was called "
502 + ", current skin status = " + status
503 + ", temperature = " + temp.getValue());
504 }
505 } else {
506 mWarnings.dismissHighTemperatureWarning();
507 }
508 }
509 }
510
511 // Thermal event received from thermal service manager subsystem
512 @VisibleForTesting
513 final class ThermalEventUsbListener extends IThermalEventListener.Stub {
514 @Override public void notifyThrottling(Temperature temp) {
515 int status = temp.getStatus();
516
517 if (status >= Temperature.THROTTLING_EMERGENCY) {
518 mWarnings.showUsbHighTemperatureAlarm();
519 Slog.d(TAG, "ThermalEventUsbListener: notifyThrottling was called "
520 + ", current usb port status = " + status
521 + ", temperature = " + temp.getValue());
522 }
Todd Poynorfb95e122017-10-04 13:00:32 -0700523 }
524 }
525}