PowerUI
powerUI是SystemUI显示电池相关信息的模块,包括低电量提醒,危急电量关机提醒,高温关机提醒,省电模式等的功能。
在powerUI.java 中主要是两个函数start()和onReveice()
启动流程
SystemUI启动时会加载众多功能模块,其中就包含着PowerUI,会直接调用\
PowerUI.start()
start() 函数是在PowerUI 中最先触发的方法。在方法内进行了一些赋值操作,及注册对电量变化和屏幕开闭状态的广播监听
1)实例化PowerManager,因为是处理和Power相关的业务,必须实例化PowerManager.
2)初始化关屏时间,关屏时间会持续刷新。
3)实例化PowerNotificationWarnings,Power相关的事件会通过Notification方式进行处理。
4)监控电池电量,在电量不足是给出警告和提示。
5)更新电池电量等级。
public void start() {
//获取PowerManager 用于获取电池的相关信息
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
//获取自启动以来的毫秒数
mScreenOffTime = mPowerManager.isScreenOn() ? -1 : SystemClock.elapsedRealtime();
mWarnings = Dependency.get(WarningsUI.class);
//和混合通知相关,相关功能平台默认是关闭的,我们暂时也就不关注了
mEnhancedEstimates = Dependency.get(EnhancedEstimates.class);
mLastConfiguration.setTo(mContext.getResources().getConfiguration());
// 监测低电量阀值的改变
ContentObserver obs = new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
updateBatteryWarningLevels();
}
};
final ContentResolver resolver = mContext.getContentResolver();
resolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
false, obs, UserHandle.USER_ALL);
// 更新低电量等阀值
updateBatteryWarningLevels();
// 监听相关广播
mReceiver.init();
//检查我们是否需要让用户知道手机之前因温度过高而关闭
showWarnOnThermalShutdown();
// Register an observer to configure mEnableSkinTemperatureWarning and perform the
// registration of skin thermal event listener upon Settings change.
//注册观察者以配置 mEnableSkinTemperatureWarning 并在设置更改时执行皮肤热事件侦听器的注册。
resolver.registerContentObserver(
Settings.Global.getUriFor(Settings.Global.SHOW_TEMPERATURE_WARNING),
false /*notifyForDescendants*/,
new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
doSkinThermalEventListenerRegistration();
}
});
// Register an observer to configure mEnableUsbTemperatureAlarm and perform the
// registration of usb thermal event listener upon Settings change.
//注册观察者以配置 mEnableUsbTemperatureAlarm 并在设置更改时执行 USB 热事件侦听器的注册。
resolver.registerContentObserver(
Settings.Global.getUriFor(Settings.Global.SHOW_USB_TEMPERATURE_ALARM),
false /*notifyForDescendants*/,
new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
doUsbThermalEventListenerRegistration();
}
});
// 初始化温度阀值
initThermalEventListeners();
mCommandQueue.addCallback(this);
}
电池电量有三个关键值定义如下(frameworks\base\core\res\res\valuesconfig.xml):
<integer name="config_criticalBatteryWarningLevel">5</integer>
<integer name="config_lowBatteryWarningLevel">15</integer>
<integer name="config_lowBatteryCloseWarningBump">5</integer>
低电量警告
updateBatteryWarningLevels
void updateBatteryWarningLevels() {
//获取系统配置的危急电量,默认值是5
int critLevel = mContext.getResources().getInteger(
com.android.internal.R.integer.config_criticalBatteryWarningLevel);
// 获取系统配置的低电量值,默认:15
int warnLevel = mContext.getResources().getInteger(
com.android.internal.R.integer.config_lowBatteryWarningLevel);
if (warnLevel < critLevel) {
warnLevel = critLevel;
}
mLowBatteryReminderLevels[0] = warnLevel;
mLowBatteryReminderLevels[1] = critLevel;
// 获取系统配置的关闭低电量警告状态的电量值,默认:20(15+5)
mLowBatteryAlertCloseLevel = mLowBatteryReminderLevels[0]
+ mContext.getResources().getInteger(
com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
}
电池相关广播监听
final class Receiver extends BroadcastReceiver {
private boolean mHasReceivedBattery = false;
public void init() {
// Register for Intent broadcasts for...
IntentFilter filter = new IntentFilter();
// 省电模式改变
filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
// 电池状态改变
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
// 开关屏
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_SCREEN_ON);
// 切换用户
filter.addAction(Intent.ACTION_USER_SWITCHED);
mBroadcastDispatcher.registerReceiverWithHandler(this, filter, mHandler);
// Force get initial values. Relying on Sticky behavior until API for getting info.
if (!mHasReceivedBattery) {
// Get initial state
Intent intent = mContext.registerReceiver(
null,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED)
);
if (intent != null) {
onReceive(mContext, intent);
}
}
}
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)) {
ThreadUtils.postOnBackgroundThread(() -> {
if (mPowerManager.isPowerSaveMode()) {
// 开启省电模式则关闭低电量警告
mWarnings.dismissLowBatteryWarning();
}
});
} else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
mHasReceivedBattery = true;
// 电量
final int oldBatteryLevel = mBatteryLevel;
mBatteryLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 100);
final int oldBatteryStatus = mBatteryStatus;
mBatteryStatus = intent.getIntExtra(BatteryManager.EXTRA_STATUS,
BatteryManager.BATTERY_STATUS_UNKNOWN);
// 充电
final int oldPlugType = mPlugType;
mPlugType = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 1);
final int oldInvalidCharger = mInvalidCharger;
mInvalidCharger = intent.getIntExtra(BatteryManager.EXTRA_INVALID_CHARGER, 0);
mLastBatteryStateSnapshot = mCurrentBatteryStateSnapshot;
final boolean plugged = mPlugType != 0;
final boolean oldPlugged = oldPlugType != 0;
// 根据当前电量与危急电量、低电量、关闭低电量警告电量比较判断当前所处状态
int oldBucket = findBatteryLevelBucket(oldBatteryLevel);
int bucket = findBatteryLevelBucket(mBatteryLevel);
if (DEBUG) {
Slog.d(TAG, "buckets ....." + mLowBatteryAlertCloseLevel
+ " .. " + mLowBatteryReminderLevels[0]
+ " .. " + mLowBatteryReminderLevels[1]);
Slog.d(TAG, "level " + oldBatteryLevel + " --> " + mBatteryLevel);
Slog.d(TAG, "status " + oldBatteryStatus + " --> " + mBatteryStatus);
Slog.d(TAG, "plugType " + oldPlugType + " --> " + mPlugType);
Slog.d(TAG, "invalidCharger " + oldInvalidCharger + " --> " + mInvalidCharger);
Slog.d(TAG, "bucket " + oldBucket + " --> " + bucket);
Slog.d(TAG, "plugged " + oldPlugged + " --> " + plugged);
}
// 更新电池警告信息
mWarnings.update(mBatteryLevel, bucket, mScreenOffTime);
if (oldInvalidCharger == 0 && mInvalidCharger != 0) {
Slog.d(TAG, "showing invalid charger warning");
mWarnings.showInvalidChargerWarning();
return;
} else if (oldInvalidCharger != 0 && mInvalidCharger == 0) {
mWarnings.dismissInvalidChargerWarning();
} else if (mWarnings.isInvalidChargerWarningShowing()) {
// if invalid charger is showing, don't show low battery
if (DEBUG) {
Slog.d(TAG, "Bad Charger");
}
return;
}
// Show the correct version of low battery warning if needed
if (mLastShowWarningTask != null) {
mLastShowWarningTask.cancel(true);
if (DEBUG) {
Slog.d(TAG, "cancelled task");
}
}
mLastShowWarningTask = ThreadUtils.postOnBackgroundThread(() -> {
// 判断是否要显示低电量警告
maybeShowBatteryWarningV2(
plugged, bucket);
});
} else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
mScreenOffTime = SystemClock.elapsedRealtime();
} else if (Intent.ACTION_SCREEN_ON.equals(action)) {
mScreenOffTime = -1;
} else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
mWarnings.userSwitched();
} else {
Slog.w(TAG, "unknown intent: " + intent);
}
}
}
protected void maybeShowBatteryWarningV2(boolean plugged, int bucket) {
final boolean hybridEnabled = mEnhancedEstimates.isHybridNotificationEnabled();
final boolean isPowerSaverMode = mPowerManager.isPowerSaveMode();
// Stick current battery state into an immutable container to determine if we should show
// a warning.
if (DEBUG) {
Slog.d(TAG, "evaluating which notification to show");
}
if (hybridEnabled) {
if (DEBUG) {
Slog.d(TAG, "using hybrid");
}
Estimate estimate = refreshEstimateIfNeeded();
mCurrentBatteryStateSnapshot = new BatteryStateSnapshot(mBatteryLevel, isPowerSaverMode,
plugged, bucket, mBatteryStatus, mLowBatteryReminderLevels[1],
mLowBatteryReminderLevels[0], estimate.getEstimateMillis(),
estimate.getAverageDischargeTime(),
mEnhancedEstimates.getSevereWarningThreshold(),
mEnhancedEstimates.getLowWarningThreshold(), estimate.isBasedOnUsage(),
mEnhancedEstimates.getLowWarningEnabled());
} else {
if (DEBUG) {
Slog.d(TAG, "using standard");
}
mCurrentBatteryStateSnapshot = new BatteryStateSnapshot(mBatteryLevel, isPowerSaverMode,
plugged, bucket, mBatteryStatus, mLowBatteryReminderLevels[1],
mLowBatteryReminderLevels[0]);
}
mWarnings.updateSnapshot(mCurrentBatteryStateSnapshot);
if (mCurrentBatteryStateSnapshot.isHybrid()) {
maybeShowHybridWarning(mCurrentBatteryStateSnapshot, mLastBatteryStateSnapshot);
} else {
maybeShowBatteryWarning(mCurrentBatteryStateSnapshot, mLastBatteryStateSnapshot);
}
}
protected void maybeShowBatteryWarning(
BatteryStateSnapshot currentSnapshot,
BatteryStateSnapshot lastSnapshot) {
final boolean playSound = currentSnapshot.getBucket() != lastSnapshot.getBucket()
|| lastSnapshot.getPlugged();
if (shouldShowLowBatteryWarning(currentSnapshot, lastSnapshot)) {
mWarnings.showLowBatteryWarning(playSound);
} else if (shouldDismissLowBatteryWarning(currentSnapshot, lastSnapshot)) {
mWarnings.dismissLowBatteryWarning();
} else {
mWarnings.updateLowBatteryWarning();
}
}
在ACTION_SCREEN_OFF、ACTION_SCREEN_ON这两个广播事件处理中只是简单的对 mScreenOffTime 进行了重新赋值,当屏幕关闭时设置为从系统启动到现在的时间,当屏幕开启时设置为 -1。该值用于在其他位置做差值判断如播放低电量声音时是否播放。
final ContentResolver cr = mContext.getContentResolver();
final int silenceAfter = Settings.Global.getInt(cr,
Settings.Global.LOW_BATTERY_SOUND_TIMEOUT, 0);
final long offTime = SystemClock.elapsedRealtime() - mScreenOffTime;
if (silenceAfter > 0
&& mScreenOffTime > 0
&& offTime > silenceAfter) {
Slog.i(TAG, "screen off too long (" + offTime + "ms, limit " + silenceAfter
+ "ms): not waking up the user with low battery sound"); // 屏幕休眠时间太久了,不使用低电量声音唤醒使用者
return;
}
ACTION_BATTERY_CHANGED 广播
final int oldBatteryLevel = mBatteryLevel;
mBatteryLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 100);
final int oldBatteryStatus = mBatteryStatus;
mBatteryStatus = intent.getIntExtra(BatteryManager.EXTRA_STATUS,
BatteryManager.BATTERY_STATUS_UNKNOWN);
final int oldPlugType = mPlugType;
mPlugType = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 1);
final int oldInvalidCharger = mInvalidCharger;
mInvalidCharger = intent.getIntExtra(BatteryManager.EXTRA_INVALID_CHARGER, 0);
final boolean plugged = mPlugType != 0;
final boolean oldPlugged = oldPlugType != 0;
int oldBucket = findBatteryLevelBucket(oldBatteryLevel);
int bucket = findBatteryLevelBucket(mBatteryLevel); // 获取电量等级判断
相关判断如下
if (DEBUG) { // debug 环境下输出更多的日志信息
Slog.d(TAG, "buckets ....." + mLowBatteryAlertCloseLevel
+ " .. " + mLowBatteryReminderLevels[0]
+ " .. " + mLowBatteryReminderLevels[1]);
Slog.d(TAG, "level " + oldBatteryLevel + " --> " + mBatteryLevel);
Slog.d(TAG, "status " + oldBatteryStatus + " --> " + mBatteryStatus);
Slog.d(TAG, "plugType " + oldPlugType + " --> " + mPlugType);
Slog.d(TAG, "invalidCharger " + oldInvalidCharger + " --> " + mInvalidCharger);
Slog.d(TAG, "bucket " + oldBucket + " --> " + bucket);
Slog.d(TAG, "plugged " + oldPlugged + " --> " + plugged);
}
if (oldBatteryStatus == BatteryManager.BATTERY_STATUS_FULL
&& mBatteryStatus == BatteryManager.BATTERY_STATUS_DISCHARGING) {
mIfDisChargeHappen = 1; // 如果电池满并且没有再充电状态下 mIfDisChanrgeHappen =1
}
if (oldInvalidCharger == 0 && mInvalidCharger != 0) { // 判断新旧充电是否可用
Slog.d(TAG, "showing invalid charger warning");
showInvalidChargerDialog(); // 不可用弹出充电不可用的对话框
return;
} else if (oldInvalidCharger != 0 && mInvalidCharger == 0) {
dismissInvalidChargerDialog(); // 充电可用后 让对话框消失
} else if (mInvalidChargerDialog != null) {
// if invalid charger is showing, don't show low battery
// 如果不可用的对话框已经存在就不提示低电量
return;
}
下面判断是否弹出电量低及充电满和播放声音
if (!plugged
&& ((bucket < oldBucket || oldPlugged) || (mBatteryLevel==1 || oldPlugged))
&& mBatteryStatus != BatteryManager.BATTERY_STATUS_CHARGING
&& bucket < 0) {
showLowBatteryWarning(); // 弹出低电量报警
// only play SFX when the dialog comes up or the bucket changes
if (bucket != oldBucket || oldPlugged) {
playLowBatterySound(); // 播放低电量报警声音
}
} else if (plugged || (bucket > oldBucket && bucket > 0)) {
dismissLowBatteryWarning(); // 让低电量报警消失
} else if (mBatteryLevelTextView != null) {
showLowBatteryWarning();
}
if(!plugged) {
mOldPluggedFull = 0;
dismissFullBatteryWarning(); // 让满电提示消失
}
if(mBatteryLevel >= 100 && plugged
&& mOldPluggedFull == 0 && mIfDisChargeHappen == 1) {
mOldPluggedFull = 1 ;
showFullBatteryWarning(); // 显示满电提示
playLowBatterySound(); //播放声音
mIfDisChargeHappen = 0;
} else if ( mBatteryLevel < 100 && isChargerConnected(mPlugType)) {
if (mUsbPlugged == 1) {
playChargerConnectedSound(); // 播放连接充电时的声音
}
mUsbPlugged ++;
}