blob: c5aab601283cae94fad177be2632796611143117 [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;
Jason Monkd819c312017-08-11 12:53:36 -040047import com.android.systemui.Dependency;
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -080048import com.android.systemui.R;
Joe Onorato10523b4d2010-10-25 10:42:46 -070049import com.android.systemui.SystemUI;
Jason Monk2a6ea9c2017-01-26 11:14:51 -050050import com.android.systemui.statusbar.phone.StatusBar;
Jason Monkd819c312017-08-11 12:53:36 -040051
John Spurlockde84f0e2013-06-12 12:41:00 -040052import java.io.FileDescriptor;
53import java.io.PrintWriter;
54import java.util.Arrays;
Salvador Martinezf9e47502018-01-04 13:45:48 -080055import java.util.concurrent.TimeUnit;
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;
Joe Onorato10523b4d2010-10-25 10:42:46 -070064
John Spurlocked452c52014-03-06 12:02:31 -050065 private final Handler mHandler = new Handler();
John Spurlock3332ba52014-03-10 17:44:07 -040066 private final Receiver mReceiver = new Receiver();
Joe Onorato4ca7f1e2010-10-27 15:32:23 -070067
John Spurlock3332ba52014-03-10 17:44:07 -040068 private PowerManager mPowerManager;
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -080069 private HardwarePropertiesManager mHardwarePropertiesManager;
John Spurlock3332ba52014-03-10 17:44:07 -040070 private WarningsUI mWarnings;
Adam Lesinski1aab3fa2017-07-31 13:42:00 -070071 private final Configuration mLastConfiguration = new Configuration();
John Spurlocked452c52014-03-06 12:02:31 -050072 private int mBatteryLevel = 100;
Salvador Martinezf9e47502018-01-04 13:45:48 -080073 private long mTimeRemaining = Long.MAX_VALUE;
John Spurlocked452c52014-03-06 12:02:31 -050074 private int mBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN;
75 private int mPlugType = 0;
76 private int mInvalidCharger = 0;
Salvador Martinezf9e47502018-01-04 13:45:48 -080077 private EnhancedEstimates mEnhancedEstimates;
Joe Onorato4ca7f1e2010-10-27 15:32:23 -070078
John Spurlocked452c52014-03-06 12:02:31 -050079 private int mLowBatteryAlertCloseLevel;
80 private final int[] mLowBatteryReminderLevels = new int[2];
Joe Onorato10523b4d2010-10-25 10:42:46 -070081
Daniel Sandlerdea64622013-09-23 16:05:57 -040082 private long mScreenOffTime = -1;
83
Andrew Sappersteina6ed7f82017-02-01 17:13:08 -080084 private float mThresholdTemp;
85 private float[] mRecentTemps = new float[MAX_RECENT_TEMPS];
86 private int mNumTemps;
87 private long mNextLogTime;
Todd Poynorfb95e122017-10-04 13:00:32 -070088 private IThermalService mThermalService;
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -080089
Adam Lesinski1aab3fa2017-07-31 13:42:00 -070090 // by using the same instance (method references are not guaranteed to be the same object
Salvador Martinezf9e47502018-01-04 13:45:48 -080091 // We create a method reference here so that we are guaranteed that we can remove a callback
Adam Lesinski1aab3fa2017-07-31 13:42:00 -070092 // each time they are created).
93 private final Runnable mUpdateTempCallback = this::updateTemperatureWarning;
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);
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -080097 mHardwarePropertiesManager = (HardwarePropertiesManager)
98 mContext.getSystemService(Context.HARDWARE_PROPERTIES_SERVICE);
John Spurlock3332ba52014-03-10 17:44:07 -040099 mScreenOffTime = mPowerManager.isScreenOn() ? -1 : SystemClock.elapsedRealtime();
Jason Monkd819c312017-08-11 12:53:36 -0400100 mWarnings = Dependency.get(WarningsUI.class);
Salvador Martinezf9e47502018-01-04 13:45:48 -0800101 mEnhancedEstimates = Dependency.get(EnhancedEstimates.class);
Adam Lesinski1aab3fa2017-07-31 13:42:00 -0700102 mLastConfiguration.setTo(mContext.getResources().getConfiguration());
Daniel Sandlerdea64622013-09-23 16:05:57 -0400103
Dianne Hackborn14272302014-06-10 23:13:02 -0700104 ContentObserver obs = new ContentObserver(mHandler) {
105 @Override
106 public void onChange(boolean selfChange) {
107 updateBatteryWarningLevels();
108 }
109 };
110 final ContentResolver resolver = mContext.getContentResolver();
111 resolver.registerContentObserver(Settings.Global.getUriFor(
112 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
113 false, obs, UserHandle.USER_ALL);
114 updateBatteryWarningLevels();
John Spurlock3332ba52014-03-10 17:44:07 -0400115 mReceiver.init();
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800116
Salvador Martineza6f7b252017-04-10 10:46:15 -0700117 // Check to see if we need to let the user know that the phone previously shut down due
118 // to the temperature being too high.
119 showThermalShutdownDialog();
120
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800121 initTemperatureWarning();
John Spurlock3332ba52014-03-10 17:44:07 -0400122 }
Dianne Hackborn14272302014-06-10 23:13:02 -0700123
Adam Lesinski1aab3fa2017-07-31 13:42:00 -0700124 @Override
125 protected void onConfigurationChanged(Configuration newConfig) {
126 final int mask = ActivityInfo.CONFIG_MCC | ActivityInfo.CONFIG_MNC;
127
128 // Safe to modify mLastConfiguration here as it's only updated by the main thread (here).
129 if ((mLastConfiguration.updateFrom(newConfig) & mask) != 0) {
130 mHandler.post(this::initTemperatureWarning);
131 }
132 }
133
Dianne Hackborn14272302014-06-10 23:13:02 -0700134 void updateBatteryWarningLevels() {
135 int critLevel = mContext.getResources().getInteger(
136 com.android.internal.R.integer.config_criticalBatteryWarningLevel);
137
138 final ContentResolver resolver = mContext.getContentResolver();
Makoto Onuki4a9036b2018-01-11 14:48:20 -0800139 final int defWarnLevel = mContext.getResources().getInteger(
Dianne Hackborn14272302014-06-10 23:13:02 -0700140 com.android.internal.R.integer.config_lowBatteryWarningLevel);
Makoto Onuki4a9036b2018-01-11 14:48:20 -0800141 final int lowPowerModeTriggerLevel = Settings.Global.getInt(resolver,
Dianne Hackborn14272302014-06-10 23:13:02 -0700142 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, defWarnLevel);
Makoto Onuki4a9036b2018-01-11 14:48:20 -0800143
144 // NOTE: Keep the logic in sync with BatteryService.
145 // TODO: Propagate this value from BatteryService to system UI, really.
146 int warnLevel = Math.min(defWarnLevel, lowPowerModeTriggerLevel);
147
Dianne Hackborn14272302014-06-10 23:13:02 -0700148 if (warnLevel == 0) {
149 warnLevel = defWarnLevel;
150 }
151 if (warnLevel < critLevel) {
152 warnLevel = critLevel;
153 }
154
155 mLowBatteryReminderLevels[0] = warnLevel;
156 mLowBatteryReminderLevels[1] = critLevel;
157 mLowBatteryAlertCloseLevel = mLowBatteryReminderLevels[0]
158 + mContext.getResources().getInteger(
159 com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
160 }
161
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700162 /**
163 * Buckets the battery level.
164 *
165 * The code in this function is a little weird because I couldn't comprehend
166 * the bucket going up when the battery level was going down. --joeo
167 *
168 * 1 means that the battery is "ok"
169 * 0 means that the battery is between "ok" and what we should warn about.
170 * less than 0 means that the battery is low
171 */
172 private int findBatteryLevelBucket(int level) {
173 if (level >= mLowBatteryAlertCloseLevel) {
174 return 1;
175 }
Dianne Hackborn14272302014-06-10 23:13:02 -0700176 if (level > mLowBatteryReminderLevels[0]) {
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700177 return 0;
178 }
179 final int N = mLowBatteryReminderLevels.length;
180 for (int i=N-1; i>=0; i--) {
181 if (level <= mLowBatteryReminderLevels[i]) {
182 return -1-i;
183 }
184 }
185 throw new RuntimeException("not possible!");
186 }
187
John Spurlock3332ba52014-03-10 17:44:07 -0400188 private final class Receiver extends BroadcastReceiver {
189
190 public void init() {
191 // Register for Intent broadcasts for...
192 IntentFilter filter = new IntentFilter();
193 filter.addAction(Intent.ACTION_BATTERY_CHANGED);
194 filter.addAction(Intent.ACTION_SCREEN_OFF);
195 filter.addAction(Intent.ACTION_SCREEN_ON);
John Spurlockecbc5e82014-10-22 09:05:51 -0400196 filter.addAction(Intent.ACTION_USER_SWITCHED);
John Spurlock3332ba52014-03-10 17:44:07 -0400197 mContext.registerReceiver(this, filter, null, mHandler);
John Spurlock3332ba52014-03-10 17:44:07 -0400198 }
199
Joe Onorato10523b4d2010-10-25 10:42:46 -0700200 @Override
201 public void onReceive(Context context, Intent intent) {
202 String action = intent.getAction();
203 if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700204 final int oldBatteryLevel = mBatteryLevel;
205 mBatteryLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 100);
206 final int oldBatteryStatus = mBatteryStatus;
207 mBatteryStatus = intent.getIntExtra(BatteryManager.EXTRA_STATUS,
208 BatteryManager.BATTERY_STATUS_UNKNOWN);
209 final int oldPlugType = mPlugType;
210 mPlugType = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 1);
211 final int oldInvalidCharger = mInvalidCharger;
212 mInvalidCharger = intent.getIntExtra(BatteryManager.EXTRA_INVALID_CHARGER, 0);
213
214 final boolean plugged = mPlugType != 0;
215 final boolean oldPlugged = oldPlugType != 0;
216
217 int oldBucket = findBatteryLevelBucket(oldBatteryLevel);
218 int bucket = findBatteryLevelBucket(mBatteryLevel);
219
Daniel Sandler71986622011-07-26 13:06:49 -0400220 if (DEBUG) {
Daniel Sandlerdea64622013-09-23 16:05:57 -0400221 Slog.d(TAG, "buckets ....." + mLowBatteryAlertCloseLevel
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700222 + " .. " + mLowBatteryReminderLevels[0]
223 + " .. " + mLowBatteryReminderLevels[1]);
Daniel Sandlerdea64622013-09-23 16:05:57 -0400224 Slog.d(TAG, "level " + oldBatteryLevel + " --> " + mBatteryLevel);
225 Slog.d(TAG, "status " + oldBatteryStatus + " --> " + mBatteryStatus);
226 Slog.d(TAG, "plugType " + oldPlugType + " --> " + mPlugType);
227 Slog.d(TAG, "invalidCharger " + oldInvalidCharger + " --> " + mInvalidCharger);
228 Slog.d(TAG, "bucket " + oldBucket + " --> " + bucket);
229 Slog.d(TAG, "plugged " + oldPlugged + " --> " + plugged);
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700230 }
231
John Spurlocked452c52014-03-06 12:02:31 -0500232 mWarnings.update(mBatteryLevel, bucket, mScreenOffTime);
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700233 if (oldInvalidCharger == 0 && mInvalidCharger != 0) {
Daniel Sandlerdea64622013-09-23 16:05:57 -0400234 Slog.d(TAG, "showing invalid charger warning");
John Spurlocked452c52014-03-06 12:02:31 -0500235 mWarnings.showInvalidChargerWarning();
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700236 return;
237 } else if (oldInvalidCharger != 0 && mInvalidCharger == 0) {
John Spurlocked452c52014-03-06 12:02:31 -0500238 mWarnings.dismissInvalidChargerWarning();
239 } else if (mWarnings.isInvalidChargerWarningShowing()) {
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700240 // if invalid charger is showing, don't show low battery
241 return;
242 }
243
Salvador Martinezf9e47502018-01-04 13:45:48 -0800244 // Show the correct version of low battery warning if needed
245 maybeShowBatteryWarning(plugged, oldPlugged, oldBucket, bucket);
Beverly334bc5f2017-07-31 10:37:17 -0400246
Daniel Sandlerdea64622013-09-23 16:05:57 -0400247 } else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
248 mScreenOffTime = SystemClock.elapsedRealtime();
249 } else if (Intent.ACTION_SCREEN_ON.equals(action)) {
250 mScreenOffTime = -1;
John Spurlockecbc5e82014-10-22 09:05:51 -0400251 } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
252 mWarnings.userSwitched();
Joe Onorato10523b4d2010-10-25 10:42:46 -0700253 } else {
Daniel Sandlerdea64622013-09-23 16:05:57 -0400254 Slog.w(TAG, "unknown intent: " + intent);
Joe Onorato10523b4d2010-10-25 10:42:46 -0700255 }
256 }
Salvador Martinezf9e47502018-01-04 13:45:48 -0800257 }
258
259 protected void maybeShowBatteryWarning(boolean plugged, boolean oldPlugged, int oldBucket,
260 int bucket) {
261 boolean isPowerSaver = mPowerManager.isPowerSaveMode();
262 // only play SFX when the dialog comes up or the bucket changes
263 final boolean playSound = bucket != oldBucket || oldPlugged;
264 long oldTimeRemaining = mTimeRemaining;
265 if (mEnhancedEstimates.isHybridNotificationEnabled()) {
266 final Estimate estimate = mEnhancedEstimates.getEstimate();
267 // Turbo is not always booted once SysUI is running so we have ot make sure we actually
268 // get data back
269 if (estimate != null) {
270 mTimeRemaining = estimate.estimateMillis;
271 mWarnings.updateEstimate(estimate);
272 }
273 }
274
275 if (shouldShowLowBatteryWarning(plugged, oldPlugged, oldBucket, bucket, oldTimeRemaining,
276 mTimeRemaining,
277 isPowerSaver, mBatteryStatus)) {
278 mWarnings.showLowBatteryWarning(playSound);
279 } else if (shouldDismissLowBatteryWarning(plugged, oldBucket, bucket, mTimeRemaining,
280 isPowerSaver)) {
281 mWarnings.dismissLowBatteryWarning();
282 } else {
283 mWarnings.updateLowBatteryWarning();
284 }
285 }
286
287 @VisibleForTesting
288 boolean shouldShowLowBatteryWarning(boolean plugged, boolean oldPlugged, int oldBucket,
289 int bucket, long oldTimeRemaining, long timeRemaining,
290 boolean isPowerSaver, int mBatteryStatus) {
291 return !plugged
292 && !isPowerSaver
293 && (((bucket < oldBucket || oldPlugged) && bucket < 0)
294 || (mEnhancedEstimates.isHybridNotificationEnabled()
295 && timeRemaining < THREE_HOURS_IN_MILLIS
296 && isHourLess(oldTimeRemaining, timeRemaining)))
297 && mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN;
298 }
299
300 private boolean isHourLess(long oldTimeRemaining, long timeRemaining) {
301 final long dif = oldTimeRemaining - timeRemaining;
302 return dif >= TimeUnit.HOURS.toMillis(1);
303 }
304
305 @VisibleForTesting
306 boolean shouldDismissLowBatteryWarning(boolean plugged, int oldBucket, int bucket,
307 long timeRemaining, boolean isPowerSaver) {
308 final boolean hybridWouldDismiss = mEnhancedEstimates.isHybridNotificationEnabled()
309 && timeRemaining > THREE_HOURS_IN_MILLIS;
310 final boolean standardWouldDismiss = (bucket > oldBucket && bucket > 0);
311 return isPowerSaver
312 || plugged
313 || (standardWouldDismiss && (!mEnhancedEstimates.isHybridNotificationEnabled()
314 || hybridWouldDismiss));
315 }
Joe Onorato10523b4d2010-10-25 10:42:46 -0700316
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800317 private void initTemperatureWarning() {
Andrew Sappersteine3352562017-01-20 15:41:03 -0800318 ContentResolver resolver = mContext.getContentResolver();
319 Resources resources = mContext.getResources();
320 if (Settings.Global.getInt(resolver, Settings.Global.SHOW_TEMPERATURE_WARNING,
321 resources.getInteger(R.integer.config_showTemperatureWarning)) == 0) {
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800322 return;
323 }
324
Andrew Sappersteina6ed7f82017-02-01 17:13:08 -0800325 mThresholdTemp = Settings.Global.getFloat(resolver, Settings.Global.WARNING_TEMPERATURE,
Andrew Sappersteine3352562017-01-20 15:41:03 -0800326 resources.getInteger(R.integer.config_warningTemperature));
Andrew Sapperstein75184712017-01-05 16:45:37 -0800327
Andrew Sappersteina6ed7f82017-02-01 17:13:08 -0800328 if (mThresholdTemp < 0f) {
Todd Poynorfb95e122017-10-04 13:00:32 -0700329 // Get the shutdown temperature, adjust for warning tolerance.
Andrew Sapperstein75184712017-01-05 16:45:37 -0800330 float[] throttlingTemps = mHardwarePropertiesManager.getDeviceTemperatures(
331 HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN,
Jason Monkd819c312017-08-11 12:53:36 -0400332 HardwarePropertiesManager.TEMPERATURE_SHUTDOWN);
Andrew Sapperstein75184712017-01-05 16:45:37 -0800333 if (throttlingTemps == null
334 || throttlingTemps.length == 0
335 || throttlingTemps[0] == HardwarePropertiesManager.UNDEFINED_TEMPERATURE) {
336 return;
337 }
Jason Monkd819c312017-08-11 12:53:36 -0400338 mThresholdTemp = throttlingTemps[0] -
339 resources.getInteger(R.integer.config_warningTemperatureTolerance);
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800340 }
Adam Lesinski1aab3fa2017-07-31 13:42:00 -0700341
Todd Poynorfb95e122017-10-04 13:00:32 -0700342 if (mThermalService == null) {
343 // Enable push notifications of throttling from vendor thermal
344 // management subsystem via thermalservice, in addition to our
345 // usual polling, to react to temperature jumps more quickly.
346 IBinder b = ServiceManager.getService("thermalservice");
347
348 if (b != null) {
349 mThermalService = IThermalService.Stub.asInterface(b);
350 try {
351 mThermalService.registerThermalEventListener(
352 new ThermalEventListener());
353 } catch (RemoteException e) {
354 // Should never happen.
355 }
356 } else {
357 Slog.w(TAG, "cannot find thermalservice, no throttling push notifications");
358 }
359 }
360
Andrew Sappersteina6ed7f82017-02-01 17:13:08 -0800361 setNextLogTime();
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800362
Adam Lesinski1aab3fa2017-07-31 13:42:00 -0700363 // This initialization method may be called on a configuration change. Only one set of
364 // ongoing callbacks should be occurring, so remove any now. updateTemperatureWarning will
365 // schedule an ongoing callback.
366 mHandler.removeCallbacks(mUpdateTempCallback);
367
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800368 // We have passed all of the checks, start checking the temp
369 updateTemperatureWarning();
370 }
371
Salvador Martineza6f7b252017-04-10 10:46:15 -0700372 private void showThermalShutdownDialog() {
373 if (mPowerManager.getLastShutdownReason()
374 == PowerManager.SHUTDOWN_REASON_THERMAL_SHUTDOWN) {
375 mWarnings.showThermalShutdownWarning();
376 }
377 }
378
Jason Monkd819c312017-08-11 12:53:36 -0400379 @VisibleForTesting
380 protected void updateTemperatureWarning() {
Andrew Sappersteina6ed7f82017-02-01 17:13:08 -0800381 float[] temps = mHardwarePropertiesManager.getDeviceTemperatures(
382 HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN,
383 HardwarePropertiesManager.TEMPERATURE_CURRENT);
384 if (temps.length != 0) {
385 float temp = temps[0];
386 mRecentTemps[mNumTemps++] = temp;
387
388 StatusBar statusBar = getComponent(StatusBar.class);
389 if (statusBar != null && !statusBar.isDeviceInVrMode()
390 && temp >= mThresholdTemp) {
391 logAtTemperatureThreshold(temp);
Salvador Martineza6f7b252017-04-10 10:46:15 -0700392 mWarnings.showHighTemperatureWarning();
Andrew Sapperstein65d8a5f2016-12-19 14:36:33 -0800393 } else {
Salvador Martineza6f7b252017-04-10 10:46:15 -0700394 mWarnings.dismissHighTemperatureWarning();
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800395 }
396 }
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800397
Andrew Sappersteina6ed7f82017-02-01 17:13:08 -0800398 logTemperatureStats();
399
Adam Lesinski1aab3fa2017-07-31 13:42:00 -0700400 mHandler.postDelayed(mUpdateTempCallback, TEMPERATURE_INTERVAL);
Andrew Sappersteinb7caf1d2016-12-14 15:39:20 -0800401 }
402
Andrew Sappersteina6ed7f82017-02-01 17:13:08 -0800403 private void logAtTemperatureThreshold(float temp) {
404 StringBuilder sb = new StringBuilder();
405 sb.append("currentTemp=").append(temp)
406 .append(",thresholdTemp=").append(mThresholdTemp)
407 .append(",batteryStatus=").append(mBatteryStatus)
408 .append(",recentTemps=");
409 for (int i = 0; i < mNumTemps; i++) {
410 sb.append(mRecentTemps[i]).append(',');
411 }
412 Slog.i(TAG, sb.toString());
413 }
414
415 /**
416 * Calculates and logs min, max, and average
417 * {@link HardwarePropertiesManager#DEVICE_TEMPERATURE_SKIN} over the past
418 * {@link #TEMPERATURE_LOGGING_INTERVAL}.
419 */
420 private void logTemperatureStats() {
421 if (mNextLogTime > System.currentTimeMillis() && mNumTemps != MAX_RECENT_TEMPS) {
422 return;
423 }
424
425 if (mNumTemps > 0) {
426 float sum = mRecentTemps[0], min = mRecentTemps[0], max = mRecentTemps[0];
427 for (int i = 1; i < mNumTemps; i++) {
428 float temp = mRecentTemps[i];
429 sum += temp;
430 if (temp > max) {
431 max = temp;
432 }
433 if (temp < min) {
434 min = temp;
435 }
436 }
437
438 float avg = sum / mNumTemps;
439 Slog.i(TAG, "avg=" + avg + ",min=" + min + ",max=" + max);
440 MetricsLogger.histogram(mContext, "device_skin_temp_avg", (int) avg);
441 MetricsLogger.histogram(mContext, "device_skin_temp_min", (int) min);
442 MetricsLogger.histogram(mContext, "device_skin_temp_max", (int) max);
443 }
444 setNextLogTime();
445 mNumTemps = 0;
446 }
447
448 private void setNextLogTime() {
449 mNextLogTime = System.currentTimeMillis() + TEMPERATURE_LOGGING_INTERVAL;
450 }
451
Joe Onorato10523b4d2010-10-25 10:42:46 -0700452 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700453 pw.print("mLowBatteryAlertCloseLevel=");
454 pw.println(mLowBatteryAlertCloseLevel);
455 pw.print("mLowBatteryReminderLevels=");
456 pw.println(Arrays.toString(mLowBatteryReminderLevels));
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700457 pw.print("mBatteryLevel=");
458 pw.println(Integer.toString(mBatteryLevel));
459 pw.print("mBatteryStatus=");
460 pw.println(Integer.toString(mBatteryStatus));
461 pw.print("mPlugType=");
462 pw.println(Integer.toString(mPlugType));
463 pw.print("mInvalidCharger=");
464 pw.println(Integer.toString(mInvalidCharger));
Daniel Sandlerdea64622013-09-23 16:05:57 -0400465 pw.print("mScreenOffTime=");
466 pw.print(mScreenOffTime);
467 if (mScreenOffTime >= 0) {
468 pw.print(" (");
469 pw.print(SystemClock.elapsedRealtime() - mScreenOffTime);
470 pw.print(" ago)");
471 }
472 pw.println();
473 pw.print("soundTimeout=");
474 pw.println(Settings.Global.getInt(mContext.getContentResolver(),
475 Settings.Global.LOW_BATTERY_SOUND_TIMEOUT, 0));
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700476 pw.print("bucket: ");
477 pw.println(Integer.toString(findBatteryLevelBucket(mBatteryLevel)));
Andrew Sappersteina6ed7f82017-02-01 17:13:08 -0800478 pw.print("mThresholdTemp=");
479 pw.println(Float.toString(mThresholdTemp));
480 pw.print("mNextLogTime=");
481 pw.println(Long.toString(mNextLogTime));
John Spurlocked452c52014-03-06 12:02:31 -0500482 mWarnings.dump(pw);
483 }
484
485 public interface WarningsUI {
486 void update(int batteryLevel, int bucket, long screenOffTime);
Salvador Martinezf9e47502018-01-04 13:45:48 -0800487 void updateEstimate(Estimate estimate);
John Spurlocked452c52014-03-06 12:02:31 -0500488 void dismissLowBatteryWarning();
489 void showLowBatteryWarning(boolean playSound);
490 void dismissInvalidChargerWarning();
491 void showInvalidChargerWarning();
492 void updateLowBatteryWarning();
493 boolean isInvalidChargerWarningShowing();
Salvador Martineza6f7b252017-04-10 10:46:15 -0700494 void dismissHighTemperatureWarning();
495 void showHighTemperatureWarning();
496 void showThermalShutdownWarning();
John Spurlocked452c52014-03-06 12:02:31 -0500497 void dump(PrintWriter pw);
John Spurlockecbc5e82014-10-22 09:05:51 -0400498 void userSwitched();
Joe Onorato10523b4d2010-10-25 10:42:46 -0700499 }
Joe Onorato10523b4d2010-10-25 10:42:46 -0700500
Todd Poynorfb95e122017-10-04 13:00:32 -0700501 // Thermal event received from vendor thermal management subsystem
502 private final class ThermalEventListener extends IThermalEventListener.Stub {
503 @Override public void notifyThrottling(boolean isThrottling, Temperature temp) {
504 // Trigger an update of the temperature warning. Only one
505 // callback can be enabled at a time, so remove any existing
506 // callback; updateTemperatureWarning will schedule another one.
507 mHandler.removeCallbacks(mUpdateTempCallback);
508 updateTemperatureWarning();
509 }
510 }
511}