这篇文章主要总结一下常见的电池相关的需求实现的方法。
/frameworks/base/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
电池图标的绘制
public void draw(Canvas c) {
final int level = /*mLevel*/updateChargingAnimLevel();
final Rect bounds = getBounds();
if (level == -1) return;
float drawFrac = (float) level / 100f;
final int height = mHeight;
final int width = (int) (getAspectRatio() * mHeight);
final int px = (mWidth - width) / 2;
final int buttonHeight = Math.round(height * mButtonHeightFraction);
final int left = mPadding.left + bounds.left;
final int top = bounds.bottom - mPadding.bottom - height;
mFrame.set(left, top, width + left, height + top);
mFrame.offset(px, 0);
// button-frame: area above the battery body
mButtonFrame.set( //电池上边的凸起的位置
mFrame.left + Math.round(width * 0.27f),
mFrame.top,
mFrame.right - Math.round(width * 0.27f),
mFrame.top + buttonHeight);
// frame: battery body area 电池的桶装图标
mFrame.top += buttonHeight;
// set the battery charging color
mBatteryPaint.setColor(batteryColorForLevel(level));//根据点亮的等级设置电池的颜色
if (level >= FULL) { //当电量为96时显示为充满电
drawFrac = 1f;
} else if (level <= mCriticalLevel) { //当电量小于4的时候显示电池为空
drawFrac = 0f;
}
// define the battery shape
mShapePath.reset();
final float radius = getRadiusRatio() * (mFrame.height() + buttonHeight);
mShapePath.setFillType(FillType.WINDING);
mShapePath.addRoundRect(mFrame, radius, radius, Direction.CW);
mShapePath.addRect(mButtonFrame, Direction.CW);
if (mCharging) {//充电时候的闪电的绘制
// define the bolt shape
// Shift right by 1px for maximal bolt-goodness
final float bl = mFrame.left + mFrame.width() / 4f + 1;
final float bt = mFrame.top + mFrame.height() / 6f;
final float br = mFrame.right - mFrame.width() / 4f + 1;
final float bb = mFrame.bottom - mFrame.height() / 10f;
if (mBoltFrame.left != bl || mBoltFrame.top != bt
|| mBoltFrame.right != br || mBoltFrame.bottom != bb) {
mBoltFrame.set(bl, bt, br, bb);
mBoltPath.reset();
mBoltPath.moveTo(
mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
for (int i = 2; i < mBoltPoints.length; i += 2) {
mBoltPath.lineTo(
mBoltFrame.left + mBoltPoints[i] * mBoltFrame.width(),
mBoltFrame.top + mBoltPoints[i + 1] * mBoltFrame.height());
}
mBoltPath.lineTo(
mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
}
float boltPct = (mBoltFrame.bottom - levelTop) / (mBoltFrame.bottom - mBoltFrame.top);
boltPct = Math.min(Math.max(boltPct, 0), 1);
if (boltPct <= BOLT_LEVEL_THRESHOLD) {
// draw the bolt if opaque
c.drawPath(mBoltPath, mBoltPaint);
} else {
// otherwise cut the bolt out of the overall shape
mShapePath.op(mBoltPath, Path.Op.DIFFERENCE);
}
} else if (mPowerSaveEnabled) {
// define the plus shape
final float pw = mFrame.width() * 2 / 3;
final float pl = mFrame.left + (mFrame.width() - pw) / 2;
final float pt = mFrame.top + (mFrame.height() - pw) / 2;
final float pr = mFrame.right - (mFrame.width() - pw) / 2;
final float pb = mFrame.bottom - (mFrame.height() - pw) / 2;
if (mPlusFrame.left != pl || mPlusFrame.top != pt
|| mPlusFrame.right != pr || mPlusFrame.bottom != pb) {
mPlusFrame.set(pl, pt, pr, pb);
mPlusPath.reset();
mPlusPath.moveTo(
mPlusFrame.left + mPlusPoints[0] * mPlusFrame.width(),
mPlusFrame.top + mPlusPoints[1] * mPlusFrame.height());
for (int i = 2; i < mPlusPoints.length; i += 2) {
mPlusPath.lineTo(
mPlusFrame.left + mPlusPoints[i] * mPlusFrame.width(),
mPlusFrame.top + mPlusPoints[i + 1] * mPlusFrame.height());
}
mPlusPath.lineTo(
mPlusFrame.left + mPlusPoints[0] * mPlusFrame.width(),
mPlusFrame.top + mPlusPoints[1] * mPlusFrame.height());
}
float boltPct = (mPlusFrame.bottom - levelTop) / (mPlusFrame.bottom - mPlusFrame.top);
boltPct = Math.min(Math.max(boltPct, 0), 1);
if (boltPct <= BOLT_LEVEL_THRESHOLD) {
// draw the bolt if opaque
c.drawPath(mPlusPath, mPlusPaint);
} else {
// otherwise cut the bolt out of the overall shape
mShapePath.op(mPlusPath, Path.Op.DIFFERENCE);
}
}
// compute percentage text
boolean pctOpaque = false;
float pctX = 0, pctY = 0;
String pctText = null;
if (!mCharging && !mPowerSaveEnabled && level > mCriticalLevel && mShowPercent) {
mTextPaint.setColor(getColorForLevel(level));
mTextPaint.setTextSize(height *
(SINGLE_DIGIT_PERCENT ? 0.75f
: (mLevel == 100 ? 0.38f : 0.5f)));
mTextHeight = -mTextPaint.getFontMetrics().ascent;
pctText = String.valueOf(SINGLE_DIGIT_PERCENT ? (level / 10) : level);
pctX = mWidth * 0.5f;
pctY = (mHeight + mTextHeight) * 0.47f;
pctOpaque = levelTop > pctY;
if (!pctOpaque) {
mTextPath.reset();
mTextPaint.getTextPath(pctText, 0, pctText.length(), pctX, pctY, mTextPath);
// cut the percentage text out of the overall shape
mShapePath.op(mTextPath, Path.Op.DIFFERENCE);
}
}
// draw the battery shape background
c.drawPath(mShapePath, mFramePaint);
// draw the battery shape, clipped to charging level
mFrame.top = levelTop;
mClipPath.reset();
mClipPath.addRect(mFrame, Path.Direction.CCW);
mShapePath.op(mClipPath, Path.Op.INTERSECT);
c.drawPath(mShapePath, mBatteryPaint);
if (!mCharging && !mPowerSaveEnabled) {
if (level <= mCriticalLevel) {
// draw the warning text
final float x = mWidth * 0.5f;
final float y = (mHeight + mWarningTextHeight) * 0.48f;
c.drawText(mWarningString, x, y, mWarningTextPaint);
} else if (pctOpaque) {
// draw the percentage text
c.drawText(pctText, pctX, pctY, mTextPaint);
}
}
}
需求场景一:
更改充电闪电图标的颜色
frameworks/base/packages/SettingsLib/res/values/colors.xml
<color name="battery_bolt_color">#2196F3</color>
frameworks/base/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
//声明变量
protected final Paint mBoltColorPaint;
//在BatteryMeterDrawableBase声明变量
public BatteryMeterDrawableBase(Context context, int frameColor) {
mBoltColorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mBoltColorPaint.setColor(Utils.getDefaultColor(mContext, R.color.battery_bolt_color));
}
//在draw方法中添加上色方法
@Override
public void draw(Canvas c) {
mClipPath.reset();
mClipPath.addRect(mFrame, Path.Direction.CCW);
mShapePath.op(mClipPath, Path.Op.INTERSECT);
c.drawPath(mShapePath, mBatteryPaint);
/// M: modified by xiangzaixiansheng for battery bolt color @{
if (mCharging) {
c.drawPath(mBoltPath, mBoltColorPaint);
}
/// @}
if (!mCharging && !mPowerSaveEnabled) {
}
//
需求场景二:电池点亮分级显示
[0-5] 红色无电,5% 长度
(5-15] 1 格 红色图标, 15% 长度
(15-30] 2 格 25% 长度
(30-50] 3 格 40% 长度
(50-70] 4 格 60% 长度
(70-85] 5 格 80% 长度
(85-95] 6 格 95% 长度
(95-100] 满格 长方形+突起 满
frameworks/base/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
//导包
import android.os.Handler;
//修改宽高比
private static final float ASPECT_RATIO = 6.0f / 12.0f;
//声明变量
private int mAnimOffset;
private static final int ANIM_DURATION = 500;
private final Handler mHandler;
private final Runnable mInvalidate = new Runnable() {
@Override
public void run() {
invalidateSelf();
}
};
//在BatteryMeterDrawableBase增加方法
public BatteryMeterDrawableBase(Context context, int frameColor) {
//增加方法
mHandler = new Handler();
}
//在draw修改
@Override
public void draw(Canvas c) {
//final int level = mLevel;
final int level = /*mLevel*/updateChargingAnimLevel();
final float levelTop = drawFrac == 1f ? mButtonFrame.top
: (mFrame.top + (mFrame.height() * (1f - drawFrac)));
// define the battery shape
//修改下面的方法@{
mShapePath.reset();
mShapePath.moveTo(mButtonFrame.left, mButtonFrame.top);
mShapePath.lineTo(mButtonFrame.right, mButtonFrame.top);
mShapePath.lineTo(mButtonFrame.right, mFrame.top);
mShapePath.lineTo(mFrame.right -2 , mFrame.top);
mShapePath.lineTo(mFrame.right, mFrame.top + 2);
mShapePath.lineTo(mFrame.right, mFrame.bottom - 2);
mShapePath.lineTo(mFrame.right -2 , mFrame.bottom);
mShapePath.lineTo(mFrame.left +2, mFrame.bottom);
mShapePath.lineTo(mFrame.left, mFrame.bottom - 2);
mShapePath.lineTo(mFrame.left, mFrame.top + 2);
mShapePath.lineTo(mFrame.left + 2, mFrame.top);
mShapePath.lineTo(mButtonFrame.left, mFrame.top);
mShapePath.lineTo(mButtonFrame.left, mButtonFrame.top);
///}@
mClipPath.reset();
mClipPath.addRect(mFrame, Path.Direction.CCW);
mShapePath.op(mClipPath, Path.Op.INTERSECT);
c.drawPath(mShapePath, mBatteryPaint);
if (mCharging) {
// define the bolt shape
// draw the battery shape background
c.drawPath(mShapePath, mFramePaint);
// draw the battery shape, clipped to charging level
///增加的方法@{
if (levelTop <= 4.33f) {
/// level = 100 ;mFrame is 100%
mFrame.top = 0.33f;
} else if (4.33f < levelTop && levelTop <= 6.29f) {
/// level (95,100) ;mFrame is 100%
mFrame.top = 4.33f;
} else if (6.29f < levelTop && levelTop <= 10.23f) {
/// level (85,95); mFrame is 95%
mFrame.top = 6.29f;
} else if (10.23f < levelTop && levelTop <= 16.13f) {
/// level (70,85); mFrame is 80%
mFrame.top = 12.20f;
} else if (16.13f < levelTop && levelTop <= 23.99f) {
/// level (50,70); mFrame is 60%
mFrame.top = 20.06f;
} else if (23.99f < levelTop && levelTop <= 31.86f) {
/// level (30,50); mFrame is 40%
mFrame.top = 27.92f;
} else if (31.86f < levelTop && levelTop <= 37.76f) {
/// level (15,30); mFrame is 25%
mFrame.top = 33.82f;
} else if (37.76f < levelTop && levelTop <= 41.70f) {
mFrame.top = 37.76f;
/// level (5,15); mFrame is 15%
} else if (41.70f < levelTop && levelTop <= 44.00f) {
/// level (0,5); mFrame is 5%
mFrame.top = 41.70f;
}
//增加的方法}@
mClipPath.reset();
mClipPath.addRect(mFrame, Path.Direction.CCW);
mShapePath.op(mClipPath, Path.Op.INTERSECT);
c.drawPath(mShapePath, mBatteryPaint);
////最后添加updateChargingAnimLevel方法
private int updateChargingAnimLevel() {
int curLevel = mLevel;
if (!mCharging) {
mAnimOffset = 0;
mHandler.removeCallbacks(mInvalidate);
} else {
curLevel += mAnimOffset;
if (curLevel >= FULL) {
curLevel = 100;
mAnimOffset = 0;
} else if (0 < curLevel && curLevel < 5) {
mAnimOffset += 10;
} else if (5 < curLevel && curLevel < 15) {
mAnimOffset += 10;
} else if (15 < curLevel && curLevel < 30) {
mAnimOffset += 15;
} else if (30 < curLevel && curLevel < 50) {
mAnimOffset += 20;
} else if (50 < curLevel && curLevel < 65) {
mAnimOffset += 20;
} else if (65 < curLevel && curLevel < 70) {
mAnimOffset += 15;
} else if (70 < curLevel && curLevel < 80) {
mAnimOffset += 15;
} else if (80 <= curLevel && curLevel < 85) {
mAnimOffset += 10;
} else if (85 < curLevel && curLevel < 95) {
mAnimOffset += 15;
} else if (curLevel == 0) {
mAnimOffset += 6;
} else {
mAnimOffset += 9;
}
mHandler.removeCallbacks(mInvalidate);
mHandler.postDelayed(mInvalidate, ANIM_DURATION);
}
return curLevel;
}
///}@
需求三:修改省电模式下的电池颜色
frameworks/base/packages/SettingsLib/res/values/colors.xml
<color name="battery_power_save_color">#FF9800</color>
frameworks/base/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
//
public void draw(Canvas c) {
//注释掉下面的方法,主要是省电模式下的方法
/*} else if (mPowerSaveEnabled) {
// define the plus shape
final float pw = mFrame.width() * 2 / 3;
final float pl = mFrame.left + (mFrame.width() - pw) / 2;
final float pt = mFrame.top + (mFrame.height() - pw) / 2;
final float pr = mFrame.right - (mFrame.width() - pw) / 2;
final float pb = mFrame.bottom - (mFrame.height() - pw) / 2;
if (mPlusFrame.left != pl || mPlusFrame.top != pt
|| mPlusFrame.right != pr || mPlusFrame.bottom != pb) {
mPlusFrame.set(pl, pt, pr, pb);
mPlusPath.reset();
mPlusPath.moveTo(
mPlusFrame.left + mPlusPoints[0] * mPlusFrame.width(),
mPlusFrame.top + mPlusPoints[1] * mPlusFrame.height());
for (int i = 2; i < mPlusPoints.length; i += 2) {
mPlusPath.lineTo(
mPlusFrame.left + mPlusPoints[i] * mPlusFrame.width(),
mPlusFrame.top + mPlusPoints[i + 1] * mPlusFrame.height());
}
mPlusPath.lineTo(
mPlusFrame.left + mPlusPoints[0] * mPlusFrame.width(),
mPlusFrame.top + mPlusPoints[1] * mPlusFrame.height());
}
float boltPct = (mPlusFrame.bottom - levelTop) / (mPlusFrame.bottom - mPlusFrame.top);
boltPct = Math.min(Math.max(boltPct, 0), 1);
if (boltPct <= BOLT_LEVEL_THRESHOLD) {
// draw the bolt if opaque
c.drawPath(mPlusPath, mPlusPaint);
} else {
// otherwise cut the bolt out of the overall shape
mShapePath.op(mPlusPath, Path.Op.DIFFERENCE);
}*/
mClipPath.reset();
mClipPath.addRect(mFrame, Path.Direction.CCW);
mShapePath.op(mClipPath, Path.Op.INTERSECT);
/// M: modified by xiangzaixiansheng 新增下面的方法@{
if (mPowerSaveEnabled) {
mBatteryPaint.setColor(Utils.getDefaultColor(mContext, R.color.battery_power_save_color));
}
/// @}
c.drawPath(mShapePath, mBatteryPaint);
}
frameworks/base / packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
public void draw(Canvas canvas) {
int targetGradientAlpha = 0, targetColor = 0;
/// M: modified by xiangzaixiansheng for change battery color when in power save mode start @{
if (mMode == MODE_WARNING) {
targetColor = /*mWarning*/mTransparent;
/// @}
需求四:
[0-5]移动终端电量低于5%时应报告低电;移动终端报告低电应有声音和视觉提示,且视觉提示在用户未进行操作之前应予保持;“电池电量过低,请尽快充电。”
(5-15] 移动终端电量低于15%时应报告低电;移动终端报告低电应有声音和视觉提示,且视觉提示在用户未进行操作之前应予保持;“电池电量偏低,请充电。”
frameworks/base/packages/SystemUI/res/values/strings.xml
<string name="keyguard_lowerpower_15">Low battery, please charge</string>
<string name="keyguard_lowerpower_5">Battery is too low, please charge as soon as possible</string>
/frameworks/base / packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
protected int mLevel;
//改成下面的
public int mLevel;
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
//1
import com.android.systemui.statusbar.policy.BatteryControllerImpl;
//2
private BatteryControllerImpl mBatteryControllerImpl;
//3
KeyguardIndicationController(Context context, ViewGroup indicationArea, LockIcon lockIcon,
WakeLock wakeLock) {
mContext = context;
mIndicationArea = indicationArea;
mTextView = (KeyguardIndicationTextView) indicationArea.findViewById(
R.id.keyguard_indication_text);
mDisclosure = (KeyguardIndicationTextView) indicationArea.findViewById(
R.id.keyguard_indication_enterprise_disclosure);
mLockIcon = lockIcon;
mWakeLock = new SettableWakeLock(wakeLock);
Resources res = context.getResources();
mSlowThreshold = res.getInteger(R.integer.config_chargingSlowlyThreshold);
mFastThreshold = res.getInteger(R.integer.config_chargingFastThreshold);
mUserManager = context.getSystemService(UserManager.class);
mBatteryInfo = IBatteryStats.Stub.asInterface(
ServiceManager.getService(BatteryStats.SERVICE_NAME));
mDevicePolicyManager = (DevicePolicyManager) context.getSystemService(
Context.DEVICE_POLICY_SERVICE);
updateDisclosure();
//add by xiangzaixiansheng
mBatteryControllerImpl = new BatteryControllerImpl(mContext);
}
///4
private void updateIndication() {
if (TextUtils.isEmpty(mTransientIndication)) {
mWakeLock.setAcquired(false);
}
if (mVisible) {
// Walk down a precedence-ordered list of what should indication
// should be shown based on user or device state
if (mDozing) {
// If we're dozing, never show a persistent indication.
if (!TextUtils.isEmpty(mTransientIndication)) {
mTextView.switchIndication(mTransientIndication);
mTextView.setTextColor(mTransientTextColor);
} else {
mTextView.switchIndication(null);
}
return;
}
if (!mUserManager.isUserUnlocked(KeyguardUpdateMonitor.getCurrentUser())) {
mTextView.switchIndication(com.android.internal.R.string.lockscreen_storage_locked);
mTextView.setTextColor(Color.WHITE);
} else if (!TextUtils.isEmpty(mTransientIndication)) {
mTextView.switchIndication(mTransientIndication);
mTextView.setTextColor(mTransientTextColor);
} else if (mPowerPluggedIn) {
String indication = computePowerIndication();
if (DEBUG_CHARGING_SPEED) {
indication += ", " + (mChargingWattage / 1000) + " mW";
}
mTextView.switchIndication(indication);
mTextView.setTextColor(Color.WHITE);
/// M: modified by xiangzaixiansheng for battery ui @{
} else if (!mPowerPluggedIn && 5 < mBatteryControllerImpl.mLevel && mBatteryControllerImpl.mLevel <= 15){
mTextView.switchIndication(mContext.getResources().getString(R.string.keyguard_lowerpower_15));
mTextView.setTextColor(Color.WHITE);
} else if (!mPowerPluggedIn && mBatteryControllerImpl.mLevel <= 5){
mTextView.switchIndication(mContext.getResources().getString(R.string.keyguard_lowerpower_5));
mTextView.setTextColor(Color.WHITE);
/// end @}
} else {
mTextView.switchIndication(mRestingIndication);
mTextView.setTextColor(Color.WHITE);
}
}
}
frameworks/base/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
private void showWarningNotification() {
final int textRes = R.string.battery_low_percent_format;
final String percentage = NumberFormat.getPercentInstance().format((double) mBatteryLevel / 100.0);
/// M: modified by xiangzaixiansheng start @{
String battery_low_title_notification = mContext.getString(R.string.battery_low_title);
if (5 < mBatteryLevel && mBatteryLevel <= 15) {
battery_low_title_notification = mContext.getString(R.string.keyguard_lowerpower_15);
} else if (mBatteryLevel <= 5){
battery_low_title_notification = mContext.getString(R.string.keyguard_lowerpower_5);
}
final Notification.Builder nb =
new Notification.Builder(mContext, NotificationChannels.ALERTS)
.setSmallIcon(R.drawable.ic_power_low)
// Bump the notification when the bucket dropped.
.setWhen(mBucketDroppedNegativeTimeMs)
.setShowWhen(false)
.setContentTitle(battery_low_title_notification)
.setContentText(mContext.getString(textRes, percentage))
.setOnlyAlertOnce(true)
.setDeleteIntent(pendingBroadcast(ACTION_DISMISSED_WARNING))
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setColor(Utils.getColorAttr(mContext, android.R.attr.colorError));
/// @}