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斋泄,然后根據充電狀態(tài)等去獲取相應的圖片進行顯示。
~
~
drawable下stat_sys_battery_charge_kb.xml如下镐牺,對應充電狀態(tài)的文件炫掐,stat_sys_battery_oppo對應電池正常狀態(tài)的文件。

<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的使用非常的簡單募胃,創(chuàng)建控制器對象旗唁,設置控件,完了痹束。這樣就可以使用自己想要的電池樣式就行修改检疫。

mOppoBatteryController = new OppoBatteryController(getContext());       
        mOppoBatteryController.addIconView(mBatteryImageView);
        mOppoBatteryController.addLabelView(mBatteryTextView);

這就是android 8.0的電池顯示,android8.0源生的電池不好修改祷嘶。我的做法的是使用自己的方法來實現屎媳。這樣也便于修改。下回見,感謝....................

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末论巍,一起剝皮案震驚了整個濱河市烛谊,隨后出現的幾起案子,更是在濱河造成了極大的恐慌嘉汰,老刑警劉巖丹禀,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異鞋怀,居然都是意外死亡双泪,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門密似,熙熙樓的掌柜王于貴愁眉苦臉地迎上來焙矛,“玉大人,你說我怎么就攤上這事辛友””猓” “怎么了剪返?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵废累,是天一觀的道長。 經常有香客問我脱盲,道長邑滨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任钱反,我火速辦了婚禮掖看,結果婚禮上,老公的妹妹穿的比我還像新娘面哥。我一直安慰自己哎壳,他們只是感情好,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布尚卫。 她就那樣靜靜地躺著归榕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪吱涉。 梳的紋絲不亂的頭發(fā)上刹泄,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天外里,我揣著相機與錄音,去河邊找鬼特石。 笑死盅蝗,一個胖子當著我的面吹牛,可吹牛的內容都是我干的姆蘸。 我是一名探鬼主播墩莫,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼逞敷!你這毒婦竟也來了贼穆?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤兰粉,失蹤者是張志新(化名)和其女友劉穎故痊,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體玖姑,經...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡愕秫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了焰络。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片戴甩。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖闪彼,靈堂內的尸體忽然破棺而出甜孤,到底是詐尸還是另有隱情,我是刑警寧澤畏腕,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布缴川,位于F島的核電站,受9級特大地震影響描馅,放射性物質發(fā)生泄漏把夸。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一铭污、第九天 我趴在偏房一處隱蔽的房頂上張望恋日。 院中可真熱鬧,春花似錦嘹狞、人聲如沸岂膳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽谈截。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間傻盟,已是汗流浹背速蕊。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留娘赴,地道東北人规哲。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像诽表,于是被迫代替她去往敵國和親唉锌。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內容