Android 8.0 电池显示,电池定制

这篇文章主要说的是android8.0SystemUI电池显示方面。
好像是从android8.0起,电池是通过代码绘制的,并非往常版本是使用drawable下的图片直接显示的,这样的话,修改起来就比较麻烦。

一、电池布局
frameworks\base\packages\SystemUI\res\layout\status_bar.xml中包含system_icon.xml布局。
system_icon布局中BatteryMeterView就是电池。
随后的id为battery_level_text、oppobattery是我加的控件。下面说说,如果要修改电池应该如何做。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/system_icons"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:gravity="center_vertical">
 
     <ImageView
        android:id="@+id/status_bar_headset"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:src="@drawable/ic_headset"
        android:visibility="gone"
      />
 
    <com.android.keyguard.AlphaOptimizedLinearLayout android:id="@+id/statusIcons"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:gravity="center_vertical"
        android:orientation="horizontal"/>
 
    <include layout="@layout/signal_cluster_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="@dimen/signal_cluster_margin_start"/>
 
    <com.android.systemui.BatteryMeterView android:id="@+id/battery"
        android:layout_height="match_parent"
        android:layout_width="wrap_content"
        android:visibility="gone"
        />
 
    <TextView 
          android:id="@+id/battery_level_text"        
          android:layout_height="match_parent"        
          android:layout_width="wrap_content"        
          android:gravity="center"        
          android:layout_gravity="center_vertical"        
          android:textColor="#ffffffff"        
          android:textSize="@dimen/battery_level_text_size"/>   
          
     <ImageView         
         android:id="@+id/oppobattery"          
         android:gravity="center"           
         android:layout_height="16dp"
         android:scaleType="fitXY"
         android:layout_width="30dp"/>
 
</LinearLayout>
BatteryMeterView.java,自定义视图,代码不难,也不简单。其中有行代码mDrawable = new BatteryMeterDrawableBase(context, frameColor);,
BatteryMeterDrawableBase电池就是在这里绘制的。
其他代码就不做就介绍了,比较简单。

 
public class BatteryMeterView extends LinearLayout implements
        BatteryStateChangeCallback, Tunable, DarkReceiver, ConfigurationListener {
 
    private final BatteryMeterDrawableBase mDrawable;
    private final String mSlotBattery;
    private final ImageView mBatteryIconView;
    private final CurrentUserTracker mUserTracker;
    private TextView mBatteryPercentView;
 
    private BatteryController mBatteryController;
    private SettingObserver mSettingObserver;
    private int mTextColor;
    private int mLevel;
    private boolean mForceShowPercent;
 
    private int mDarkModeBackgroundColor;
    private int mDarkModeFillColor;
 
    private int mLightModeBackgroundColor;
    private int mLightModeFillColor;
    private float mDarkIntensity;
    private int mUser;
 
    public BatteryMeterView(Context context) {
        this(context, null, 0);
    }
 
    public BatteryMeterView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }
 
    public BatteryMeterView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
 
        setOrientation(LinearLayout.HORIZONTAL);
        setGravity(Gravity.CENTER_VERTICAL | Gravity.START);
 
        TypedArray atts = context.obtainStyledAttributes(attrs, R.styleable.BatteryMeterView,
                defStyle, 0);
        final int frameColor = atts.getColor(R.styleable.BatteryMeterView_frameColor,
                context.getColor(R.color.meter_background_color));
        mDrawable = new BatteryMeterDrawableBase(context, frameColor);
        atts.recycle();
 
        mSettingObserver = new SettingObserver(new Handler(context.getMainLooper()));
 
        mSlotBattery = context.getString(
                com.android.internal.R.string.status_bar_battery);
        mBatteryIconView = new ImageView(context);
        mBatteryIconView.setImageDrawable(mDrawable);
        final MarginLayoutParams mlp = new MarginLayoutParams(
                getResources().getDimensionPixelSize(R.dimen.status_bar_battery_icon_width),
                getResources().getDimensionPixelSize(R.dimen.status_bar_battery_icon_height));
        mlp.setMargins(0, 0, 0,
                getResources().getDimensionPixelOffset(R.dimen.battery_margin_bottom));
        addView(mBatteryIconView, mlp);
 
        updateShowPercent();
 
        Context dualToneDarkTheme = new ContextThemeWrapper(context,
                Utils.getThemeAttr(context, R.attr.darkIconTheme));
        Context dualToneLightTheme = new ContextThemeWrapper(context,
                Utils.getThemeAttr(context, R.attr.lightIconTheme));
        mDarkModeBackgroundColor = Utils.getColorAttr(dualToneDarkTheme, R.attr.backgroundColor);
        mDarkModeFillColor = Utils.getColorAttr(dualToneDarkTheme, R.attr.fillColor);
        mLightModeBackgroundColor = Utils.getColorAttr(dualToneLightTheme, R.attr.backgroundColor);
        mLightModeFillColor = Utils.getColorAttr(dualToneLightTheme, R.attr.fillColor);
 
        // Init to not dark at all.
        onDarkChanged(new Rect(), 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
        mUserTracker = new CurrentUserTracker(mContext) {
            @Override
            public void onUserSwitched(int newUserId) {
                mUser = newUserId;
                getContext().getContentResolver().unregisterContentObserver(mSettingObserver);
                getContext().getContentResolver().registerContentObserver(
                        Settings.System.getUriFor(SHOW_BATTERY_PERCENT), false, mSettingObserver,
                        newUserId);
            }
        };
    }
 
    public void setForceShowPercent(boolean show) {
        mForceShowPercent = show;
        updateShowPercent();
    }
 
    @Override
    public boolean hasOverlappingRendering() {
        return false;
    }
 
    @Override
    public void onTuningChanged(String key, String newValue) {
        if (StatusBarIconController.ICON_BLACKLIST.equals(key)) {
            ArraySet<String> icons = StatusBarIconController.getIconBlacklist(newValue);
            boolean hidden = icons.contains(mSlotBattery);
            Dependency.get(IconLogger.class).onIconVisibility(mSlotBattery, !hidden);
            setVisibility(hidden ? View.GONE : View.GONE);
        }
    }
 
    @Override
    public void onAttachedToWindow() {
        super.onAttachedToWindow();
        mBatteryController = Dependency.get(BatteryController.class);
        mBatteryController.addCallback(this);
        mUser = ActivityManager.getCurrentUser();
        getContext().getContentResolver().registerContentObserver(
                Settings.System.getUriFor(SHOW_BATTERY_PERCENT), false, mSettingObserver, mUser);
        updateShowPercent();
        Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
        Dependency.get(ConfigurationController.class).addCallback(this);
        mUserTracker.startTracking();
    }
 
    @Override
    public void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        mUserTracker.stopTracking();
        mBatteryController.removeCallback(this);
        getContext().getContentResolver().unregisterContentObserver(mSettingObserver);
        Dependency.get(TunerService.class).removeTunable(this);
        Dependency.get(ConfigurationController.class).removeCallback(this);
    }
 
    @Override
    public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
        mDrawable.setBatteryLevel(level);
        mDrawable.setCharging(pluggedIn);
        mLevel = level;
        updatePercentText();
        setContentDescription(
                getContext().getString(charging ? R.string.accessibility_battery_level_charging
                        : R.string.accessibility_battery_level, level));
    }
 
    @Override
    public void onPowerSaveChanged(boolean isPowerSave) {
        mDrawable.setPowerSave(isPowerSave);
    }
 
    private TextView loadPercentView() {
        return (TextView) LayoutInflater.from(getContext())
                .inflate(R.layout.battery_percentage_view, null);
    }
 
    private void updatePercentText() {
        if (mBatteryPercentView != null) {
            mBatteryPercentView.setText(
                    NumberFormat.getPercentInstance().format(mLevel / 100f));
        }
    }
 
    private void updateShowPercent() {
        final boolean showing = mBatteryPercentView != null;
        if (0 != Settings.System.getIntForUser(getContext().getContentResolver(),
                SHOW_BATTERY_PERCENT, 0, mUser)) {
            if (!showing) {
                mBatteryPercentView = loadPercentView();
                if (mTextColor != 0) mBatteryPercentView.setTextColor(mTextColor);
                updatePercentText();
                addView(mBatteryPercentView,
                        0,
                        new ViewGroup.LayoutParams(
                                LayoutParams.WRAP_CONTENT,
                                LayoutParams.MATCH_PARENT));
            }
        } else {
            if (showing) {
                removeView(mBatteryPercentView);
                mBatteryPercentView = null;
            }
        }
    }
 
    @Override
    public void onDensityOrFontScaleChanged() {
        scaleBatteryMeterViews();
    }
 
    /**
     * Looks up the scale factor for status bar icons and scales the battery view by that amount.
     */
    private void scaleBatteryMeterViews() {
        Resources res = getContext().getResources();
        TypedValue typedValue = new TypedValue();
 
        res.getValue(R.dimen.status_bar_icon_scale_factor, typedValue, true);
        float iconScaleFactor = typedValue.getFloat();
 
        int batteryHeight = res.getDimensionPixelSize(R.dimen.status_bar_battery_icon_height);
        int batteryWidth = res.getDimensionPixelSize(R.dimen.status_bar_battery_icon_width);
        int marginBottom = res.getDimensionPixelSize(R.dimen.battery_margin_bottom);
 
        LinearLayout.LayoutParams scaledLayoutParams = new LinearLayout.LayoutParams(
                (int) (batteryWidth * iconScaleFactor), (int) (batteryHeight * iconScaleFactor));
        scaledLayoutParams.setMargins(0, 0, 0, marginBottom);
 
        mBatteryIconView.setLayoutParams(scaledLayoutParams);
        FontSizeUtils.updateFontSize(mBatteryPercentView, R.dimen.qs_time_expanded_size);
    }
 
    @Override
    public void onDarkChanged(Rect area, float darkIntensity, int tint) {
        mDarkIntensity = darkIntensity;
        float intensity = DarkIconDispatcher.isInArea(area, this) ? darkIntensity : 0;
        int foreground = getColorForDarkIntensity(intensity, mLightModeFillColor,
                mDarkModeFillColor);
        int background = getColorForDarkIntensity(intensity, mLightModeBackgroundColor,
                mDarkModeBackgroundColor);
        mDrawable.setColors(foreground, background);
        setTextColor(foreground);
    }
 
    public void setTextColor(int color) {
        mTextColor = color;
        if (mBatteryPercentView != null) {
            mBatteryPercentView.setTextColor(color);
        }
    }
 
    public void setFillColor(int color) {
        if (mLightModeFillColor == color) {
            return;
        }
        mLightModeFillColor = color;
        onDarkChanged(new Rect(), mDarkIntensity, DarkIconDispatcher.DEFAULT_ICON_TINT);
    }
 
    private int getColorForDarkIntensity(float darkIntensity, int lightColor, int darkColor) {
        return (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, lightColor, darkColor);
    }
 
    private final class SettingObserver extends ContentObserver {
        public SettingObserver(Handler handler) {
            super(handler);
        }
 
        @Override
        public void onChange(boolean selfChange, Uri uri) {
            super.onChange(selfChange, uri);
            updateShowPercent();
        }
    }
}
在很多情况下,我们需要修改电池样式,横向电池,纵向等等。往常的安卓版本,我们只要将drawable下的电池图片就行替换就行了,但android8.0起,由于电池是代码绘制成的,所以无法像往常一样进行修改。而我的做法呢,是将android8.0源生的电池去除。
自己添加电池。

<TextView 
          android:id="@+id/battery_level_text"        
          android:layout_height="match_parent"        
          android:layout_width="wrap_content"        
          android:gravity="center"        
          android:layout_gravity="center_vertical"        
          android:textColor="#ffffffff"        
          android:textSize="@dimen/battery_level_text_size"/>   
          
     <ImageView         
         android:id="@+id/oppobattery"          
         android:gravity="center"           
         android:layout_height="16dp"
         android:scaleType="fitXY"
         android:layout_width="30dp"/>
 
以上两个控件是我在system_icon.xml中添加的。
然后,添加一个自己的控制器,代码如下。

 
public class OppoBatteryController extends BroadcastReceiver {
    private static final String TAG = "StatusBar.BatteryController";
 
    private Context mContext;
    private ArrayList<ImageView> mIconViews = new ArrayList<ImageView>();
    private ArrayList<TextView> mLabelViews = new ArrayList<TextView>();
 
    private ArrayList<BatteryStateChangeCallback> mChangeCallbacks =
            new ArrayList<BatteryStateChangeCallback>();
 
    public interface BatteryStateChangeCallback {
        public void onBatteryLevelChanged(int level, boolean pluggedIn);
    }
 
    public OppoBatteryController(Context context) {
        mContext = context;
 
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_BATTERY_CHANGED);
        context.registerReceiver(this, filter);
    }
 
    public void addIconView(ImageView v) {
        mIconViews.add(v);
    }
 
    public void addLabelView(TextView v) {
        mLabelViews.add(v);
    }
 
    public void addStateChangedCallback(BatteryStateChangeCallback cb) {
        mChangeCallbacks.add(cb);
    }
 
    public void onReceive(Context context, Intent intent) {
        final String action = intent.getAction();
        if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
            final int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
            final int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS,
                    BatteryManager.BATTERY_STATUS_UNKNOWN);
 
            boolean plugged = false;
            switch (status) {
                case BatteryManager.BATTERY_STATUS_CHARGING: 
                case BatteryManager.BATTERY_STATUS_FULL:
                    plugged = true;
                    break;
            }
 
            final int icon = plugged ? R.drawable.stat_sys_battery_charge_kb
                                     : R.drawable.stat_sys_battery_oppo;
 
            int N = mIconViews.size();
            for (int i=0; i<N; i++) {
                ImageView v = mIconViews.get(i);
                v.setImageResource(icon);
                v.setImageLevel(level);
                v.setContentDescription(mContext.getString(R.string.accessibility_battery_level_status,
                        level));
            }
            N = mLabelViews.size();
            for (int i=0; i<N; i++) {
                TextView v = mLabelViews.get(i);
                v.setText(mContext.getString(R.string.status_bar_settings_battery_meter_format,
                        level));
            }
 
            for (BatteryStateChangeCallback cb : mChangeCallbacks) {
                cb.onBatteryLevelChanged(level, plugged);
            }
        }
    }
}
 
控制器内容,也非常的简单。具体就三点addLabelView()、addIconView()、final int icon = plugged ?R.drawable.stat_sys_battery_charge_kb:R.drawable.stat_sys_battery_oppo;
添加电池ImageView和电池百分比TextView,然后根据充电状态等去获取相应的图片进行显示。
~
~
drawable下stat_sys_battery_charge_kb.xml如下,对应充电状态的文件,stat_sys_battery_oppo对应电池正常状态的文件。

<level-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:maxLevel="0" android:drawable="@drawable/oppo_stat_sys_battery_charge_anim0" />
    <item android:maxLevel="4" android:drawable="@drawable/oppo_stat_sys_battery_charge_anim4" />
    <item android:maxLevel="8" android:drawable="@drawable/oppo_stat_sys_battery_charge_anim8" />
    <item android:maxLevel="12" android:drawable="@drawable/oppo_stat_sys_battery_charge_anim12" />
    <item android:maxLevel="16" android:drawable="@drawable/oppo_stat_sys_battery_charge_anim16" />
    <item android:maxLevel="20" android:drawable="@drawable/oppo_stat_sys_battery_charge_anim20" />
    <item android:maxLevel="24" android:drawable="@drawable/oppo_stat_sys_battery_charge_anim24" />
    <item android:maxLevel="28" android:drawable="@drawable/oppo_stat_sys_battery_charge_anim28" />
 
    <item android:maxLevel="32" android:drawable="@drawable/oppo_stat_sys_battery_charge_anim32" />
    <item android:maxLevel="36" android:drawable="@drawable/oppo_stat_sys_battery_charge_anim36" />
    <item android:maxLevel="40" android:drawable="@drawable/oppo_stat_sys_battery_charge_anim40" />
    <item android:maxLevel="44" android:drawable="@drawable/oppo_stat_sys_battery_charge_anim44" />
    <item android:maxLevel="48" android:drawable="@drawable/oppo_stat_sys_battery_charge_anim48" />
    <item android:maxLevel="52" android:drawable="@drawable/oppo_stat_sys_battery_charge_anim52" />
    <item android:maxLevel="56" android:drawable="@drawable/oppo_stat_sys_battery_charge_anim56" />
    <item android:maxLevel="60" android:drawable="@drawable/oppo_stat_sys_battery_charge_anim60" />
 
    <item android:maxLevel="64" android:drawable="@drawable/oppo_stat_sys_battery_charge_anim64" />
    <item android:maxLevel="68" android:drawable="@drawable/oppo_stat_sys_battery_charge_anim68" />
    <item android:maxLevel="72" android:drawable="@drawable/oppo_stat_sys_battery_charge_anim72" />
    <item android:maxLevel="76" android:drawable="@drawable/oppo_stat_sys_battery_charge_anim76" />
    <item android:maxLevel="80" android:drawable="@drawable/oppo_stat_sys_battery_charge_anim80" />
 
     <item android:maxLevel="84" android:drawable="@drawable/oppo_stat_sys_battery_charge_anim84" />
    <item android:maxLevel="88" android:drawable="@drawable/oppo_stat_sys_battery_charge_anim88" />
    <item android:maxLevel="92" android:drawable="@drawable/oppo_stat_sys_battery_charge_anim92" />
    <item android:maxLevel="96" android:drawable="@drawable/oppo_stat_sys_battery_charge_anim96" />
    <item android:maxLevel="100" android:drawable="@drawable/oppo_stat_sys_battery_charge_anim100" />
</level-list>
OppoBatteryController的使用非常的简单,创建控制器对象,设置控件,完了。这样就可以使用自己想要的电池样式就行修改。
mOppoBatteryController = new OppoBatteryController(getContext());       
        mOppoBatteryController.addIconView(mBatteryImageView);
        mOppoBatteryController.addLabelView(mBatteryTextView);
 
这就是android 8.0的电池显示,android8.0源生的电池不好修改。我的做法的是使用自己的方法来实现。这样也便于修改。下回见,感谢....................

参考文章
--------------------- 
作者:江丶小鱼 
来源:CSDN 
原文:https://blog.csdn.net/caodaoxin555/article/details/80988123 
版权声明:本文为博主原创文章,转载请附上博文链接!

猜你喜欢

转载自blog.csdn.net/f2006116/article/details/83956830