好久没写东西,我得承认,是自己懒了。
解过几个statusbar的bug,觉得notification还是挺有意思的,分析一下流程,以作备忘吧。
- 通知的接收
1. notification由系统或第三方应用封装发出notificationManager.notify()。
2. 通知进入一个队列NotificationManagerService.enqueueNotificationInternal()。
3. 在上面方法里面会发现一个熟悉的身影,就是mStatusBar,它是StatusBarManagerService的化身。调用mBar.addNotification(key,notification);
4. 通过linux查找命令先定位IStatusBar.aidl的位置,然后在该最外路径下搜索IStatusBar.Stub可以找到具体实现它的java文件,这里我们找到了CommandQueue,java。然后调用CommandQueue. addNotification(),该方法利用handle发出一个消息:MSG_ADD_NOTIFICATION,跳转到回调函数addNotification(ne.key,ne.notification); PhoneStatusBar实现了这个回调方法。
5. 以上一个通知算是被系统statusBar所接收到。
- 通知的statusbar显示
public void addNotification(IBinder key, StatusBarNotification notification) {
// 1.初始化一个状态栏图标来体现该notification
StatusBarIconView iconView = addNotificationViews(key, notification);
if (iconView == null) return;
}
if (immersive) {
//无实际作用,4.1会被注释
} else if (notification.notification.fullScreenIntent != null) {
// 2.not immersive & a full-screen alert should be shown,比如电话和闹钟的通知灰常nb
Slog.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");
try {
notification.notification.fullScreenIntent.send();
} catch (PendingIntent.CanceledException e) {
}
} else {
// 3.usual case: status bar visible & not immersive。普通notification都走这道,用一个动画的形式显示该通知的文字信息。
tick(notification);
}
// 4.Recalculate the position of the sliding windows and the titles.
setAreThereNotifications();
// 5.刷新一下ExpandedView的位置,
updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
}
- 通知的expendView显示
代码都在上一步走完了。
条目的添加是addNotificationViews():
// 1.Construct the expanded view.
NotificationData.Entry entry = new NotificationData.Entry(key, notification, iconView);
view的刷新是addNotification():
// 5.刷新一下ExpandedView的位置,
updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
- 通知的更新
同样是从CommandQueue. updateNotification()开始走,然后到PhoneStatusBar. updateNotification()。代码流程和通知的添加几乎一致,只是没有add view这一步。
- 通知的发送
protected void sendNotification() {
// TODO Auto-generated method stub
Log.e(TAG, "-----sendNotifications----");
// 1.实例化intent和获取通知的服务。
Intent mIntent = new Intent();
NotificationManager notificationManager = (NotificationManager) mContext
.getSystemService(Context.NOTIFICATION_SERVICE);
mIntent.setClass(mContext, ShowHello.class);
PendingIntent mPendingIntent = PendingIntent.getActivity(mContext, 0, mIntent, 0);
// 2.设置通知的相应属性
// mNotification.fullScreenIntent = mPendingIntent;//这句话的作用是决定通知是否自动弹出那个可跳转的activity。
mNotification.defaults |= Notification.DEFAULT_SOUND;//设置通知是否播放声音。
mNotification.flags = Notification.FLAG_ONGOING_EVENT;
// 在4.0的expendview里多显示一张图片,2.3系统会报错
mNotification.largeIcon = BitmapFactory.decodeResource(getResources(), R.drawable.ic_action_search);
// 显示通知调用下面的方法是必须的,但在api11会被deprecated,使用Notification.Builder代替。
mNotification.setLatestEventInfo(mContext, tick, TAG, mPendingIntent);
// 3.唤醒通知
notificationManager.notify(R.drawable.ic_launcher, mNotification);
}
- 各个主要版本的变化
分析时是以4.0为准,为了兼顾其他也顺便看了一遍2.3,4.1的流程,notification总的来说没有大的变化,API升级后有些方法被弃用有了新的实现,与之相关的就是状态栏为了适配pad和更高分辨率机型进行了一些重构,体现在我们这里就是2.3的statusBarService在4.0后改名为phoneStatueBar。4.0加入的immersive模式在4.1被彻底废除。
- 三言两语
Notification的前世来生也就这样,生平中有过纠结的是NotificationManager,NotificationManagerService,StatusBarManagerService,phoneStatueBar,CommandQueue。