[android]狀態列的電量圖示變化程式碼流程
Android version : 5.0
Author :iceBear
date :2015/08/27
Android 5.0對狀態列做了一定改動,電池圖示預設不再有數字形式。但在下拉選單中,圖示旁邊會有一個數字格式的電量顯示。電量變化時,數字會變化;通常每當電量降低10%後,圖示會變化。本文對這個流程做簡單的分析,先說數字形式的。
數字形式的圖示包含在佈局檔案Status_bar_expanded_header.xml (\frameworks\base\packages\systemui\res\layout)中,
<TextView android:id="@+id/battery_level" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_marginStart="@dimen/header_battery_margin_expanded" android:paddingEnd="@dimen/battery_level_padding_end" android:textColor="#ffffff" android:textSize="@dimen/battery_level_text_size" android:importantForAccessibility="noHideDescendants"/>
並在StatusBarHeaderView.java (\frameworks\base\packages\systemui\src\com\android\systemui\statusbar\phone)中被獲取。
mBatteryLevel = (TextView) findViewById(R.id.battery_level);
每當電量變化時,數字會變化。
但是onBatteryLevelChanged()又是如何得知電量的變化的呢?public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {//傳進來的level即是當時的電量 mBatteryLevel.setText(getResources().getString(R.string.battery_level_template, level)); }
是因為StatusBarHeaderView實現了BatteryController.BatteryStateChangeCallback介面。
public interface BatteryStateChangeCallback {
void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging);
void onPowerSaveChanged();
}
而它又通過setBatteryController() 關聯了一個batteryController物件;
public void setBatteryController(BatteryController batteryController) {
mBatteryController = batteryController;//自己的catteryController
((BatteryMeterView) findViewById(R.id.battery)).setBatteryController(batteryController);
//圖示電量的controller,
//注意這個是下拉選單中的圖示,而不是狀態列中的,這裡先不理它BatteryController.BatteryStateChangeCallback
}
這個batteryController物件是在PhoneStatusBar.java (\frameworks\base\packages\systemui\src\com\android\systemui\statusbar\phone)中被new出來的。
BatteryController mBatteryController;
......
StatusBarHeaderView mHeader;
而後,又將這個物件set給了數字電量圖示所在的StatusBarHeaderView。
protected PhoneStatusBarView makeStatusBarView() {
......
mBatteryController = new BatteryController(mContext);
mBatteryController.addStateChangedCallback(new BatteryStateChangeCallback() {/*此處省略*/});
......
mHeader = (StatusBarHeaderView) mStatusBarWindow.findViewById(R.id.header);
......
mHeader.setBatteryController(mBatteryController);
}
其中,makeStatusBarView()經過一系列的引用,最終是在systemUI.java中的start()中被呼叫,該方法的具體情況仍待學習,這裡不再展開。
PhoneStatusBar把batteryController和我們的數字顯示TextView關聯在了一起,TextView可以通過batteryController感知到電量的變化並對剩餘電量的值進行修改。那麼接下來看看batteryController是如何感知電量變化的。
首先,它繼承了BroadcastReceiver,定義了IntentFilter並註冊了監聽
public BatteryController(Context context) {
mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);//我們需要的intent
filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING);
context.registerReceiver(this, filter);
......
}
然後,在onReceive()中進行處理
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
mLevel = (int)(100f //當前電量
* intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0)
/ intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100));
mPluggedIn = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0;
final int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS,
BatteryManager.BATTERY_STATUS_UNKNOWN);
mCharged = status == BatteryManager.BATTERY_STATUS_FULL;
mCharging = mCharged || status == BatteryManager.BATTERY_STATUS_CHARGING;
fireBatteryLevelChanged();//往下分發資料
}
......
}
fireBatteryLevelChanged()程式碼清單:
private void fireBatteryLevelChanged() {
final int N = mChangeCallbacks.size();
for (int i = 0; i < N; i++) {
//將事件分發給實現了介面BatteryController.BatteryStateChangeCallback的類
mChangeCallbacks.get(i).onBatteryLevelChanged(mLevel, mPluggedIn, mCharging);
}
}
其中:
private final ArrayList<BatteryStateChangeCallback> mChangeCallbacks = new ArrayList<>();
在StatusBarHeaderView.java中 private void updateListeners() {
if (mListening) {
mBatteryController.addStateChangedCallback(this);//將自己新增到mChangeCallbacks中去
mNextAlarmController.addStateChangedCallback(this);
} else {
mBatteryController.removeStateChangedCallback(this);
mNextAlarmController.removeStateChangedCallback(this);
}
}
public void setListening(boolean listening) {
if (listening == mListening) {
return;
}
mListening = listening;
updateListeners();
}
在NotificationPanelView.java (\frameworks\base\packages\systemui\src\com\android\systemui\statusbar\phone) 中
private StatusBarHeaderView mHeader;
......
private void setListening(boolean listening) {
mHeader.setListening(listening);
mKeyguardStatusBar.setListening(listening);
mQsPanel.setListening(listening);
}
public boolean onTouchEvent(MotionEvent event) {
......
if (mTwoFingerQsExpandPossible && event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN
&& event.getPointerCount() == 2
&& event.getY(event.getActionIndex()) < mStatusBarMinHeight) {
mTwoFingerQsExpand = true;
requestPanelHeightUpdate();
// Normally, we start listening when the panel is expanded, but here we need to start
// earlier so the state is already up to date when dragging down.
setListening(true);
}
super.onTouchEvent(event);
return true;
}
由於只在下拉選單欄中才有數字格式的電量顯示,所以當往下拉選單欄的時候,開始監聽並改變電量的值。程式碼到這裡就基本結束了,再往下就是TouchEvent的處理了,是另外的模組。下一期講一講電量圖示相關的內容。