icon
|
這個(gè)是設(shè)置通知的圖標(biāo)。像天氣預(yù)報(bào)圖標(biāo),。
|
sound
|
這個(gè)是設(shè)置來通知時(shí)的提示音,。
|
tickerText
|
設(shè)置提示的文字。
|
vibrate
|
來通知時(shí)振動(dòng),。
|
when
|
設(shè)置來通知時(shí)的時(shí)間,。
|
contentIntent
|
Notification的
Intent
,即點(diǎn)擊后轉(zhuǎn)向的
Activity
|
flag
|
FLAG_NO_CLEAR
|
設(shè)置為這個(gè)屬性那么通知欄的那個(gè)清楚按鈕就不會(huì)出現(xiàn)
|
FLAG_ONGOING_EVENT
|
設(shè)置為這個(gè)屬性那么通知就會(huì)像QQ圖標(biāo)一樣一直在狀態(tài)欄顯示
|
DEFAULT_ALL
|
將所有屬性設(shè)置為默認(rèn)
|
DEFAULT_SOUND
|
將提示聲音設(shè)置為默認(rèn)
|
DEFAULT_VIBRATE
|
將震動(dòng)設(shè)置為默認(rèn)
|
表1.1
填充Notification的各個(gè)屬性:
//Notification的
Intent ,,即點(diǎn)擊后轉(zhuǎn)向的 Activity
Intent notificationIntent1 = new Intent(this, this.getClass());
notificationIntent1.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent contentIntent1 = PendingIntent.getActivity(this, 0, notificationIntent1, 0);
n.contentIntent=contentIntent1;
n.icon = R.drawable.notification_icon;
n.tickerText = "hello";
notification.sound = Uri.parse("file:///sdcard/notification/ringer.mp3");
notification.vibrate = vibrate;
發(fā)送通知:
private static final int ID_NOTIFICATION = 1;
mNotificationManager.notify(ID_NOTIFICATION, notification);
通知的更新
如果需要更新一個(gè)通知,,只需要在設(shè)置好
notification 之后,,再調(diào)用setLatestEventInfo
,,然后重新發(fā)送一次通知即可。
自定義通知視圖
這部分可以參考官方文檔,,講的很詳細(xì)了,。
AndroidSDK: docs/guide/topics/ui/notifiers/notifications.html
Notification.Builder
這個(gè)類一般用于管理Notification,動(dòng)態(tài)的設(shè)置
Notification
的一些屬性,。即用set
來設(shè)置,。
問題:如何區(qū)分“正在進(jìn)行的”和“通知”,誰決定一個(gè)事件是“正在進(jìn)行的”還是持續(xù)的“通知”?
通過設(shè)置Notification的flag屬性可以設(shè)定notification是正在進(jìn)行的還是持續(xù)的notification,。
FLAG_INSISTENT和FLAG_ONGOING_EVENT標(biāo)志位可以讓Notification成為持續(xù)的或正在進(jìn)行的Notification,。
.Notification
標(biāo)記為ONGOING,如下面的代碼所示,它就能用于表示當(dāng)前正在進(jìn)行的事件(如來電),。正在進(jìn)行的事件與“通知”Notification區(qū)別在擴(kuò)展的狀態(tài)條窗口中,。
notification.flags = notification.flags | Notification.FLAG_ONGOING_EVENT;
.持續(xù)的Notification一直重復(fù),直到用戶取消,。下面的代碼給出了如何設(shè)置Notification為持續(xù)的:
notification.flags = notification.flags | Notification.FLAG_INSISTENT;
持續(xù)Notification
反復(fù)重復(fù)開頭的 Notification效果,,直到用戶取消。持續(xù)的
Notification 應(yīng)該保留給如鬧鐘的情形,,它需要及時(shí)的采取響應(yīng).
1.2.2 系統(tǒng)圖標(biāo)的增加刪除
這里主要向大家介紹如何添加一個(gè)在狀態(tài)欄顯示的系統(tǒng)圖標(biāo),,類似于系統(tǒng)默認(rèn)的鬧鐘圖標(biāo),聲音圖標(biāo)等。
文件中加資源:
.frameworks\base\core\res\res\drawalbe
中添加系統(tǒng)圖標(biāo)的圖片資源
.frameworks\base\core\res\res\values\config.xml
中添加圖片引用,,這些
icon
在這個(gè)string array的位置就決定了其在status
bar 上顯示的位置了,。我們可以從code
里面得出該結(jié)論。所以當(dāng)你要調(diào)換
icon
的順序時(shí),,改動(dòng)這個(gè)config.xml就可以了,。在
StatusBarManagerService
初始化的時(shí)候就會(huì)讀取config.xml下
icons 的String array。
這個(gè)文件中加代碼:StatusBarPolicy.java
以鬧鐘為例,。
.在
StatusbarPolicy.java
中初始化所增加的系統(tǒng)圖標(biāo)
.在構(gòu)造函數(shù)中
SetIcon
.StatusBarPolicy
調(diào)用registerReceiver
注冊(cè)了感興趣的
intent,當(dāng)感興趣的
intent
發(fā)生時(shí),,對(duì)圖標(biāo)進(jìn)行更新。例如,,設(shè)置一個(gè)鬧鐘后,,鬧鐘模塊會(huì)發(fā)出一個(gè)叫做Intent.ACTION_ALARM_CHANGED的廣播,然后
StatusBarPolicy
接收到此廣播,,繼而更新狀態(tài)欄上的鬧鐘圖標(biāo),。
………
// Alarm clock StatusBarPolicy構(gòu)造方法中初始化鬧鐘圖標(biāo)
mService.setIcon("alarm_clock",R.drawable.stat_notify_alarm, 0);
mService.setIconVisibility("alarm_clock", false);
……..
// StatusBarPolicy構(gòu)造方法中注冊(cè)鬧鐘改變廣播
filter.addAction(Intent.ACTION_ALARM_CHANGED);
…....
.添加
圖標(biāo)更新函數(shù)
private final void updateAlarm(Intent intent) {
boolean alarmSet = intent.getBooleanExtra(“alarmSet”, false);
mService.setIconVisibility(“alarm_clock”, alarmSet);
}
以上是在狀態(tài)欄添加顯示的系統(tǒng)圖標(biāo)的步驟。
代碼執(zhí)行步驟:
StatusBarManagerService.java中
StatusBarIconList mIcons = newStatusBarIconList();
………
mIcons.defineSlots(res.getStringArray(com.android.internal.R.array.config_statusBarIcons));
StatusBarPolicy.java -- > setIcon(…)
StatusBarManager.java-- > setIcon(…)
StatusBarManagerService.java-- > setIcon(…)
在StatusBarService的onCreate的時(shí)候調(diào)用StatusBarManagerService中的registerStatusBar(…)
Statusbar中的控制開關(guān)會(huì)做詳細(xì)的描述,,這里就不在贅述,。
二、模塊基本布局
2.1 Statusbar 布局
Android系統(tǒng)頂上的狀態(tài)欄是屬于FrameWork的內(nèi)容,,在此先對(duì)
statusbar
的的結(jié)構(gòu)做一定描述,。
StatusBar的布局文件
status_bar.xml
,文件位置:
frameworks/base/packages/SystemUI/res/layout/status_bar.xml
LinearLayout android:id="@+id/icons"我們看到的狀態(tài)欄,,系統(tǒng)默認(rèn)是左邊放通知圖標(biāo)
notificationIcons
,,右邊放狀態(tài)圖標(biāo)
statusIcons
--1.
通知圖標(biāo)區(qū)域:
IconMerger android:id="@+id/notificationIcons"
--2.
狀態(tài)圖標(biāo)區(qū)域:
LinearLayout android:id="@+id/statusIcons"
LinearLayout android:id="@+id/ticker"顯示。在正常情況下ticker
是不顯示的,,只有在
StatusBarService
收到通知時(shí)它才顯示
最后一個(gè)是DateView
,,它是在點(diǎn)擊
statusbar時(shí)才顯示的,默認(rèn)是隱藏的
三,、模塊內(nèi)部框架
Statusbar內(nèi)部各種交互以及模塊與其他應(yīng)用的交互都是建立在StatusbarService之上的,,其中包括
Statusbar
視圖的創(chuàng)建(包括
Statusbar
、 TrackingView和
StatusbarExpandedView
),,視圖動(dòng)畫,,系統(tǒng)圖標(biāo)(鬧鐘、
wifi
,、SIM
卡等)的加載和管理,,其他應(yīng)用通知信息的加載顯示、更新,、刪除等,,其他應(yīng)用的遠(yuǎn)程接口控制(如當(dāng)打電話時(shí)statusbar處于禁用狀態(tài)的)對(duì)Android
系統(tǒng)其他應(yīng)用的通知信息(包括圖標(biāo),、
tracker
、notification的布局等)的處理,。SIM
卡信息的控制等,。
總之StatusbarService是
Statusbar
的靈魂所在,是
Statusbar的核心,,所有關(guān)于
Statusbar
的操作處理都是建立在
StatusbarService
這個(gè)基礎(chǔ)之上的,。
四、模塊流程
在整個(gè)Statusbar模塊中包括了多個(gè)操作流程(例如StatusbarService的啟動(dòng)流程),,
Statusbar
與系統(tǒng)其他應(yīng)用交互的處理流程(例如
Statusbar
對(duì)天氣預(yù)報(bào)的通知的處理),,還有系統(tǒng)圖標(biāo)的更新流程,
statusbar
拖動(dòng)時(shí)動(dòng)畫的繪制流程,,以及遠(yuǎn)程接口的控制流程等,。
4.1啟動(dòng)流程
4.1.1 StatusbarService的啟動(dòng)流程
首先,當(dāng)系統(tǒng)進(jìn)程system_press啟動(dòng)之后,,調(diào)用系統(tǒng)SystemServer.java,,在
SystemServer
中運(yùn)行
ServerThread.run()方法時(shí)會(huì)注冊(cè)
StatusBarManagerService
。
- <SPAN style="FONT-SIZE: x-small">try {
-
- Slog.i(TAG, "Status Bar");
-
- statusBar = new StatusBarManagerService(context);
-
- ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar);
-
- } catch (Throwable e) {
-
- Slog.e(TAG, "Failure starting StatusBarManagerService", e);
-
- }
-
- 讓后調(diào)用StatusBarManagerService 的systemReady2() 方法,,會(huì)在systemReady2() 方法中啟動(dòng)StatusbarService ,。
-
- final StatusBarManagerService statusBarF = statusBar;
-
- if (statusBarF != null) statusBarF.systemReady2();
-
- public void systemReady2() {
-
- ComponentName cn = ComponentName.unflattenFromString(mContext.getString(com.android.internal.R.string.config_statusBarComponent));
-
- Intent intent = new Intent();
-
- intent.setComponent(cn);
-
- Slog.i(TAG, "Starting service: " + cn);
-
- mContext.startService(intent);
-
- } </SPAN>
- try {<span style="font-size:10px;"><span style="font-size:10px;">
-
- Slog.i(TAG, "Status Bar");
-
- statusBar = new StatusBarManagerService(context);
-
- ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar);
-
- } catch (Throwable e) {
-
- Slog.e(TAG, "Failure starting StatusBarManagerService", e);
-
- }
-
- 讓后調(diào)用StatusBarManagerService 的systemReady2() 方法,會(huì)在systemReady2() 方法中啟動(dòng)StatusbarService ,。
-
- final StatusBarManagerService statusBarF = statusBar;
-
- if (statusBarF != null) statusBarF.systemReady2();
-
- public void systemReady2() {
-
- ComponentName cn = ComponentName.unflattenFromString(mContext.getString(com.android.internal.R.string.config_statusBarComponent));
-
- Intent intent = new Intent();
-
- intent.setComponent(cn);
-
- Slog.i(TAG, "Starting service: " + cn);
-
- mContext.startService(intent);
-
- } </span></span>
注:在SystemUI模塊的SystemUiApp.java的onCreate方法中也會(huì)startService,,這是當(dāng)Statusbar意外退出而導(dǎo)致StatusbarService停止服務(wù)時(shí)會(huì)重新啟動(dòng)StatusbarService
4.1.2系統(tǒng)圖標(biāo)初始化流程
在啟動(dòng)StatusBarService后,StatusbarService會(huì)調(diào)用一個(gè)makeStatusBarView的方法,,在里面將創(chuàng)建StatusBarView在創(chuàng)建StatusbarView的過程中會(huì)加載系統(tǒng)圖標(biāo),。
在啟動(dòng)StatusbarService的過程中會(huì)創(chuàng)建StatusBarPolicy的對(duì)象,,StatusBarPolicy.java主要負(fù)責(zé)狀態(tài)欄顯示策略的管理(如狀態(tài)欄的圖標(biāo)什么時(shí)候顯示,,在什么位置顯示等)。StatusBarPolicy的構(gòu)造函數(shù)中初始化了很多系統(tǒng)圖標(biāo)(如電池信息圖標(biāo),,鬧鐘圖標(biāo),,聲音圖標(biāo),信號(hào)欄圖標(biāo)等),。,。默認(rèn)時(shí)有很多圖標(biāo)是不顯示的,需要顯示時(shí)再進(jìn)行更新,。
圖標(biāo)初始化,,以電池電量顯示為例,大概關(guān)鍵步驟如下:
通過BroadcastReceiver機(jī)制,,StatusBarPolicy中注冊(cè)的mIntentReceiver收到BatteryService廣播的ACTION_BATTERY_CHANGED事件觸發(fā),;
調(diào)用updateBattery(intent)開始更新電池狀態(tài)欄,;
從intent中解析需要的字段,調(diào)用StatusBarManager的setIcon(),。StatusBarManager是客戶端使用的狀態(tài)欄管理類,;
通過IBinder機(jī)制跨進(jìn)程調(diào)用StatusBarManagerService的setIcon()。StatusBarManagerService派生于IStatusBarService.Stub,,是狀態(tài)欄管理的服務(wù)端,,是具體實(shí)現(xiàn);
StatusBarManagerService有一個(gè)mIcons成員,,這個(gè)list成員在StatusBarManagerService創(chuàng)建時(shí)加載,。StatusBarManagerService的setIcon()過程中,會(huì)又"battery"字段獲得在mIcons中的索引,,再由包名,、圖片id和等級(jí)創(chuàng)建StatusBarIcon實(shí)例,并將這個(gè)實(shí)例更新StatusBarIconList中所獲得索引對(duì)應(yīng)項(xiàng),;
調(diào)用CommandQueue的setIcon(),。CommandQueue派生于IStatusBar.Stub,有一個(gè)內(nèi)部接口Callbacks,,這個(gè)接口的實(shí)現(xiàn)就是StatusBarService,。CommandQueue、StatusBarService和StatusBarManager屬于同一個(gè)進(jìn)程,,而StatusBarManagerService是一個(gè)系統(tǒng)級(jí)服務(wù),,它們之間必然需要通過IBinder進(jìn)程間通信;
CommandQueue用于處理狀態(tài)欄,、通知相關(guān)的請(qǐng)求,,內(nèi)部維護(hù)了一個(gè)事件隊(duì)列,setIcon()會(huì)創(chuàng)建一個(gè)OP_SET_ICON的massege,,發(fā)送給Handler處理,;
CommandQueue內(nèi)部也有一個(gè)StatusBarIconList實(shí)例,這個(gè)實(shí)例是由StatusBarService創(chuàng)建,。在處理OP_SET_ICON的massege前,,會(huì)先通過getViewIndex獲得圖標(biāo)View的位置索引viewIndex,(因?yàn)橛行﹫D標(biāo)有可能為空)再更新StatusBarIconList,,最后調(diào)用Callbacks,,也就是StatusBarService的addIcon()或者updateIcon();
以addIcon()為例,,StatusBarService的addIcon()會(huì)創(chuàng)建一個(gè)新的StatusBarIconView,,將第步中所創(chuàng)建的StatusBarIcon實(shí)例設(shè)置進(jìn)去,然后把這個(gè)view添加到LinearLayout的viewIndex位置,。
這樣一個(gè)電池相關(guān)圖標(biāo)就在狀態(tài)欄上添加或者更新了,。刪除操作類似,。
4.2 通知處理
在應(yīng)用Activity中實(shí)現(xiàn)通知欄圖標(biāo)變化的程序中。是用NotificationManager對(duì)象mNotificationManager來發(fā)送通知,。通知為Notification
mNotification 對(duì)象,,填充mNotification
的圖標(biāo)和消息內(nèi)容以及一個(gè)when,然后構(gòu)造了一個(gè)Intent對(duì)象intent,,包含了本Activity對(duì)象的引用,,以及本Activity的類名,一個(gè)PendingIntent
pi對(duì)象,,包含上述Intent對(duì)象以及本Activity對(duì)象的引用,,是用于消息列表中顯示本Activity項(xiàng)。點(diǎn)擊時(shí)重新激活Activity,。然后調(diào)用nm.setLatestEventInfo設(shè)置狀態(tài)欄下拉列表項(xiàng)內(nèi)容,。最后調(diào)用nm.notify(1,n)方法來發(fā)送通知,接著改變狀態(tài)欄的工作就由NotificationManager和StatusBarManagerService交互了,。
下面來看看NotificationManager 是如何和StatusBarManagerService 交互的,。
nm.notify(1,n)方法做了最重要的事,就是所謂的發(fā)送通知
該方法的代碼如下:
|
public void notify(int id, Notification notification)
{
notify(null, id, notification);
}
|
實(shí)際上是調(diào)用了下面這個(gè)函數(shù):
|
public void notify(String tag, int id, Notification notification)
{
int[] idOut = new int[1];
INotificationManager service = getService();
String pkg = mContext.getPackageName();
if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
try {
service.enqueueNotificationWithTag(pkg, tag, id, notification, idOut);
if (id != idOut[0]) {
Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);
}
} catch (RemoteException e) {
}
}
|
該函數(shù)中主要做了2件事:獲取一個(gè)服務(wù),,用該服務(wù)將通知事件“入隊(duì)”插入通知隊(duì)列,,所以應(yīng)該在某個(gè)地方有人在不停的讀取通知隊(duì)列。
下面是
getService的代碼,,這里的INotificationManager.Stub.asInterface(b)這個(gè)形式在好多地方出現(xiàn),,一定要詳細(xì)理解該類代碼,在Binder機(jī)制中,。
|
static public INotificationManager getService()
{
if (sService != null) {
return sService;
}
IBinder b = ServiceManager.getService("notification");
sService = INotificationManager.Stub.asInterface(b);
return sService;
}
|
在StatusBarManagerService中添加了該消息:
位于
NotificationManagerService的enqueueNotificationInternal函數(shù)中:
|
r.statusBarKey =
mStatusBar.addNotification(n);
其中n是由notification對(duì)象構(gòu)造的statusBarNotification對(duì)象 mStatusBar是一個(gè)StutusBarManagerService的引用,。
在addNotification()中執(zhí)行了:
synchronized (mNotifications) {
IBinder key = new Binder();
mNotifications.put(key, notification);
if (mBar != null) {
try {
mBar.addNotification(key, notification);
} catch (RemoteException ex) {
}
}
return key;
|
這里先執(zhí)行了mNotification.put將該通知加入一個(gè)hashMap結(jié)構(gòu)體中
然后執(zhí)行了mBar.addNotification(key,notification)
調(diào)用了CommandQueue中的addNotification方法,該方法利用Handler調(diào)用了mCallbacks.addNotification方法,,其實(shí)就是StatusBarService中的,。
這個(gè)mBar是由方法:
public void registerStatusBar(IStatusBar bar, StatusBarIconList iconList,
List<IBinder> notificationKeys, List<StatusBarNotification> notifications) {
enforceStatusBarService();
Slog.i(TAG, "registerStatusBar bar=" + bar);
mBar = bar;
synchronized (mIcons) {
iconList.copyFrom(mIcons);
}
synchronized (mNotifications) {
for (Map.Entry<IBinder,StatusBarNotification> e: mNotifications.entrySet()) {
notificationKeys.add(e.getKey());
notifications.add(e.getValue());
}
}
}
|
在StatusBarService啟動(dòng)的時(shí)候注冊(cè)的mCommandQueue對(duì)象的引用
mCommandQueue = new CommandQueue(this, iconList);
|
由該對(duì)象的實(shí)例化以及其構(gòu)造函數(shù)
public CommandQueue(Callbacks callbacks, StatusBarIconList list) {
mCallbacks = callbacks;
mList = list;
}
|
可以看出,注冊(cè)的mCommandQueue中的callbacks接口,,是由StatusBarService實(shí)現(xiàn)的
public interface Callbacks {
public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon);
public void updateIcon(String slot, int index, int viewIndex,
StatusBarIcon old, StatusBarIcon icon);
public void removeIcon(String slot, int index, int viewIndex);
public void addNotification(IBinder key, StatusBarNotification notification);
public void updateNotification(IBinder key, StatusBarNotification notification);
public void removeNotification(IBinder key);
public void disable(int state);
public void animateExpand();
public void animateCollapse();
}
|
接口聲明如上:
其中,,StatusBarService對(duì)addNotification的實(shí)現(xiàn)如下:
public void addNotification(IBinder key, StatusBarNotification notification) {
boolean shouldTick = true;
if (notification.notification.fullScreenIntent != null) {
shouldTick = false;
Slog.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");
try {
notification.notification.fullScreenIntent.send();
} catch (PendingIntent.CanceledException e) {
}
}
StatusBarIconView iconView = addNotificationViews(key, notification);
if (iconView == null) return;
if (shouldTick) {
tick(notification);
}
// Recalculate the position of the sliding windows and the titles.
setAreThereNotifications();
updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
}
|
所以到頭來enqueueNotificationInternal方法中mBar.addNotification(key,
notification);其實(shí)是調(diào)用了StatusBarService實(shí)現(xiàn)的addNotification方法,,即上面的代碼,。
上面的代碼中這句StatusBarIconView iconView = addNotificationViews(key,
notification); 以及tick(notification)
可能是將圖標(biāo)以及信息顯示在StatusBarView上的主要語句。接著進(jìn)入這兩個(gè)方法,。
addNotificationViews():
|
StatusBarIconView addNotificationViews(IBinder key, StatusBarNotification notification) {
NotificationData list;
ViewGroup parent;
final boolean isOngoing = notification.isOngoing();
if (isOngoing) {
list = mOngoing;
parent = mOngoingItems;
} else {
list = mLatest;
parent = mLatestItems;
}
// Construct the expanded view.
final View[] views = makeNotificationView(notification, parent);
if (views == null) {
handleNotificationError(key, notification, "Couldn't expand RemoteViews for: "
+ notification);
return null;
}
final View row = views[0];
final View content = views[1];
final View expanded = views[2];
// Construct the icon.
final StatusBarIconView iconView = new StatusBarIconView(this,
notification.pkg + "/0x" + Integer.toHexString(notification.id));
final StatusBarIcon ic = new StatusBarIcon(notification.pkg, notification.notification.icon,
notification.notification.iconLevel, notification.notification.number);
if (!iconView.set(ic)) {
handleNotificationError(key, notification, "Coulding create icon: " + ic);
return null;
}
// Add the expanded view.
final int viewIndex = list.add(key, notification, row, content, expanded, iconView);
parent.addView(row, viewIndex);
// Add the icon.
final int iconIndex = chooseIconIndex(isOngoing, viewIndex);
mNotificationIcons.addView(iconView, iconIndex);
return iconView;
}
|
final StatusBarIconView iconView = new StatusBarIconView(this,
notification.pkg + "/0x" + Integer.toHexString(notification.id));
其中這一句利用傳來的notification構(gòu)造了圖標(biāo)view
mNotificationIcons.addView(iconView, iconIndex);
其中mNotificationIcons是一個(gè)IconMerger對(duì)象,,IconMerger是繼承LinearLayout的類。
這一句將圖標(biāo)顯示在StatusBar上,。
|
如上就是當(dāng)應(yīng)用發(fā)送完notification后
StatusbarService
是如何將發(fā)送的信息顯示到
Statusbar
上的,。
4.3 圖標(biāo)更新
4.3.1通過廣播接收器的方式
StatusBarPolicy調(diào)用
registerReceiver注冊(cè)了感興趣的
intent,
當(dāng)感興趣的intent
發(fā)生時(shí),,對(duì)圖標(biāo)進(jìn)行更新。例如,,設(shè)置一個(gè)鬧鐘后,,鬧鐘模塊會(huì)發(fā)出一個(gè)叫做
Intent.ACTION_ALARM_CHANGED
的廣播,然后
StatusBarPolicy接收到此廣播,,繼而更新狀態(tài)欄上的鬧鐘圖標(biāo),。
………
// Alarm clock StatusBarPolicy構(gòu)造方法中初始化鬧鐘圖標(biāo)
mService.setIcon("alarm_clock",R.drawable.stat_notify_alarm, 0);
mService.setIconVisibility("alarm_clock", false);
……..
// StatusBarPolicy構(gòu)造方法中注冊(cè)鬧鐘改變廣播
filter.addAction(Intent.ACTION_ALARM_CHANGED);
…....
//改變鬧鐘圖標(biāo)
private final void updateAlarm(Intent intent) {
boolean alarmSet = intent.getBooleanExtra(“alarmSet”, false);
mService.setIconVisibility(“alarm_clock”, alarmSet);
}
StatusBarPolicy只是一個(gè)策略管理,實(shí)際的功能是StatusBarService來實(shí)現(xiàn)的,。
StatusBarService
初始化時(shí)初始化了一個(gè)用于顯示
statusbar 的StatusBarView,。
StatusBarView
里面定義了
icon名字,的顯示順序,,對(duì)應(yīng)的png
圖等,,在
StatusBarService調(diào)用
makeStatusBarView
方法時(shí)實(shí)現(xiàn)
statusbar的初始化
4.3.2通過遠(yuǎn)程代理方式
StatusBarManager有一個(gè)更新圖標(biāo)的方法:
public void updateIcon(IBinder key, String slot, int iconId, int iconLevel),不過
StatusBarManager
并未把方法公開在
sdk 中,,但是應(yīng)該有方法可以訪問的,。
public void updateIcon(IBinder key, String slot, int iconId, int iconLevel) {
try {
mService.updateIcon(key, slot, mContext.getPackageName(), iconId, iconLevel);
} catch (RemoteException ex) {
throw new RuntimeException(ex);
}
}
mService 是StatusBarManager的一個(gè)成員變量,
StatusBarManager
被構(gòu)建的時(shí)候被賦值,,他是
IStatusBar
的一個(gè)代理對(duì)象
StatusBarManager(Context context) {
mContext = context;
mService = IStatusBar.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
}
4.4 拖動(dòng)刷新
4.4.1 StatusbarView從被點(diǎn)擊到拖動(dòng)
從點(diǎn)擊StatusBar會(huì)出現(xiàn)新的View,,它的流程如下:
StatusBarView 就是StatusBar 所代表的View ,那么查看它的代碼,,看它處理點(diǎn)擊的方法,。
它屬性變量保存了StatusBarService的引用mService,它的點(diǎn)擊處理函數(shù)onTouchEvent()和onInterceptTouchEvent()都會(huì)調(diào)用到StatusBarService類中的interceptTouchEvent()方法,。
當(dāng)我們點(diǎn)擊StatusBar 時(shí),,會(huì)先走到onInterceptTouchEvent() 這個(gè)函數(shù),而且這個(gè)函數(shù)只會(huì)在第一次走到,,然后會(huì)走到onTouchEvent() 方法,,這個(gè)方法每收到一個(gè)TouchEvent()
就會(huì)走到,因此會(huì)走到多次,。
函數(shù)onInterceptTouchEvent() 的處理:
1 ,、調(diào)用到StatusBarService 中的interceptTouchEvent() ,在這里又會(huì)走到event.getAction()
== MotionEvent.ACTION_DOWN 分支,,在分支中,,由于mExpanded == false 且y < hitSize會(huì)繼續(xù)調(diào)用prepareTracking(y) 。
2 ,、函數(shù)prepareTracking() 處理:這里由于mExpanded == false所以會(huì)向H 中發(fā)送MSG_ANIMATE_REVEAL
消息,,進(jìn)入StatusBarService 自己的消息循環(huán)。執(zhí)行doRevealAnimation() 函數(shù),。
3 ,、函數(shù)doRevealAnimation() 處理:這個(gè)實(shí)現(xiàn)的功能很簡單,,就是在TrackingView( 就是點(diǎn)擊時(shí)StatusBar
下出現(xiàn)的View) 還沒有完全顯示出來的時(shí)候,通過動(dòng)畫的方式,,一點(diǎn)一點(diǎn)的將TrackingView 顯示出來,。
當(dāng)我們手指離開時(shí)調(diào)用順序如下:
1 、StatusBarView :onTouchEvent() ,,此時(shí)Action != MotionEvent.ACTION_DOWN
走到 StatusBarService :interceptTouchEvent() ,;
2 、interceptTouchEvent() 中會(huì)走到分支else if (mTracking) ,;
3 ,、由于ACTION_UP所以會(huì)調(diào)用performFling() ,在這里會(huì)向Handler 發(fā)送
MSG_ANIMATE消息,,然后進(jìn)入函數(shù)doAnimation() ,。
4 、在doAnimation() 由于mAnimY < mStatusBarView.getHeight() 分支成立,,會(huì)繼續(xù)調(diào)用updateExpandedViewPos(0)
和performCollapse();
5 ,、在performCollapse() 中,通過mTrackingView.setVisibility(View.GONE)實(shí)現(xiàn)了讓mTrackingView
的隱藏,,其實(shí)這個(gè)函數(shù)還實(shí)現(xiàn)了其他的View 的隱藏,,比如我們點(diǎn)擊后進(jìn)行拖動(dòng)所出現(xiàn)的其他View 。
4.5 遠(yuǎn)程接口
4.5.1 Statusbar遠(yuǎn)程接口簡介
StatusBarManagerService通過使用
IStatusBar
的
aidl調(diào)用 CommandQueue 在
CommandQueue 中定義Callbacks
StatusBarService實(shí)現(xiàn)了
CommandQueue
中
Callbacks的回調(diào)
public interface Callbacks {
public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon);
public void updateIcon(String slot, int index, int viewIndex,
StatusBarIcon old, StatusBarIcon icon);
public void removeIcon(String slot, int index, int viewIndex);
public void addNotification(IBinder key, StatusBarNotification notification);
public void updateNotification(IBinder key, StatusBarNotification notification);
public void removeNotification(IBinder key);
public void disable(int state);
public void animateExpand();
public void animateExpandToggles(boolean needForceStatusBar);
public void animateCollapse();
public void showSIMIndicator(String businessType);
public void hideSIMIndicator();
}
由上述源碼我們可以得出在StatusbarService.java中都有增加
/
刪除狀態(tài)欄圖標(biāo),、增加/
更新
/刪除
notification
,、禁用
Statusbar、
SIM
指示信息的隱藏和顯示,、還有Statusbar拖動(dòng)動(dòng)畫的實(shí)現(xiàn),。
4.5.2 StatusBarManager的使用
如4.3.2
所講,通過遠(yuǎn)程代理方式更新狀態(tài)欄圖標(biāo),,因?yàn)?/span>
StatusBarManager
方法在
SDK中并未公開如下就講述對(duì)StatusBarManager的使用方法,。
在StatusbarService.java中的的
disable
方法,就實(shí)現(xiàn)并擴(kuò)展了了StatusbarManager的
disable
所實(shí)現(xiàn)的功能(如statusbar的禁止拖動(dòng),,不顯示通知圖標(biāo),,不顯示ticker
等)。
- <SPAN style="FONT-SIZE: x-small">
-
-
- public void disable(int state) {
- final int old = mDisabled;
- final int diff = state ^ old;
- mDisabled = state;
- if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
- if ((state & StatusBarManager.DISABLE_EXPAND) != 0) {
- if (SPEW) Slog.d(TAG, "DISABLE_EXPAND: yes");
- animateCollapse();
- }
- }
- if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
- if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
- if (SPEW) Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
- if (mTicking) {
- mTicker.halt();
- } else {
- setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out);
- }
- } else {
- if (SPEW) Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
- if (!mExpandedVisible) {
- setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
- }
- }
- } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
- if (mTicking && (state & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
- if (SPEW) Slog.d(TAG, "DISABLE_NOTIFICATION_TICKER: yes");
- mTicker.halt();
- }
- }
- }
- 下面在將一種簡單的對(duì)StatusBarManager的引用方法:
- Object service = getSystemService ("statusbar");
- try {
- Class <?> statusBarManager = Class.forName
- ("android.app.StatusBarManager");
- Method expand = statusBarManager.getMethod ("disable",int.class);
- expand.invoke (service,0x00000001);
- } catch (Exception e) {
- e.printStackTrace();
- }</SPAN>
- <span style="font-size:10px;"><span style="font-size:10px;">
-
-
- public void disable(int state) {
- final int old = mDisabled;
- final int diff = state ^ old;
- mDisabled = state;
- if ((diff & StatusBarManager.DISABLE_EXPAND) != 0) {
- if ((state & StatusBarManager.DISABLE_EXPAND) != 0) {
- if (SPEW) Slog.d(TAG, "DISABLE_EXPAND: yes");
- animateCollapse();
- }
- }
- if ((diff & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
- if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
- if (SPEW) Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
- if (mTicking) {
- mTicker.halt();
- } else {
- setNotificationIconVisibility(false, com.android.internal.R.anim.fade_out);
- }
- } else {
- if (SPEW) Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
- if (!mExpandedVisible) {
- setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
- }
- }
- } else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
- if (mTicking && (state & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
- if (SPEW) Slog.d(TAG, "DISABLE_NOTIFICATION_TICKER: yes");
- mTicker.halt();
- }
- }
- }
- 下面在將一種簡單的對(duì)StatusBarManager的引用方法:
- Object service = getSystemService ("statusbar");
- try {
- Class <?> statusBarManager = Class.forName
- ("android.app.StatusBarManager");
- Method expand = statusBarManager.getMethod ("disable",int.class);
- expand.invoke (service,0x00000001);
- } catch (Exception e) {
- e.printStackTrace();
- }</span></span>
權(quán)限:
<uses-permission android:name="android.permission.STATUS_BAR"/>
<uses-permission android:name="android.permission.DISABLE_STATUS_BAR"/>
這個(gè)方法也是禁用statusbar 的一種方法,。
五,、重要文件的介紹
StatusBarManagerService.java
|
StatusBarManagerService 是服務(wù)端
StatusBarService 的管理者
|
顧名思義,StatusBarManagerService是
StatusBarService的管理者,,是StatusBarService與外界通信的橋梁,,如4.2所講。
在
StatusBarManagerService.java
中,,有 addNotification,,
removeNotification,updateNotification
等方法用于管理傳遞給他的通知對(duì)象。這個(gè)類是一些管理方法,,實(shí)際執(zhí)行相關(guān)動(dòng)作的是在IStatusBar.java里面,,這個(gè)是
framework/base/core/java/com /android/internal/statusbar/IStatusBar.aidl自動(dòng)生成的用于
IPC
的類。
|
表 5.1
StatusBarService.java
|
StatusBarservice 是Statusbar
的核心
|
StatusBarService這個(gè)服務(wù)是Statusbar模塊的中心點(diǎn),,所有關(guān)于圖標(biāo)的加載,、更新、刪除等處理,,與應(yīng)用的交互,,對(duì)通知信息的處理,動(dòng)畫的完成等都是建立在StatusBarService這個(gè)基礎(chǔ)之上的,。
|
表 5.2
StatusBarPolicy.java
|
StatusBarPolicy 負(fù)責(zé)狀態(tài)欄顯示的策略管理
|
Android中狀態(tài)欄上有很多圖標(biāo),,這些圖標(biāo)什么時(shí)候顯示什么時(shí)候不顯示,這些都是StatusBarPolicy
來管理的,。
StatusBarPolicy的構(gòu)造函數(shù)里初始化了好幾個(gè)圖標(biāo),,如鬧鐘icon,信號(hào)欄icon等,。默認(rèn)時(shí)有很多圖標(biāo)是不顯示的,,需要顯示時(shí)再進(jìn)行更新。StatusBarPolicy調(diào)用registerReceiver
注冊(cè)了感興趣的intent,當(dāng)感興趣的intent發(fā)生時(shí),,對(duì)圖標(biāo)進(jìn)行更新,。
StatusBarPolicy只是一個(gè)策略管理,實(shí)際的功能是StatusBarService來實(shí)現(xiàn)的,。StatusBarService初始化時(shí)初始化了一個(gè)用于顯示statusbar的StatusBarView,。StatusBarView里面定義了icon名字,的顯示順序,,對(duì)應(yīng)的png圖等,,在StatusBarService調(diào)用makeStatusBarView方法時(shí)實(shí)現(xiàn)statusbar的初始化。
|
表 5.3
CommandQueue.java
|
CommandQueue 是StatusBarservice
和StatusBarManagerService
交互的樞紐
|
IStatusBar.java里面對(duì)應(yīng)的方法是用CommandQueue
的接口callback
的形式調(diào)用的,,
callback的實(shí)現(xiàn)在對(duì)應(yīng)的服務(wù)提供類也就是StatusBarService.java中提供的,。
最終執(zhí)行狀態(tài)欄更新通知等事件都是在實(shí)現(xiàn)的CommandQueue.Callbacks里面執(zhí)行。
|
表 5.4
六,、總結(jié)
本文檔主要講述了SystemUI
模塊中
Statusbar模塊的主要功能和實(shí)先步驟,,文檔中介紹了Statusbar的功能,使用方法,,模塊框架,,以及模塊一些實(shí)現(xiàn)的主要流程等。
希望大家在閱讀文檔的過程中,如果發(fā)現(xiàn)文檔的缺點(diǎn)和錯(cuò)誤,,請(qǐng)及時(shí)反饋,,我將以最快的速度加以改進(jìn)。