Android 8.1 中Systemui中的常见修改(二)电池的修改

本文详细介绍电池图标绘制原理及电量警告机制。涵盖充电图标颜色修改、电池图标分级显示、省电模式下颜色调整及电量低时的声音和视觉警告。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这篇文章主要总结一下常见的电池相关的需求实现的方法。

/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));
        /// @}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值