1 /* 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 17 package com.android.systemui.power; 18 19 import android.content.BroadcastReceiver; 20 import android.content.ContentResolver; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.IntentFilter; 24 import android.content.pm.ActivityInfo; 25 import android.content.res.Configuration; 26 import android.content.res.Resources; 27 import android.database.ContentObserver; 28 import android.os.BatteryManager; 29 import android.os.Handler; 30 import android.os.HardwarePropertiesManager; 31 import android.os.IBinder; 32 import android.os.IThermalEventListener; 33 import android.os.IThermalService; 34 import android.os.PowerManager; 35 import android.os.RemoteException; 36 import android.os.ServiceManager; 37 import android.os.SystemClock; 38 import android.os.Temperature; 39 import android.os.UserHandle; 40 import android.provider.Settings; 41 import android.text.format.DateUtils; 42 import android.util.Log; 43 import android.util.Slog; 44 45 import com.android.internal.annotations.VisibleForTesting; 46 import com.android.internal.logging.MetricsLogger; 47 import com.android.settingslib.utils.ThreadUtils; 48 import com.android.systemui.Dependency; 49 import com.android.systemui.R; 50 import com.android.systemui.SystemUI; 51 import com.android.systemui.statusbar.phone.StatusBar; 52 53 import java.io.FileDescriptor; 54 import java.io.PrintWriter; 55 import java.time.Duration; 56 import java.util.Arrays; 57 58 public class PowerUI extends SystemUI { 59 static final String TAG = "PowerUI"; 60 static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 61 private static final long TEMPERATURE_INTERVAL = 30 * DateUtils.SECOND_IN_MILLIS; 62 private static final long TEMPERATURE_LOGGING_INTERVAL = DateUtils.HOUR_IN_MILLIS; 63 private static final int MAX_RECENT_TEMPS = 125; // TEMPERATURE_LOGGING_INTERVAL plus a buffer 64 static final long THREE_HOURS_IN_MILLIS = DateUtils.HOUR_IN_MILLIS * 3; 65 private static final int CHARGE_CYCLE_PERCENT_RESET = 45; 66 private static final long SIX_HOURS_MILLIS = Duration.ofHours(6).toMillis(); 67 68 private final Handler mHandler = new Handler(); 69 @VisibleForTesting 70 final Receiver mReceiver = new Receiver(); 71 72 private PowerManager mPowerManager; 73 private HardwarePropertiesManager mHardwarePropertiesManager; 74 private WarningsUI mWarnings; 75 private final Configuration mLastConfiguration = new Configuration(); 76 private long mTimeRemaining = Long.MAX_VALUE; 77 private int mPlugType = 0; 78 private int mInvalidCharger = 0; 79 private EnhancedEstimates mEnhancedEstimates; 80 private boolean mLowWarningShownThisChargeCycle; 81 private boolean mSevereWarningShownThisChargeCycle; 82 83 private int mLowBatteryAlertCloseLevel; 84 private final int[] mLowBatteryReminderLevels = new int[2]; 85 86 private long mScreenOffTime = -1; 87 88 private float mThresholdTemp; 89 private float[] mRecentTemps = new float[MAX_RECENT_TEMPS]; 90 private int mNumTemps; 91 private long mNextLogTime; 92 private IThermalService mThermalService; 93 94 @VisibleForTesting int mBatteryLevel = 100; 95 @VisibleForTesting int mBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN; 96 97 // by using the same instance (method references are not guaranteed to be the same object 98 // We create a method reference here so that we are guaranteed that we can remove a callback 99 // each time they are created). 100 private final Runnable mUpdateTempCallback = this::updateTemperatureWarning; 101 start()102 public void start() { 103 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 104 mHardwarePropertiesManager = (HardwarePropertiesManager) 105 mContext.getSystemService(Context.HARDWARE_PROPERTIES_SERVICE); 106 mScreenOffTime = mPowerManager.isScreenOn() ? -1 : SystemClock.elapsedRealtime(); 107 mWarnings = Dependency.get(WarningsUI.class); 108 mEnhancedEstimates = Dependency.get(EnhancedEstimates.class); 109 mLastConfiguration.setTo(mContext.getResources().getConfiguration()); 110 111 ContentObserver obs = new ContentObserver(mHandler) { 112 @Override 113 public void onChange(boolean selfChange) { 114 updateBatteryWarningLevels(); 115 } 116 }; 117 final ContentResolver resolver = mContext.getContentResolver(); 118 resolver.registerContentObserver(Settings.Global.getUriFor( 119 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL), 120 false, obs, UserHandle.USER_ALL); 121 updateBatteryWarningLevels(); 122 mReceiver.init(); 123 124 // Check to see if we need to let the user know that the phone previously shut down due 125 // to the temperature being too high. 126 showThermalShutdownDialog(); 127 128 initTemperatureWarning(); 129 } 130 131 @Override onConfigurationChanged(Configuration newConfig)132 protected void onConfigurationChanged(Configuration newConfig) { 133 final int mask = ActivityInfo.CONFIG_MCC | ActivityInfo.CONFIG_MNC; 134 135 // Safe to modify mLastConfiguration here as it's only updated by the main thread (here). 136 if ((mLastConfiguration.updateFrom(newConfig) & mask) != 0) { 137 mHandler.post(this::initTemperatureWarning); 138 } 139 } 140 updateBatteryWarningLevels()141 void updateBatteryWarningLevels() { 142 int critLevel = mContext.getResources().getInteger( 143 com.android.internal.R.integer.config_criticalBatteryWarningLevel); 144 int warnLevel = mContext.getResources().getInteger( 145 com.android.internal.R.integer.config_lowBatteryWarningLevel); 146 147 if (warnLevel < critLevel) { 148 warnLevel = critLevel; 149 } 150 151 mLowBatteryReminderLevels[0] = warnLevel; 152 mLowBatteryReminderLevels[1] = critLevel; 153 mLowBatteryAlertCloseLevel = mLowBatteryReminderLevels[0] 154 + mContext.getResources().getInteger( 155 com.android.internal.R.integer.config_lowBatteryCloseWarningBump); 156 } 157 158 /** 159 * Buckets the battery level. 160 * 161 * The code in this function is a little weird because I couldn't comprehend 162 * the bucket going up when the battery level was going down. --joeo 163 * 164 * 1 means that the battery is "ok" 165 * 0 means that the battery is between "ok" and what we should warn about. 166 * less than 0 means that the battery is low 167 */ findBatteryLevelBucket(int level)168 private int findBatteryLevelBucket(int level) { 169 if (level >= mLowBatteryAlertCloseLevel) { 170 return 1; 171 } 172 if (level > mLowBatteryReminderLevels[0]) { 173 return 0; 174 } 175 final int N = mLowBatteryReminderLevels.length; 176 for (int i=N-1; i>=0; i--) { 177 if (level <= mLowBatteryReminderLevels[i]) { 178 return -1-i; 179 } 180 } 181 throw new RuntimeException("not possible!"); 182 } 183 184 @VisibleForTesting 185 final class Receiver extends BroadcastReceiver { 186 init()187 public void init() { 188 // Register for Intent broadcasts for... 189 IntentFilter filter = new IntentFilter(); 190 filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED); 191 filter.addAction(Intent.ACTION_BATTERY_CHANGED); 192 filter.addAction(Intent.ACTION_SCREEN_OFF); 193 filter.addAction(Intent.ACTION_SCREEN_ON); 194 filter.addAction(Intent.ACTION_USER_SWITCHED); 195 mContext.registerReceiver(this, filter, null, mHandler); 196 } 197 198 @Override onReceive(Context context, Intent intent)199 public void onReceive(Context context, Intent intent) { 200 String action = intent.getAction(); 201 if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)) { 202 ThreadUtils.postOnBackgroundThread(() -> { 203 if (mPowerManager.isPowerSaveMode()) { 204 mWarnings.dismissLowBatteryWarning(); 205 } 206 }); 207 } else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) { 208 final int oldBatteryLevel = mBatteryLevel; 209 mBatteryLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 100); 210 final int oldBatteryStatus = mBatteryStatus; 211 mBatteryStatus = intent.getIntExtra(BatteryManager.EXTRA_STATUS, 212 BatteryManager.BATTERY_STATUS_UNKNOWN); 213 final int oldPlugType = mPlugType; 214 mPlugType = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 1); 215 final int oldInvalidCharger = mInvalidCharger; 216 mInvalidCharger = intent.getIntExtra(BatteryManager.EXTRA_INVALID_CHARGER, 0); 217 218 final boolean plugged = mPlugType != 0; 219 final boolean oldPlugged = oldPlugType != 0; 220 221 int oldBucket = findBatteryLevelBucket(oldBatteryLevel); 222 int bucket = findBatteryLevelBucket(mBatteryLevel); 223 224 if (DEBUG) { 225 Slog.d(TAG, "buckets ....." + mLowBatteryAlertCloseLevel 226 + " .. " + mLowBatteryReminderLevels[0] 227 + " .. " + mLowBatteryReminderLevels[1]); 228 Slog.d(TAG, "level " + oldBatteryLevel + " --> " + mBatteryLevel); 229 Slog.d(TAG, "status " + oldBatteryStatus + " --> " + mBatteryStatus); 230 Slog.d(TAG, "plugType " + oldPlugType + " --> " + mPlugType); 231 Slog.d(TAG, "invalidCharger " + oldInvalidCharger + " --> " + mInvalidCharger); 232 Slog.d(TAG, "bucket " + oldBucket + " --> " + bucket); 233 Slog.d(TAG, "plugged " + oldPlugged + " --> " + plugged); 234 } 235 236 mWarnings.update(mBatteryLevel, bucket, mScreenOffTime); 237 if (oldInvalidCharger == 0 && mInvalidCharger != 0) { 238 Slog.d(TAG, "showing invalid charger warning"); 239 mWarnings.showInvalidChargerWarning(); 240 return; 241 } else if (oldInvalidCharger != 0 && mInvalidCharger == 0) { 242 mWarnings.dismissInvalidChargerWarning(); 243 } else if (mWarnings.isInvalidChargerWarningShowing()) { 244 // if invalid charger is showing, don't show low battery 245 return; 246 } 247 248 // Show the correct version of low battery warning if needed 249 ThreadUtils.postOnBackgroundThread(() -> { 250 maybeShowBatteryWarning(plugged, oldPlugged, oldBucket, bucket); 251 }); 252 253 } else if (Intent.ACTION_SCREEN_OFF.equals(action)) { 254 mScreenOffTime = SystemClock.elapsedRealtime(); 255 } else if (Intent.ACTION_SCREEN_ON.equals(action)) { 256 mScreenOffTime = -1; 257 } else if (Intent.ACTION_USER_SWITCHED.equals(action)) { 258 mWarnings.userSwitched(); 259 } else { 260 Slog.w(TAG, "unknown intent: " + intent); 261 } 262 } 263 } 264 maybeShowBatteryWarning(boolean plugged, boolean oldPlugged, int oldBucket, int bucket)265 protected void maybeShowBatteryWarning(boolean plugged, boolean oldPlugged, int oldBucket, 266 int bucket) { 267 boolean isPowerSaver = mPowerManager.isPowerSaveMode(); 268 // only play SFX when the dialog comes up or the bucket changes 269 final boolean playSound = bucket != oldBucket || oldPlugged; 270 final boolean hybridEnabled = mEnhancedEstimates.isHybridNotificationEnabled(); 271 if (hybridEnabled) { 272 final Estimate estimate = mEnhancedEstimates.getEstimate(); 273 // Turbo is not always booted once SysUI is running so we have ot make sure we actually 274 // get data back 275 if (estimate != null) { 276 mTimeRemaining = estimate.estimateMillis; 277 mWarnings.updateEstimate(estimate); 278 mWarnings.updateThresholds(mEnhancedEstimates.getLowWarningThreshold(), 279 mEnhancedEstimates.getSevereWarningThreshold()); 280 281 // if we are now over 45% battery & 6 hours remaining we can trigger hybrid 282 // notification again 283 if (mBatteryLevel >= CHARGE_CYCLE_PERCENT_RESET 284 && mTimeRemaining > SIX_HOURS_MILLIS) { 285 mLowWarningShownThisChargeCycle = false; 286 mSevereWarningShownThisChargeCycle = false; 287 } 288 } 289 } 290 291 if (shouldShowLowBatteryWarning(plugged, oldPlugged, oldBucket, bucket, 292 mTimeRemaining, isPowerSaver, mBatteryStatus)) { 293 mWarnings.showLowBatteryWarning(playSound); 294 295 // mark if we've already shown a warning this cycle. This will prevent the notification 296 // trigger from spamming users by only showing low/critical warnings once per cycle 297 if (hybridEnabled) { 298 if (mTimeRemaining < mEnhancedEstimates.getSevereWarningThreshold() 299 || mBatteryLevel < mLowBatteryReminderLevels[1]) { 300 mSevereWarningShownThisChargeCycle = true; 301 } else { 302 mLowWarningShownThisChargeCycle = true; 303 } 304 } 305 } else if (shouldDismissLowBatteryWarning(plugged, oldBucket, bucket, mTimeRemaining, 306 isPowerSaver)) { 307 mWarnings.dismissLowBatteryWarning(); 308 } else { 309 mWarnings.updateLowBatteryWarning(); 310 } 311 } 312 313 @VisibleForTesting shouldShowLowBatteryWarning(boolean plugged, boolean oldPlugged, int oldBucket, int bucket, long timeRemaining, boolean isPowerSaver, int batteryStatus)314 boolean shouldShowLowBatteryWarning(boolean plugged, boolean oldPlugged, int oldBucket, 315 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 321 return !plugged 322 && !isPowerSaver 323 && (((bucket < oldBucket || oldPlugged) && bucket < 0)) 324 && batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN; 325 } 326 327 @VisibleForTesting shouldDismissLowBatteryWarning(boolean plugged, int oldBucket, int bucket, long timeRemaining, boolean isPowerSaver)328 boolean shouldDismissLowBatteryWarning(boolean plugged, int oldBucket, int bucket, 329 long timeRemaining, boolean isPowerSaver) { 330 final boolean hybridWouldDismiss = mEnhancedEstimates.isHybridNotificationEnabled() 331 && timeRemaining > mEnhancedEstimates.getLowWarningThreshold(); 332 final boolean standardWouldDismiss = (bucket > oldBucket && bucket > 0); 333 return isPowerSaver 334 || plugged 335 || (standardWouldDismiss && (!mEnhancedEstimates.isHybridNotificationEnabled() 336 || hybridWouldDismiss)); 337 } 338 isEnhancedTrigger(boolean plugged, long timeRemaining, boolean isPowerSaver, int batteryStatus)339 private boolean isEnhancedTrigger(boolean plugged, long timeRemaining, boolean isPowerSaver, 340 int batteryStatus) { 341 if (plugged || isPowerSaver || batteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) { 342 return false; 343 } 344 int warnLevel = mLowBatteryReminderLevels[0]; 345 int critLevel = mLowBatteryReminderLevels[1]; 346 347 // Only show the low warning once per charge cycle 348 final boolean canShowWarning = !mLowWarningShownThisChargeCycle 349 && (timeRemaining < mEnhancedEstimates.getLowWarningThreshold() 350 || mBatteryLevel <= warnLevel); 351 352 // Only show the severe warning once per charge cycle 353 final boolean canShowSevereWarning = !mSevereWarningShownThisChargeCycle 354 && (timeRemaining < mEnhancedEstimates.getSevereWarningThreshold() 355 || mBatteryLevel <= critLevel); 356 357 return canShowWarning || canShowSevereWarning; 358 } 359 initTemperatureWarning()360 private void initTemperatureWarning() { 361 ContentResolver resolver = mContext.getContentResolver(); 362 Resources resources = mContext.getResources(); 363 if (Settings.Global.getInt(resolver, Settings.Global.SHOW_TEMPERATURE_WARNING, 364 resources.getInteger(R.integer.config_showTemperatureWarning)) == 0) { 365 return; 366 } 367 368 mThresholdTemp = Settings.Global.getFloat(resolver, Settings.Global.WARNING_TEMPERATURE, 369 resources.getInteger(R.integer.config_warningTemperature)); 370 371 if (mThresholdTemp < 0f) { 372 // Get the shutdown temperature, adjust for warning tolerance. 373 float[] throttlingTemps = mHardwarePropertiesManager.getDeviceTemperatures( 374 HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN, 375 HardwarePropertiesManager.TEMPERATURE_SHUTDOWN); 376 if (throttlingTemps == null 377 || throttlingTemps.length == 0 378 || throttlingTemps[0] == HardwarePropertiesManager.UNDEFINED_TEMPERATURE) { 379 return; 380 } 381 mThresholdTemp = throttlingTemps[0] - 382 resources.getInteger(R.integer.config_warningTemperatureTolerance); 383 } 384 385 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. 389 IBinder b = ServiceManager.getService("thermalservice"); 390 391 if (b != null) { 392 mThermalService = IThermalService.Stub.asInterface(b); 393 try { 394 mThermalService.registerThermalEventListener( 395 new ThermalEventListener()); 396 } catch (RemoteException e) { 397 // Should never happen. 398 } 399 } else { 400 Slog.w(TAG, "cannot find thermalservice, no throttling push notifications"); 401 } 402 } 403 404 setNextLogTime(); 405 406 // This initialization method may be called on a configuration change. Only one set of 407 // ongoing callbacks should be occurring, so remove any now. updateTemperatureWarning will 408 // schedule an ongoing callback. 409 mHandler.removeCallbacks(mUpdateTempCallback); 410 411 // We have passed all of the checks, start checking the temp 412 updateTemperatureWarning(); 413 } 414 showThermalShutdownDialog()415 private void showThermalShutdownDialog() { 416 if (mPowerManager.getLastShutdownReason() 417 == PowerManager.SHUTDOWN_REASON_THERMAL_SHUTDOWN) { 418 mWarnings.showThermalShutdownWarning(); 419 } 420 } 421 422 @VisibleForTesting updateTemperatureWarning()423 protected void updateTemperatureWarning() { 424 float[] temps = mHardwarePropertiesManager.getDeviceTemperatures( 425 HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN, 426 HardwarePropertiesManager.TEMPERATURE_CURRENT); 427 if (temps.length != 0) { 428 float temp = temps[0]; 429 mRecentTemps[mNumTemps++] = temp; 430 431 StatusBar statusBar = getComponent(StatusBar.class); 432 if (statusBar != null && !statusBar.isDeviceInVrMode() 433 && temp >= mThresholdTemp) { 434 logAtTemperatureThreshold(temp); 435 mWarnings.showHighTemperatureWarning(); 436 } else { 437 mWarnings.dismissHighTemperatureWarning(); 438 } 439 } 440 441 logTemperatureStats(); 442 443 mHandler.postDelayed(mUpdateTempCallback, TEMPERATURE_INTERVAL); 444 } 445 logAtTemperatureThreshold(float temp)446 private void logAtTemperatureThreshold(float temp) { 447 StringBuilder sb = new StringBuilder(); 448 sb.append("currentTemp=").append(temp) 449 .append(",thresholdTemp=").append(mThresholdTemp) 450 .append(",batteryStatus=").append(mBatteryStatus) 451 .append(",recentTemps="); 452 for (int i = 0; i < mNumTemps; i++) { 453 sb.append(mRecentTemps[i]).append(','); 454 } 455 Slog.i(TAG, sb.toString()); 456 } 457 458 /** 459 * Calculates and logs min, max, and average 460 * {@link HardwarePropertiesManager#DEVICE_TEMPERATURE_SKIN} over the past 461 * {@link #TEMPERATURE_LOGGING_INTERVAL}. 462 */ logTemperatureStats()463 private void logTemperatureStats() { 464 if (mNextLogTime > System.currentTimeMillis() && mNumTemps != MAX_RECENT_TEMPS) { 465 return; 466 } 467 468 if (mNumTemps > 0) { 469 float sum = mRecentTemps[0], min = mRecentTemps[0], max = mRecentTemps[0]; 470 for (int i = 1; i < mNumTemps; i++) { 471 float temp = mRecentTemps[i]; 472 sum += temp; 473 if (temp > max) { 474 max = temp; 475 } 476 if (temp < min) { 477 min = temp; 478 } 479 } 480 481 float avg = sum / mNumTemps; 482 Slog.i(TAG, "avg=" + avg + ",min=" + min + ",max=" + max); 483 MetricsLogger.histogram(mContext, "device_skin_temp_avg", (int) avg); 484 MetricsLogger.histogram(mContext, "device_skin_temp_min", (int) min); 485 MetricsLogger.histogram(mContext, "device_skin_temp_max", (int) max); 486 } 487 setNextLogTime(); 488 mNumTemps = 0; 489 } 490 setNextLogTime()491 private void setNextLogTime() { 492 mNextLogTime = System.currentTimeMillis() + TEMPERATURE_LOGGING_INTERVAL; 493 } 494 dump(FileDescriptor fd, PrintWriter pw, String[] args)495 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 496 pw.print("mLowBatteryAlertCloseLevel="); 497 pw.println(mLowBatteryAlertCloseLevel); 498 pw.print("mLowBatteryReminderLevels="); 499 pw.println(Arrays.toString(mLowBatteryReminderLevels)); 500 pw.print("mBatteryLevel="); 501 pw.println(Integer.toString(mBatteryLevel)); 502 pw.print("mBatteryStatus="); 503 pw.println(Integer.toString(mBatteryStatus)); 504 pw.print("mPlugType="); 505 pw.println(Integer.toString(mPlugType)); 506 pw.print("mInvalidCharger="); 507 pw.println(Integer.toString(mInvalidCharger)); 508 pw.print("mScreenOffTime="); 509 pw.print(mScreenOffTime); 510 if (mScreenOffTime >= 0) { 511 pw.print(" ("); 512 pw.print(SystemClock.elapsedRealtime() - mScreenOffTime); 513 pw.print(" ago)"); 514 } 515 pw.println(); 516 pw.print("soundTimeout="); 517 pw.println(Settings.Global.getInt(mContext.getContentResolver(), 518 Settings.Global.LOW_BATTERY_SOUND_TIMEOUT, 0)); 519 pw.print("bucket: "); 520 pw.println(Integer.toString(findBatteryLevelBucket(mBatteryLevel))); 521 pw.print("mThresholdTemp="); 522 pw.println(Float.toString(mThresholdTemp)); 523 pw.print("mNextLogTime="); 524 pw.println(Long.toString(mNextLogTime)); 525 mWarnings.dump(pw); 526 } 527 528 public interface WarningsUI { update(int batteryLevel, int bucket, long screenOffTime)529 void update(int batteryLevel, int bucket, long screenOffTime); updateEstimate(Estimate estimate)530 void updateEstimate(Estimate estimate); updateThresholds(long lowThreshold, long severeThreshold)531 void updateThresholds(long lowThreshold, long severeThreshold); dismissLowBatteryWarning()532 void dismissLowBatteryWarning(); showLowBatteryWarning(boolean playSound)533 void showLowBatteryWarning(boolean playSound); dismissInvalidChargerWarning()534 void dismissInvalidChargerWarning(); showInvalidChargerWarning()535 void showInvalidChargerWarning(); updateLowBatteryWarning()536 void updateLowBatteryWarning(); isInvalidChargerWarningShowing()537 boolean isInvalidChargerWarningShowing(); dismissHighTemperatureWarning()538 void dismissHighTemperatureWarning(); showHighTemperatureWarning()539 void showHighTemperatureWarning(); showThermalShutdownWarning()540 void showThermalShutdownWarning(); dump(PrintWriter pw)541 void dump(PrintWriter pw); userSwitched()542 void userSwitched(); 543 } 544 545 // Thermal event received from vendor thermal management subsystem 546 private final class ThermalEventListener extends IThermalEventListener.Stub { notifyThrottling(boolean isThrottling, Temperature temp)547 @Override public void notifyThrottling(boolean isThrottling, Temperature temp) { 548 // Trigger an update of the temperature warning. Only one 549 // callback can be enabled at a time, so remove any existing 550 // callback; updateTemperatureWarning will schedule another one. 551 mHandler.removeCallbacks(mUpdateTempCallback); 552 updateTemperatureWarning(); 553 } 554 } 555 } 556