Android 4.0 Notification
通常,在手機有未接電話,收到消息或者掛著退出主界面的QQ,在狀態欄會有一個Notification,那么,這個notification如何產生的?
通常做法:
Intent?intent?=?new?Intent();
????????intent.setClass(this,?Noti.class);
//一般而言,對于需要點擊Notification需要遷移到對應的View的需要下面這個操作
????????intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
????????
????????PendingIntent?mPendingIntent?=?PendingIntent.getActivity(this,?0,?intent,?0);
????????
????????Notification?mNotification?=?new?Notification();
????????mNotification.icon?=?R.drawable.presence_online;//icon?的id
????????mNotification.tickerText?=?"Online";
????????mNotification.defaults?=?Notification.DEFAULT_SOUND?;
????????mNotification.flags?=?Notification.FLAG_AUTO_CANCEL;
????????
????????mNotification.setLatestEventInfo(this,?"QQ",?"Online",?mPendingIntent);
????mNotificationManager.notify(0,?mNotification);
在android手機中,有一個Notification類,這個類從根本上講只是一個記錄我們需要在狀態欄顯示Notification?icon的一些信息,比如:要顯示的Icon的id,led燈閃爍以及閃爍顏色和閃爍時間,讓手機產生振動等。Notification的flag有FLAG_SHOW_LIGHTS,FLAG_AUTO_CANCEL等。有關Notification有三個主要的函數:setLatestEventInfo,notify和cancel
在下面這段代碼中,RemoteViews?是顯示在擴展狀態欄上的,也就是將狀態欄拉下時顯示的Notification,
contentView.setImageViewResource(com.android.internal.R.id.icon,?this.icon)則是將我們設定的icon賦給id為com.android.internal.R.id.icon的ImageView,以便在statusBar中調用顯示。同樣下面都是將本地信息設置為全局信息以便在statusbar中顯示。特別要提一下contentIntent是一個PendingIntent,它負責在點擊Notification時遷移的View。Notification.java:
public?void?setLatestEventInfo(Context?context,
????????????CharSequence?contentTitle,?CharSequence?contentText,?PendingIntent?contentIntent)?{
??RemoteViews?contentView?=?new?RemoteViews(context.getPackageName(),
??????????????com.android.internal.R.layout.status_bar_latest_event_content);
??if?(this.icon?!=?0)?{//實際上就是要顯示的消息對應的icon
??????????contentView.setImageViewResource(com.android.internal.R.id.icon,?this.icon);
??}
??if?(contentTitle?!=?null)?{//Notification對應的title
????????????contentView.setTextViewText(com.android.internal.R.id.title,?contentTitle);
??}
??if?(contentText?!=?null)?{//狀態所對應的下標題
???????????contentView.setTextViewText(com.android.internal.R.id.text,?contentText);
?}
?if?(this.when?!=?0)?{
??????????contentView.setLong(com.android.internal.R.id.time,?"setTime",?when);
?????}
?this.contentView?=?contentView;
?this.contentIntent?=?contentIntent;
}???
那么它是如何顯示到狀態欄上的?
NotificationManager調用Notify函數?:
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)?{
????????}
????}
最重要的是,在NotificationManagerService.java中,service.enqueueNotificationWithTag(pkg,?tag,?id,?notification,?idOut);它調用NotificationManagerService中方法enqueueNotificationInternal發出聲音振動和燈光,這都只要調用相關的系統服務做就可以了。
以何種方式進行通知狀態欄顯示的?
???if?(notification.icon?!=?0)?{
????????????????StatusBarNotification?n?=?new?StatusBarNotification(pkg,?id,?tag,
????????????????????????r.uid,?r.initialPid,?notification);
????????????????if?(old?!=?null?&&?old.statusBarKey?!=?null)?{
????????????????????r.statusBarKey?=?old.statusBarKey;
????????????????????long?identity?=?Binder.clearCallingIdentity();
????????????????????try?{
????????????????????????mStatusBar.updateNotification(r.statusBarKey,?n);
????????????????????}
????????????????????finally?{
????????????????????????Binder.restoreCallingIdentity(identity);
????????????????????}
????????????????}?else?{
????????????????????long?identity?=?Binder.clearCallingIdentity();
????????????????????try?{
????????????????????????r.statusBarKey?=?mStatusBar.addNotification(n);
????????????????????????mAttentionLight.pulse();
????????????????????}
????????????????????finally?{
????????????????????????Binder.restoreCallingIdentity(identity);
????????????????????}
????????????????}
????????????????sendAccessibilityEvent(notification,?pkg);
在這里調用了statusbarService.java的updateNotification方法,又調用addNotificationViews將icon顯示到狀態欄并顯示相關信息。
updateNotification這個方法中調用addNotificationViews:
//?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;
????????}
至此,就完成了添加一個icon到Statusbar,同時還有text、title等等。
以DownLoadProvider下載完成后點擊下載的Notification,然后消失Notification為例解釋FLAG_AUTO_CANCEL原因:
在DownLoadProvider這個app中,DownLoadService會創建一個用于更新下載完成Notification的類DownloadNotification,還有一個開啟的線程:updateThread,在這個線程中調用了mNofier.updateNofication(mDownloads.values());然后再DownloadNotification.java中更新下載進度和完成狀態,當下載完成時會在StatusBar上顯示下載完成這個icon。
那么,系統如何維護狀態欄上的Notification呢?也就是如何點擊后取消這個Notification呢?
在StatusBarService下private?class?Launcher?implements?View.OnClickListener
是監聽點擊StatusBarService的函數,當點擊這個Notification時,在void?OnClick()方法中有這樣的callback:mBarService.onNotificationClick(mPkg,?mTag,?mId);
mBarService是這樣定義的:
IStatusBarService?mBarService?=?IStatusBarService.Stub.asInterface(
????????????????ServiceManager.getService(Context.STATUS_BAR_SERVICE));
這就意味著mBarService使用的是StatusbarManagerService.java中定義的接口,如下:
public?interface?NotificationCallbacks?{
????????void?onSetDisabled(int?status);
????????void?onClearAll();
????????void?onNotificationClick(String?pkg,?String?tag,?int?id);
????????void?onPanelRevealed();
????????void?onNotificationError(String?pkg,?String?tag,?int?id,
????????????????int?uid,?int?initialPid,?String?message);
}
onNotificationClick是在NotificationManagerService.java中實現的。因此,當點擊statusbar上的Notification時就調用NotificationManagerService中的這個響應函數:
?public?void?onNotificationClick(String?pkg,?String?tag,?int?id)?{
????????cancelNotification(pkg,?tag,?id,?Notification.FLAG_AUTO_CANCEL,
?????????????????Notification.FLAG_FOREGROUND_SERVICE);
?}
cancelNotification定義如下:
????private?void?cancelNotification(String?pkg,?String?tag,?int?id,?int?mustHaveFlags,
????????????int?mustNotHaveFlags)?{
????????EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL,?pkg,?id,?mustHaveFlags);
????????synchronized?(mNotificationList)?{
????????????int?index?=?indexOfNotificationLocked(pkg,?tag,?id);
????????????if?(index?>=?0)?{
????????????????NotificationRecord?r?=?mNotificationList.get(index);
????????????????if?((r.notification.flags?&?mustHaveFlags)?!=?mustHaveFlags)?{
????????????????????return;
????????????????}
????????????????if?((r.notification.flags?&?mustNotHaveFlags)?!=?0)?{
????????????????????return;
????????????????}
????????????????mNotificationList.remove(index);
????????????????cancelNotificationLocked(r);
????????????????updateLightsLocked();
????????????}
????????}
這就解釋了為什么只有設置Notification?的flag為Notification.FLAG_AUTO_CANCEL才能取消Notification。
總結
以上是生活随笔為你收集整理的Android 4.0 Notification的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ubuntu10.10+android
- 下一篇: android4.0 SystemUi系