1. 程式人生 > >Android 8.0 電池顯示,電池定製

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 
版權宣告:本文為博主原創文章,轉載請附上博文連結!