blob: c43f5728aaa26a35ed3e7964e5b2004ae658cc30 [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;
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -080030import android.os.HardwarePropertiesManager;
Todd Poynorfb95e122017-10-04 13:00:32 -070031import android.os.IBinder;
32import android.os.IThermalEventListener;
33import android.os.IThermalService;
Daniel Sandlerdea64622013-09-23 16:05:57 -040034import android.os.PowerManager;
Todd Poynorfb95e122017-10-04 13:00:32 -070035import android.os.RemoteException;
36import android.os.ServiceManager;
Daniel Sandlerdea64622013-09-23 16:05:57 -040037import android.os.SystemClock;
Todd Poynorfb95e122017-10-04 13:00:32 -070038import android.os.Temperature;
Dianne Hackborn14272302014-06-10 23:13:02 -070039import android.os.UserHandle;
Joe Onorato10523b4d2010-10-25 10:42:46 -070040import android.provider.Settings;
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -080041import android.text.format.DateUtils;
John Spurlock1bb480a2014-08-02 17:12:43 -040042import android.util.Log;
Daniel Sandlerdea64622013-09-23 16:05:57 -040043import android.util.Slog;
Jason Monkd819c312017-08-11 12:53:36 -040044
45import com.android.internal.annotations.VisibleForTesting;
Andrew Sappersteina6ed7f82017-02-01 17:13:08 -080046import com.android.internal.logging.MetricsLogger;
Salvador Martinez110f9a12018-01-31 09:57:17 -080047import com.android.settingslib.utils.ThreadUtils;
Jason Monkd819c312017-08-11 12:53:36 -040048import com.android.systemui.Dependency;
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -080049import com.android.systemui.R;
Joe Onorato10523b4d2010-10-25 10:42:46 -070050import com.android.systemui.SystemUI;
Jason Monk2a6ea9c2017-01-26 11:14:51 -050051import com.android.systemui.statusbar.phone.StatusBar;
Jason Monkd819c312017-08-11 12:53:36 -040052
John Spurlockde84f0e2013-06-12 12:41:00 -040053import java.io.FileDescriptor;
54import java.io.PrintWriter;
Salvador Martinezfd38aa52018-03-28 23:56:59 -070055import java.time.Duration;
John Spurlockde84f0e2013-06-12 12:41:00 -040056import java.util.Arrays;
Salvador Martinez7ad2c172019-02-11 16:09:28 -080057import java.util.concurrent.Future;
John Spurlockde84f0e2013-06-12 12:41:00 -040058
Joe Onorato10523b4d2010-10-25 10:42:46 -070059public class PowerUI extends SystemUI {
60 static final String TAG = "PowerUI";
John Spurlock1bb480a2014-08-02 17:12:43 -040061 static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -080062 private static final long TEMPERATURE_INTERVAL = 30 * DateUtils.SECOND_IN_MILLIS;
Andrew Sappersteina6ed7f82017-02-01 17:13:08 -080063 private static final long TEMPERATURE_LOGGING_INTERVAL = DateUtils.HOUR_IN_MILLIS;
64 private static final int MAX_RECENT_TEMPS = 125; // TEMPERATURE_LOGGING_INTERVAL plus a buffer
Salvador Martinezf9e47502018-01-04 13:45:48 -080065 static final long THREE_HOURS_IN_MILLIS = DateUtils.HOUR_IN_MILLIS * 3;
Salvador Martinezfd38aa52018-03-28 23:56:59 -070066 private static final int CHARGE_CYCLE_PERCENT_RESET = 45;
67 private static final long SIX_HOURS_MILLIS = Duration.ofHours(6).toMillis();
Joe Onorato10523b4d2010-10-25 10:42:46 -070068
John Spurlocked452c52014-03-06 12:02:31 -050069 private final Handler mHandler = new Handler();
Amin Shaikh2f6c45c2018-04-16 14:00:09 -040070 @VisibleForTesting
71 final Receiver mReceiver = new Receiver();
Joe Onorato4ca7f1e2010-10-27 15:32:23 -070072
John Spurlock3332ba52014-03-10 17:44:07 -040073 private PowerManager mPowerManager;
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -080074 private HardwarePropertiesManager mHardwarePropertiesManager;
John Spurlock3332ba52014-03-10 17:44:07 -040075 private WarningsUI mWarnings;
Adam Lesinski1aab3fa2017-07-31 13:42:00 -070076 private final Configuration mLastConfiguration = new Configuration();
Salvador Martinezf9e47502018-01-04 13:45:48 -080077 private long mTimeRemaining = Long.MAX_VALUE;
John Spurlocked452c52014-03-06 12:02:31 -050078 private int mPlugType = 0;
79 private int mInvalidCharger = 0;
Salvador Martinezf9e47502018-01-04 13:45:48 -080080 private EnhancedEstimates mEnhancedEstimates;
Salvador Martinez926f0712018-07-03 18:07:07 -070081 private Estimate mLastEstimate;
Salvador Martinez36307962018-02-08 14:29:08 -080082 private boolean mLowWarningShownThisChargeCycle;
83 private boolean mSevereWarningShownThisChargeCycle;
Salvador Martinez7ad2c172019-02-11 16:09:28 -080084 private Future mLastShowWarningTask;
Joe Onorato4ca7f1e2010-10-27 15:32:23 -070085
John Spurlocked452c52014-03-06 12:02:31 -050086 private int mLowBatteryAlertCloseLevel;
87 private final int[] mLowBatteryReminderLevels = new int[2];
Joe Onorato10523b4d2010-10-25 10:42:46 -070088
Daniel Sandlerdea64622013-09-23 16:05:57 -040089 private long mScreenOffTime = -1;
90
Andrew Sappersteina6ed7f82017-02-01 17:13:08 -080091 private float mThresholdTemp;
92 private float[] mRecentTemps = new float[MAX_RECENT_TEMPS];
93 private int mNumTemps;
94 private long mNextLogTime;
Wei Wangbf05e602018-11-21 11:46:48 -080095 @VisibleForTesting IThermalService mThermalService;
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -080096
Salvador Martinezfd38aa52018-03-28 23:56:59 -070097 @VisibleForTesting int mBatteryLevel = 100;
Salvador Martinez36307962018-02-08 14:29:08 -080098 @VisibleForTesting int mBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN;
99
Adam Lesinski1aab3fa2017-07-31 13:42:00 -0700100 // by using the same instance (method references are not guaranteed to be the same object
Salvador Martinezf9e47502018-01-04 13:45:48 -0800101 // We create a method reference here so that we are guaranteed that we can remove a callback
Adam Lesinski1aab3fa2017-07-31 13:42:00 -0700102 // each time they are created).
103 private final Runnable mUpdateTempCallback = this::updateTemperatureWarning;
104
Joe Onorato10523b4d2010-10-25 10:42:46 -0700105 public void start() {
John Spurlock3332ba52014-03-10 17:44:07 -0400106 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800107 mHardwarePropertiesManager = (HardwarePropertiesManager)
108 mContext.getSystemService(Context.HARDWARE_PROPERTIES_SERVICE);
John Spurlock3332ba52014-03-10 17:44:07 -0400109 mScreenOffTime = mPowerManager.isScreenOn() ? -1 : SystemClock.elapsedRealtime();
Jason Monkd819c312017-08-11 12:53:36 -0400110 mWarnings = Dependency.get(WarningsUI.class);
Salvador Martinezf9e47502018-01-04 13:45:48 -0800111 mEnhancedEstimates = Dependency.get(EnhancedEstimates.class);
Adam Lesinski1aab3fa2017-07-31 13:42:00 -0700112 mLastConfiguration.setTo(mContext.getResources().getConfiguration());
Daniel Sandlerdea64622013-09-23 16:05:57 -0400113
Dianne Hackborn14272302014-06-10 23:13:02 -0700114 ContentObserver obs = new ContentObserver(mHandler) {
115 @Override
116 public void onChange(boolean selfChange) {
117 updateBatteryWarningLevels();
118 }
119 };
120 final ContentResolver resolver = mContext.getContentResolver();
121 resolver.registerContentObserver(Settings.Global.getUriFor(
122 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
123 false, obs, UserHandle.USER_ALL);
124 updateBatteryWarningLevels();
John Spurlock3332ba52014-03-10 17:44:07 -0400125 mReceiver.init();
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800126
Salvador Martineza6f7b252017-04-10 10:46:15 -0700127 // Check to see if we need to let the user know that the phone previously shut down due
128 // to the temperature being too high.
129 showThermalShutdownDialog();
130
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800131 initTemperatureWarning();
John Spurlock3332ba52014-03-10 17:44:07 -0400132 }
Dianne Hackborn14272302014-06-10 23:13:02 -0700133
Adam Lesinski1aab3fa2017-07-31 13:42:00 -0700134 @Override
135 protected void onConfigurationChanged(Configuration newConfig) {
136 final int mask = ActivityInfo.CONFIG_MCC | ActivityInfo.CONFIG_MNC;
137
138 // Safe to modify mLastConfiguration here as it's only updated by the main thread (here).
139 if ((mLastConfiguration.updateFrom(newConfig) & mask) != 0) {
140 mHandler.post(this::initTemperatureWarning);
141 }
142 }
143
Dianne Hackborn14272302014-06-10 23:13:02 -0700144 void updateBatteryWarningLevels() {
145 int critLevel = mContext.getResources().getInteger(
146 com.android.internal.R.integer.config_criticalBatteryWarningLevel);
Makoto Onuki16a0dd22018-03-20 10:40:37 -0700147 int warnLevel = mContext.getResources().getInteger(
Dianne Hackborn14272302014-06-10 23:13:02 -0700148 com.android.internal.R.integer.config_lowBatteryWarningLevel);
Makoto Onuki4a9036b2018-01-11 14:48:20 -0800149
Dianne Hackborn14272302014-06-10 23:13:02 -0700150 if (warnLevel < critLevel) {
151 warnLevel = critLevel;
152 }
153
154 mLowBatteryReminderLevels[0] = warnLevel;
155 mLowBatteryReminderLevels[1] = critLevel;
156 mLowBatteryAlertCloseLevel = mLowBatteryReminderLevels[0]
157 + mContext.getResources().getInteger(
158 com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
159 }
160
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700161 /**
162 * Buckets the battery level.
163 *
164 * The code in this function is a little weird because I couldn't comprehend
165 * the bucket going up when the battery level was going down. --joeo
166 *
167 * 1 means that the battery is "ok"
168 * 0 means that the battery is between "ok" and what we should warn about.
169 * less than 0 means that the battery is low
170 */
171 private int findBatteryLevelBucket(int level) {
172 if (level >= mLowBatteryAlertCloseLevel) {
173 return 1;
174 }
Dianne Hackborn14272302014-06-10 23:13:02 -0700175 if (level > mLowBatteryReminderLevels[0]) {
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700176 return 0;
177 }
178 final int N = mLowBatteryReminderLevels.length;
179 for (int i=N-1; i>=0; i--) {
180 if (level <= mLowBatteryReminderLevels[i]) {
181 return -1-i;
182 }
183 }
184 throw new RuntimeException("not possible!");
185 }
186
Amin Shaikh2f6c45c2018-04-16 14:00:09 -0400187 @VisibleForTesting
188 final class Receiver extends BroadcastReceiver {
John Spurlock3332ba52014-03-10 17:44:07 -0400189
190 public void init() {
191 // Register for Intent broadcasts for...
192 IntentFilter filter = new IntentFilter();
Amin Shaikh2f6c45c2018-04-16 14:00:09 -0400193 filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
John Spurlock3332ba52014-03-10 17:44:07 -0400194 filter.addAction(Intent.ACTION_BATTERY_CHANGED);
195 filter.addAction(Intent.ACTION_SCREEN_OFF);
196 filter.addAction(Intent.ACTION_SCREEN_ON);
John Spurlockecbc5e82014-10-22 09:05:51 -0400197 filter.addAction(Intent.ACTION_USER_SWITCHED);
John Spurlock3332ba52014-03-10 17:44:07 -0400198 mContext.registerReceiver(this, filter, null, mHandler);
John Spurlock3332ba52014-03-10 17:44:07 -0400199 }
200
Joe Onorato10523b4d2010-10-25 10:42:46 -0700201 @Override
202 public void onReceive(Context context, Intent intent) {
203 String action = intent.getAction();
Amin Shaikh2f6c45c2018-04-16 14:00:09 -0400204 if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)) {
205 ThreadUtils.postOnBackgroundThread(() -> {
206 if (mPowerManager.isPowerSaveMode()) {
207 mWarnings.dismissLowBatteryWarning();
208 }
209 });
210 } else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700211 final int oldBatteryLevel = mBatteryLevel;
212 mBatteryLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 100);
213 final int oldBatteryStatus = mBatteryStatus;
214 mBatteryStatus = intent.getIntExtra(BatteryManager.EXTRA_STATUS,
215 BatteryManager.BATTERY_STATUS_UNKNOWN);
216 final int oldPlugType = mPlugType;
217 mPlugType = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 1);
218 final int oldInvalidCharger = mInvalidCharger;
219 mInvalidCharger = intent.getIntExtra(BatteryManager.EXTRA_INVALID_CHARGER, 0);
220
221 final boolean plugged = mPlugType != 0;
222 final boolean oldPlugged = oldPlugType != 0;
223
224 int oldBucket = findBatteryLevelBucket(oldBatteryLevel);
225 int bucket = findBatteryLevelBucket(mBatteryLevel);
226
Daniel Sandler71986622011-07-26 13:06:49 -0400227 if (DEBUG) {
Daniel Sandlerdea64622013-09-23 16:05:57 -0400228 Slog.d(TAG, "buckets ....." + mLowBatteryAlertCloseLevel
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700229 + " .. " + mLowBatteryReminderLevels[0]
230 + " .. " + mLowBatteryReminderLevels[1]);
Daniel Sandlerdea64622013-09-23 16:05:57 -0400231 Slog.d(TAG, "level " + oldBatteryLevel + " --> " + mBatteryLevel);
232 Slog.d(TAG, "status " + oldBatteryStatus + " --> " + mBatteryStatus);
233 Slog.d(TAG, "plugType " + oldPlugType + " --> " + mPlugType);
234 Slog.d(TAG, "invalidCharger " + oldInvalidCharger + " --> " + mInvalidCharger);
235 Slog.d(TAG, "bucket " + oldBucket + " --> " + bucket);
236 Slog.d(TAG, "plugged " + oldPlugged + " --> " + plugged);
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700237 }
238
John Spurlocked452c52014-03-06 12:02:31 -0500239 mWarnings.update(mBatteryLevel, bucket, mScreenOffTime);
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700240 if (oldInvalidCharger == 0 && mInvalidCharger != 0) {
Daniel Sandlerdea64622013-09-23 16:05:57 -0400241 Slog.d(TAG, "showing invalid charger warning");
John Spurlocked452c52014-03-06 12:02:31 -0500242 mWarnings.showInvalidChargerWarning();
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700243 return;
244 } else if (oldInvalidCharger != 0 && mInvalidCharger == 0) {
John Spurlocked452c52014-03-06 12:02:31 -0500245 mWarnings.dismissInvalidChargerWarning();
246 } else if (mWarnings.isInvalidChargerWarningShowing()) {
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700247 // if invalid charger is showing, don't show low battery
248 return;
249 }
250
Salvador Martinezf9e47502018-01-04 13:45:48 -0800251 // Show the correct version of low battery warning if needed
Salvador Martinez7ad2c172019-02-11 16:09:28 -0800252 if (mLastShowWarningTask != null) {
253 mLastShowWarningTask.cancel(true);
254 }
255 mLastShowWarningTask = ThreadUtils.postOnBackgroundThread(() -> {
Salvador Martinez926f0712018-07-03 18:07:07 -0700256 maybeShowBatteryWarning(
257 oldBatteryLevel, plugged, oldPlugged, oldBucket, bucket);
Salvador Martinez110f9a12018-01-31 09:57:17 -0800258 });
Beverly334bc5f2017-07-31 10:37:17 -0400259
Daniel Sandlerdea64622013-09-23 16:05:57 -0400260 } else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
261 mScreenOffTime = SystemClock.elapsedRealtime();
262 } else if (Intent.ACTION_SCREEN_ON.equals(action)) {
263 mScreenOffTime = -1;
John Spurlockecbc5e82014-10-22 09:05:51 -0400264 } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
265 mWarnings.userSwitched();
Joe Onorato10523b4d2010-10-25 10:42:46 -0700266 } else {
Daniel Sandlerdea64622013-09-23 16:05:57 -0400267 Slog.w(TAG, "unknown intent: " + intent);
Joe Onorato10523b4d2010-10-25 10:42:46 -0700268 }
269 }
Salvador Martinezf9e47502018-01-04 13:45:48 -0800270 }
271
Salvador Martinez926f0712018-07-03 18:07:07 -0700272 protected void maybeShowBatteryWarning(int oldBatteryLevel, boolean plugged, boolean oldPlugged,
273 int oldBucket, int bucket) {
Salvador Martinezf9e47502018-01-04 13:45:48 -0800274 boolean isPowerSaver = mPowerManager.isPowerSaveMode();
275 // only play SFX when the dialog comes up or the bucket changes
276 final boolean playSound = bucket != oldBucket || oldPlugged;
Salvador Martinezfd38aa52018-03-28 23:56:59 -0700277 final boolean hybridEnabled = mEnhancedEstimates.isHybridNotificationEnabled();
278 if (hybridEnabled) {
Salvador Martinez926f0712018-07-03 18:07:07 -0700279 Estimate estimate = mLastEstimate;
280 if (estimate == null || mBatteryLevel != oldBatteryLevel) {
281 estimate = mEnhancedEstimates.getEstimate();
282 mLastEstimate = estimate;
283 }
Salvador Martinez7ad2c172019-02-11 16:09:28 -0800284 // Turbo is not always booted once SysUI is running so we have to make sure we actually
Salvador Martinezf9e47502018-01-04 13:45:48 -0800285 // get data back
286 if (estimate != null) {
287 mTimeRemaining = estimate.estimateMillis;
288 mWarnings.updateEstimate(estimate);
Salvador Martinezbb902fc2018-01-22 19:46:55 -0800289 mWarnings.updateThresholds(mEnhancedEstimates.getLowWarningThreshold(),
290 mEnhancedEstimates.getSevereWarningThreshold());
Salvador Martinezfd38aa52018-03-28 23:56:59 -0700291
292 // if we are now over 45% battery & 6 hours remaining we can trigger hybrid
293 // notification again
294 if (mBatteryLevel >= CHARGE_CYCLE_PERCENT_RESET
295 && mTimeRemaining > SIX_HOURS_MILLIS) {
296 mLowWarningShownThisChargeCycle = false;
297 mSevereWarningShownThisChargeCycle = false;
298 }
Salvador Martinezf9e47502018-01-04 13:45:48 -0800299 }
300 }
301
Salvador Martinez36307962018-02-08 14:29:08 -0800302 if (shouldShowLowBatteryWarning(plugged, oldPlugged, oldBucket, bucket,
303 mTimeRemaining, isPowerSaver, mBatteryStatus)) {
Salvador Martinezf9e47502018-01-04 13:45:48 -0800304 mWarnings.showLowBatteryWarning(playSound);
Salvador Martinez36307962018-02-08 14:29:08 -0800305
Salvador Martinezfd38aa52018-03-28 23:56:59 -0700306 // mark if we've already shown a warning this cycle. This will prevent the notification
307 // trigger from spamming users by only showing low/critical warnings once per cycle
308 if (hybridEnabled) {
Salvador Martinez88b0d502018-10-01 11:31:43 -0700309 if (mTimeRemaining <= mEnhancedEstimates.getSevereWarningThreshold()
310 || mBatteryLevel <= mLowBatteryReminderLevels[1]) {
Salvador Martinezfd38aa52018-03-28 23:56:59 -0700311 mSevereWarningShownThisChargeCycle = true;
Salvador Martinez88b0d502018-10-01 11:31:43 -0700312 mLowWarningShownThisChargeCycle = true;
Salvador Martinezfd38aa52018-03-28 23:56:59 -0700313 } else {
314 mLowWarningShownThisChargeCycle = true;
315 }
Salvador Martinez36307962018-02-08 14:29:08 -0800316 }
Salvador Martinezf9e47502018-01-04 13:45:48 -0800317 } else if (shouldDismissLowBatteryWarning(plugged, oldBucket, bucket, mTimeRemaining,
318 isPowerSaver)) {
319 mWarnings.dismissLowBatteryWarning();
320 } else {
321 mWarnings.updateLowBatteryWarning();
322 }
323 }
324
325 @VisibleForTesting
326 boolean shouldShowLowBatteryWarning(boolean plugged, boolean oldPlugged, int oldBucket,
Salvador Martinezfd38aa52018-03-28 23:56:59 -0700327 int bucket, long timeRemaining, boolean isPowerSaver, int batteryStatus) {
328 if (mEnhancedEstimates.isHybridNotificationEnabled()) {
329 // triggering logic when enhanced estimate is available
330 return isEnhancedTrigger(plugged, timeRemaining, isPowerSaver, batteryStatus);
331 }
332 // legacy triggering logic
Salvador Martinezf9e47502018-01-04 13:45:48 -0800333 return !plugged
334 && !isPowerSaver
Salvador Martinezfd38aa52018-03-28 23:56:59 -0700335 && (((bucket < oldBucket || oldPlugged) && bucket < 0))
336 && batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN;
Salvador Martinezf9e47502018-01-04 13:45:48 -0800337 }
338
Salvador Martinezf9e47502018-01-04 13:45:48 -0800339 @VisibleForTesting
340 boolean shouldDismissLowBatteryWarning(boolean plugged, int oldBucket, int bucket,
341 long timeRemaining, boolean isPowerSaver) {
Salvador Martinezc25604b2018-08-03 14:07:44 -0700342 final boolean hybridEnabled = mEnhancedEstimates.isHybridNotificationEnabled();
343 final boolean hybridWouldDismiss = hybridEnabled
Salvador Martinezbb902fc2018-01-22 19:46:55 -0800344 && timeRemaining > mEnhancedEstimates.getLowWarningThreshold();
Salvador Martinezf9e47502018-01-04 13:45:48 -0800345 final boolean standardWouldDismiss = (bucket > oldBucket && bucket > 0);
Salvador Martinezc25604b2018-08-03 14:07:44 -0700346 return (isPowerSaver && !hybridEnabled)
Salvador Martinezf9e47502018-01-04 13:45:48 -0800347 || plugged
348 || (standardWouldDismiss && (!mEnhancedEstimates.isHybridNotificationEnabled()
349 || hybridWouldDismiss));
350 }
Joe Onorato10523b4d2010-10-25 10:42:46 -0700351
Salvador Martinezfd38aa52018-03-28 23:56:59 -0700352 private boolean isEnhancedTrigger(boolean plugged, long timeRemaining, boolean isPowerSaver,
353 int batteryStatus) {
Salvador Martinezc25604b2018-08-03 14:07:44 -0700354 if (plugged || batteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) {
Salvador Martinez36307962018-02-08 14:29:08 -0800355 return false;
356 }
Salvador Martinezfd38aa52018-03-28 23:56:59 -0700357 int warnLevel = mLowBatteryReminderLevels[0];
358 int critLevel = mLowBatteryReminderLevels[1];
Salvador Martinez36307962018-02-08 14:29:08 -0800359
Salvador Martinezc25604b2018-08-03 14:07:44 -0700360 // Only show the low warning once per charge cycle & no battery saver
361 final boolean canShowWarning = !mLowWarningShownThisChargeCycle && !isPowerSaver
Salvador Martinezfd38aa52018-03-28 23:56:59 -0700362 && (timeRemaining < mEnhancedEstimates.getLowWarningThreshold()
Salvador Martinez7ad2c172019-02-11 16:09:28 -0800363 || mBatteryLevel <= warnLevel);
Salvador Martinez36307962018-02-08 14:29:08 -0800364
Salvador Martinezfd38aa52018-03-28 23:56:59 -0700365 // Only show the severe warning once per charge cycle
366 final boolean canShowSevereWarning = !mSevereWarningShownThisChargeCycle
367 && (timeRemaining < mEnhancedEstimates.getSevereWarningThreshold()
Salvador Martinez7ad2c172019-02-11 16:09:28 -0800368 || mBatteryLevel <= critLevel);
Salvador Martinez36307962018-02-08 14:29:08 -0800369
Salvador Martinez7ad2c172019-02-11 16:09:28 -0800370 final boolean canShow = canShowWarning || canShowSevereWarning;
371 if (DEBUG) {
372 Slog.d(TAG, "Enhanced trigger is: " + canShow + "\nwith values: "
373 + " mLowWarningShownThisChargeCycle: " + mLowWarningShownThisChargeCycle
374 + " mSevereWarningShownThisChargeCycle: " + mSevereWarningShownThisChargeCycle
375 + " mEnhancedEstimates.timeremaining: " + timeRemaining
376 + " mBatteryLevel: " + mBatteryLevel
377 + " canShowWarning: " + canShowWarning
378 + " canShowSevereWarning: " + canShowSevereWarning
379 + " plugged: " + plugged
380 + " batteryStatus: " + batteryStatus
381 + " isPowerSaver: " + isPowerSaver);
382 }
Salvador Martinez36307962018-02-08 14:29:08 -0800383 return canShowWarning || canShowSevereWarning;
384 }
385
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800386 private void initTemperatureWarning() {
Andrew Sappersteine3352562017-01-20 15:41:03 -0800387 ContentResolver resolver = mContext.getContentResolver();
388 Resources resources = mContext.getResources();
389 if (Settings.Global.getInt(resolver, Settings.Global.SHOW_TEMPERATURE_WARNING,
390 resources.getInteger(R.integer.config_showTemperatureWarning)) == 0) {
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800391 return;
392 }
393
Andrew Sappersteina6ed7f82017-02-01 17:13:08 -0800394 mThresholdTemp = Settings.Global.getFloat(resolver, Settings.Global.WARNING_TEMPERATURE,
Andrew Sappersteine3352562017-01-20 15:41:03 -0800395 resources.getInteger(R.integer.config_warningTemperature));
Andrew Sapperstein75184712017-01-05 16:45:37 -0800396
Andrew Sappersteina6ed7f82017-02-01 17:13:08 -0800397 if (mThresholdTemp < 0f) {
Todd Poynorfb95e122017-10-04 13:00:32 -0700398 // Get the shutdown temperature, adjust for warning tolerance.
Andrew Sapperstein75184712017-01-05 16:45:37 -0800399 float[] throttlingTemps = mHardwarePropertiesManager.getDeviceTemperatures(
400 HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN,
Jason Monkd819c312017-08-11 12:53:36 -0400401 HardwarePropertiesManager.TEMPERATURE_SHUTDOWN);
Andrew Sapperstein75184712017-01-05 16:45:37 -0800402 if (throttlingTemps == null
403 || throttlingTemps.length == 0
404 || throttlingTemps[0] == HardwarePropertiesManager.UNDEFINED_TEMPERATURE) {
405 return;
406 }
Jason Monkd819c312017-08-11 12:53:36 -0400407 mThresholdTemp = throttlingTemps[0] -
408 resources.getInteger(R.integer.config_warningTemperatureTolerance);
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800409 }
Adam Lesinski1aab3fa2017-07-31 13:42:00 -0700410
Todd Poynorfb95e122017-10-04 13:00:32 -0700411 if (mThermalService == null) {
412 // Enable push notifications of throttling from vendor thermal
413 // management subsystem via thermalservice, in addition to our
414 // usual polling, to react to temperature jumps more quickly.
Wei Wangbf05e602018-11-21 11:46:48 -0800415 IBinder b = ServiceManager.getService(Context.THERMAL_SERVICE);
Todd Poynorfb95e122017-10-04 13:00:32 -0700416
417 if (b != null) {
418 mThermalService = IThermalService.Stub.asInterface(b);
419 try {
Wei Wangbad7c202018-11-01 11:57:39 -0700420 mThermalService.registerThermalEventListenerWithType(
421 new ThermalEventListener(), Temperature.TYPE_SKIN);
Todd Poynorfb95e122017-10-04 13:00:32 -0700422 } catch (RemoteException e) {
423 // Should never happen.
424 }
425 } else {
426 Slog.w(TAG, "cannot find thermalservice, no throttling push notifications");
427 }
428 }
429
Andrew Sappersteina6ed7f82017-02-01 17:13:08 -0800430 setNextLogTime();
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800431
432 // We have passed all of the checks, start checking the temp
Wei Wangfeb9de62018-11-26 14:35:17 -0800433 mHandler.post(mUpdateTempCallback);
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800434 }
435
Salvador Martineza6f7b252017-04-10 10:46:15 -0700436 private void showThermalShutdownDialog() {
437 if (mPowerManager.getLastShutdownReason()
438 == PowerManager.SHUTDOWN_REASON_THERMAL_SHUTDOWN) {
439 mWarnings.showThermalShutdownWarning();
440 }
441 }
442
Jason Monkd819c312017-08-11 12:53:36 -0400443 @VisibleForTesting
444 protected void updateTemperatureWarning() {
Andrew Sappersteina6ed7f82017-02-01 17:13:08 -0800445 float[] temps = mHardwarePropertiesManager.getDeviceTemperatures(
446 HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN,
447 HardwarePropertiesManager.TEMPERATURE_CURRENT);
448 if (temps.length != 0) {
449 float temp = temps[0];
450 mRecentTemps[mNumTemps++] = temp;
451
452 StatusBar statusBar = getComponent(StatusBar.class);
453 if (statusBar != null && !statusBar.isDeviceInVrMode()
454 && temp >= mThresholdTemp) {
455 logAtTemperatureThreshold(temp);
Salvador Martineza6f7b252017-04-10 10:46:15 -0700456 mWarnings.showHighTemperatureWarning();
Andrew Sapperstein65d8a5f2016-12-19 14:36:33 -0800457 } else {
Salvador Martineza6f7b252017-04-10 10:46:15 -0700458 mWarnings.dismissHighTemperatureWarning();
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800459 }
460 }
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800461
Andrew Sappersteina6ed7f82017-02-01 17:13:08 -0800462 logTemperatureStats();
463
Wei Wangfeb9de62018-11-26 14:35:17 -0800464 // Remove any pending callbacks as we only want to enable one
465 mHandler.removeCallbacks(mUpdateTempCallback);
Adam Lesinski1aab3fa2017-07-31 13:42:00 -0700466 mHandler.postDelayed(mUpdateTempCallback, TEMPERATURE_INTERVAL);
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800467 }
468
Andrew Sappersteina6ed7f82017-02-01 17:13:08 -0800469 private void logAtTemperatureThreshold(float temp) {
470 StringBuilder sb = new StringBuilder();
471 sb.append("currentTemp=").append(temp)
472 .append(",thresholdTemp=").append(mThresholdTemp)
473 .append(",batteryStatus=").append(mBatteryStatus)
474 .append(",recentTemps=");
475 for (int i = 0; i < mNumTemps; i++) {
476 sb.append(mRecentTemps[i]).append(',');
477 }
478 Slog.i(TAG, sb.toString());
479 }
480
481 /**
482 * Calculates and logs min, max, and average
483 * {@link HardwarePropertiesManager#DEVICE_TEMPERATURE_SKIN} over the past
484 * {@link #TEMPERATURE_LOGGING_INTERVAL}.
485 */
486 private void logTemperatureStats() {
487 if (mNextLogTime > System.currentTimeMillis() && mNumTemps != MAX_RECENT_TEMPS) {
488 return;
489 }
490
491 if (mNumTemps > 0) {
492 float sum = mRecentTemps[0], min = mRecentTemps[0], max = mRecentTemps[0];
493 for (int i = 1; i < mNumTemps; i++) {
494 float temp = mRecentTemps[i];
495 sum += temp;
496 if (temp > max) {
497 max = temp;
498 }
499 if (temp < min) {
500 min = temp;
501 }
502 }
503
504 float avg = sum / mNumTemps;
505 Slog.i(TAG, "avg=" + avg + ",min=" + min + ",max=" + max);
506 MetricsLogger.histogram(mContext, "device_skin_temp_avg", (int) avg);
507 MetricsLogger.histogram(mContext, "device_skin_temp_min", (int) min);
508 MetricsLogger.histogram(mContext, "device_skin_temp_max", (int) max);
509 }
510 setNextLogTime();
511 mNumTemps = 0;
512 }
513
514 private void setNextLogTime() {
515 mNextLogTime = System.currentTimeMillis() + TEMPERATURE_LOGGING_INTERVAL;
516 }
517
Joe Onorato10523b4d2010-10-25 10:42:46 -0700518 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700519 pw.print("mLowBatteryAlertCloseLevel=");
520 pw.println(mLowBatteryAlertCloseLevel);
521 pw.print("mLowBatteryReminderLevels=");
522 pw.println(Arrays.toString(mLowBatteryReminderLevels));
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700523 pw.print("mBatteryLevel=");
524 pw.println(Integer.toString(mBatteryLevel));
525 pw.print("mBatteryStatus=");
526 pw.println(Integer.toString(mBatteryStatus));
527 pw.print("mPlugType=");
528 pw.println(Integer.toString(mPlugType));
529 pw.print("mInvalidCharger=");
530 pw.println(Integer.toString(mInvalidCharger));
Daniel Sandlerdea64622013-09-23 16:05:57 -0400531 pw.print("mScreenOffTime=");
532 pw.print(mScreenOffTime);
533 if (mScreenOffTime >= 0) {
534 pw.print(" (");
535 pw.print(SystemClock.elapsedRealtime() - mScreenOffTime);
536 pw.print(" ago)");
537 }
538 pw.println();
539 pw.print("soundTimeout=");
540 pw.println(Settings.Global.getInt(mContext.getContentResolver(),
541 Settings.Global.LOW_BATTERY_SOUND_TIMEOUT, 0));
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700542 pw.print("bucket: ");
543 pw.println(Integer.toString(findBatteryLevelBucket(mBatteryLevel)));
Andrew Sappersteina6ed7f82017-02-01 17:13:08 -0800544 pw.print("mThresholdTemp=");
545 pw.println(Float.toString(mThresholdTemp));
546 pw.print("mNextLogTime=");
547 pw.println(Long.toString(mNextLogTime));
John Spurlocked452c52014-03-06 12:02:31 -0500548 mWarnings.dump(pw);
549 }
550
551 public interface WarningsUI {
552 void update(int batteryLevel, int bucket, long screenOffTime);
Salvador Martinezf9e47502018-01-04 13:45:48 -0800553 void updateEstimate(Estimate estimate);
Salvador Martinezbb902fc2018-01-22 19:46:55 -0800554 void updateThresholds(long lowThreshold, long severeThreshold);
John Spurlocked452c52014-03-06 12:02:31 -0500555 void dismissLowBatteryWarning();
556 void showLowBatteryWarning(boolean playSound);
557 void dismissInvalidChargerWarning();
558 void showInvalidChargerWarning();
559 void updateLowBatteryWarning();
560 boolean isInvalidChargerWarningShowing();
Salvador Martineza6f7b252017-04-10 10:46:15 -0700561 void dismissHighTemperatureWarning();
562 void showHighTemperatureWarning();
563 void showThermalShutdownWarning();
John Spurlocked452c52014-03-06 12:02:31 -0500564 void dump(PrintWriter pw);
John Spurlockecbc5e82014-10-22 09:05:51 -0400565 void userSwitched();
Joe Onorato10523b4d2010-10-25 10:42:46 -0700566 }
Joe Onorato10523b4d2010-10-25 10:42:46 -0700567
Todd Poynorfb95e122017-10-04 13:00:32 -0700568 // Thermal event received from vendor thermal management subsystem
569 private final class ThermalEventListener extends IThermalEventListener.Stub {
Wei Wangbad7c202018-11-01 11:57:39 -0700570 @Override public void notifyThrottling(Temperature temp) {
Wei Wangfeb9de62018-11-26 14:35:17 -0800571 mHandler.post(mUpdateTempCallback);
Todd Poynorfb95e122017-10-04 13:00:32 -0700572 }
573 }
574}