Android 通过BatteryService对电量进行自动管理。在BatteryService.java中从jni层获得电量mBatteryLevel,
并根据mBatteryLevel判断手机电量是否过低,然后发出警告或声音提醒,并且太低时还会自动关机。下面简单介绍一下其流程。
在BatteryService.java中判断当前电量是否过低:
/* The ACTION_BATTERY_LOW broadcast is sent in these situations:
* - is just un-plugged (previously was plugged) and battery level is
* less than or equal to WARNING, or
* - is not plugged and battery level falls to WARNING boundary
* (becomes <= mLowBatteryWarningLevel).
*/
final boolean sendBatteryLow = !plugged
&& mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
&& mBatteryLevel <= mLowBatteryWarningLevel
&& (oldPlugged || mLastBatteryLevel > mLowBatteryWarningLevel);
如果当前电量小于警告电量(在config.xml中 15)则弹出电量低提示,或者电量为0(当然这个有误差也可能是5%时就自动关机)时自动关机。如果低电量的话就发送一个广播出去:
if (sendBatteryLow) {
mSentLowBatteryBroadcast = true;
statusIntent.setAction(Intent.ACTION_BATTERY_LOW);
mContext.sendBroadcast(statusIntent);
}
下面这段代码是电量过低而自动关机:
private void More ...shutdownIfNoPowerLocked() {
// shut down gracefully if our battery is critically low and we are not powered.
// wait until the system has booted before attempting to display the shutdown dialog.
if (mBatteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)) {
mHandler.post(new Runnable() {
@Override
public void More ...run() {
if (ActivityManagerNative.isSystemReady()) {
Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
}
}
});
}
}
而在StatusBarPolicy.java中会接收广播, 里面有判断当接受到ACTION_BATTERY_LOW时,
调用onBatteryLow(intent)方法来处理:
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
.....action.
//里面会有判断当接受到ACTION_BATTERY_LOW时:
else if (action.equals(Intent.ACTION_BATTERY_LOW)) {
onBatteryLow(intent);
}
}
}
private void onBatteryLow(Intent intent) {
if (SHOW_LOW_BATTERY_WARNING) {
if (false) {
Slog.d(TAG, "mPhoneState=" + mPhoneState
+ " mLowBatteryDialog=" + mLowBatteryDialog
+ " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall);
}
if (SHOW_BATTERY_WARNINGS_IN_CALL || mPhoneState == TelephonyManager.CALL_STATE_IDLE) {
showLowBatteryWarning();
} else {
mBatteryShowLowOnEndCall = true;
}
}
}
弹出低电量过低Dialog提醒和声音提醒:
private void showLowBatteryWarning() {
closeLastBatteryView();
// Show exact battery level.
CharSequence levelText = mContext.getString(R.string.battery_low_percent_format, mBatteryLevel);
if (mBatteryLevelTextView != null) {
mBatteryLevelTextView.setText(levelText);
} else {
View v = View.inflate(mContext, R.layout.battery_low, null);
mBatteryLevelTextView=(TextView)v.findViewById(R.id.level_percent);
mBatteryLevelTextView.setText(levelText);
AlertDialog.Builder b = new AlertDialog.Builder(mContext);
b.setCancelable(true);
b.setTitle(R.string.battery_low_title);
b.setView(v);
b.setIcon(android.R.drawable.ic_dialog_alert);
b.setPositiveButton(android.R.string.ok, null);
final Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_MULTIPLE_TASK
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
| Intent.FLAG_ACTIVITY_NO_HISTORY);
if (intent.resolveActivity(mContext.getPackageManager()) != null) {
b.setNegativeButton(R.string.battery_low_why, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
mContext.startActivity(intent);
if (mLowBatteryDialog != null) {
mLowBatteryDialog.dismiss();
}
}
});
}
AlertDialog d = b.create();
d.setOnDismissListener(mLowBatteryListener);
d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
d.show();
mLowBatteryDialog = d;
}
//waring voiced
final ContentResolver cr = mContext.getContentResolver();
if (Settings.System.getInt(cr, Settings.System.POWER_SOUNDS_ENABLED, 1) == 1) {
final String soundPath = Settings.System.getString(cr, Settings.System.LOW_BATTERY_SOUND);
if (soundPath != null) {
final Uri soundUri = Uri.parse("file://" + soundPath);
if (soundUri != null) {
final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
if (sfx != null) {
sfx.setStreamType(AudioManager.STREAM_SYSTEM);
sfx.play();
}
}
}
}
}