這篇文章主要說的是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源生的電池不好修改祷嘶。我的做法的是使用自己的方法來實現屎媳。這樣也便于修改。下回見,感謝....................