Android 源码分析Notification的notify

在上一篇文章Android获取第三方音乐播放器的音乐信息的末尾,提到可以通过捕获第三方音乐发送的的Notification,来获取到当前播放的歌曲的信息。先分析下Notification的更新机制。

涉及Service:

 StatusBarManagerService
   NotificationManagerService 


这个两个service都会在frameworks/base/services/java/com/android/server/SystemServer.java文件里面进行启动的

class ServerThread extends Thread {  
 public void run() {
......
     StatusBarManagerService statusBar = null;
     NotificationManagerService notification = null;
......
    statusBar = new StatusBarManagerService(context, wm);
    ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar);
......
    notification = new NotificationManagerService(context, statusBar, lights);                   
    ServiceManager.addService(Context.NOTIFICATION_SERVICE, notification);

......
 
   }

}

下面开始跟踪Notification的Notify流程。

1.

当在Activity里面创建一个Notification,并Notify

NotificationManager nm = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);               
Notification n = new Notification(R.drawable.chat, "Hello,there!", System.currentTimeMillis());             
n.flags = Notification.FLAG_AUTO_CANCEL;                
Intent i = new Intent(arg0.getContext(), NotificationShow.class);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_NEW_TASK);           
//PendingIntent
PendingIntent contentIntent = PendingIntent.getActivity(
        arg0.getContext(), 
        R.string.app_name, 
        i, 
        PendingIntent.FLAG_UPDATE_CURRENT);
                 
n.setLatestEventInfo(
        arg0.getContext(),
        "Hello,there!", 
        "Hello,there,I'm john.", 
        contentIntent);
nm.notify(R.string.app_name, n);

2.调用NotificationManager.notify,进入notify 方法

 public void notify(int id, Notification notification)
    {
        notify(null, id, notification);
    }

 public void notify(String tag, int id, Notification notification)
    {
......
         INotificationManager service = getService();

......
         service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
              notification, idOut, UserHandle.myUserId());
......         
 }

3.在调用notify(String tag, int id, Notification notification)时,会调用getService()

static public INotificationManager getService()
78    {
79        if (sService != null) {
80            return sService;
81        }
82        IBinder b = ServiceManager.getService("notification");
83        sService = INotificationManager.Stub.asInterface(b);
84        return sService;
85    }
这里发现,会调用ServiceManager.getService("notification"), 这样就会获取到文章刚开始讲的NotificationManagerService 的一个binder对象。获取回到第二步调用service.enqueueNotificationWithTAG.

4.进入NotificationManagerService的enqueueNotificationWithTAG

public void enqueueNotificationWithTag(String pkg, String basePkg, String tag, int id,
1621            Notification notification, int[] idOut, int userId)
1622    {
1623        enqueueNotificationInternal(pkg, basePkg, Binder.getCallingUid(), Binder.getCallingPid(),
1624                tag, id, notification, idOut, userId);
1625    }

1634    public void enqueueNotificationInternal(final String pkg, String basePkg, final int callingUid,
1635            final int callingPid, final String tag, final int id, final Notification notification,
1636            int[] idOut, int incomingUserId)
1637    {
......
		final StatusBarNotification n = new StatusBarNotification(
1755                            pkg, id, tag, callingUid, callingPid, score, notification, user);

1792                                mStatusBar.updateNotification(r.statusBarKey, n);
1793                           
......
         }
在这个方法里,会将前面传递进来的Notification封装成一个StatusBarNotification对象,然后调用mStatusBar.updateNotification去更新,这个mStatusBar是什么?

5. 文章最开始提到会在ServerThread里面添加NotificationManagerService,在创建的NotificationManagerService的时候,会调用它的构造函数

 NotificationManagerService(Context context, StatusBarManagerService statusBar,
1291            LightsService lights)
1292    {
       	....... 
	}
这里面就会传递进来,在ServerThread里刚刚创建的StatusBarManagerService. 所以在第4步的时候我们能够调用mStatusBar.updateNotification()。

6. StatusBarManagerService 中mStatusBar.updateNotification()方法

  public void updateNotification(IBinder key, StatusBarNotification notification) {
512        synchronized (mNotifications) {
516            mNotifications.put(key, notification);
......
519                    mBar.updateNotification(key, notification);
......
524    }
这里会调用mBar.updateNotification(),mBar是什么?

7. StatusBarManagerService 中 mBar对象

volatile IStatusBar mBar;

  // Callbacks from the status bar service.
428    // ================================================================================
429    public void registerStatusBar(IStatusBar bar, StatusBarIconList iconList,
430            List<IBinder> notificationKeys, List<StatusBarNotification> notifications,
431            int switches[], List<IBinder> binders) {
......  

上面发现有个registerStatusBar方法,会传递进来一个IStatusBar 对象,那这个方法会在哪里调用呢?

8.  在StatusBarManagerService中,我们发现调用mBar对象都是去处理StatusBar的UI,那这个StatusBar是哪里的?SystemUI里面的。检索下SystemUI的代码,果然发现在

BaseStatusBar里面:

 public void start() { 
mBarService.registerStatusBar(mCommandQueue, iconList, notificationKeys, notifications,
250                    switches, binders);
}
在这里registerStatusBar, 而这个mCommandQueue参数就是前面IStatusBar对象。

9. mCommanQueue变量

 protected CommandQueue mCommandQueue;

28/**
29 * This class takes the functions from IStatusBar that come in on
30 * binder pool threads and posts messages to get them onto the main
31 * thread, and calls onto Callbacks.  It also takes care of
32 * coalescing these calls so they don't stack up.  For the calls
33 * are coalesced, note that they are all idempotent.
34 */
35public class CommandQueue extends IStatusBar.Stub{
/**
78     * These methods are called back on the main thread.
79     */
80    public interface Callbacks {
81        public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon);
82        public void updateIcon(String slot, int index, int viewIndex,
83                StatusBarIcon old, StatusBarIcon icon);
84        public void removeIcon(String slot, int index, int viewIndex);
85        public void addNotification(IBinder key, StatusBarNotification notification);
86        public void updateNotification(IBinder key, StatusBarNotification notification);
87        public void removeNotification(IBinder key);
88        public void disable(int state);
89        public void animateExpandNotificationsPanel();
90        public void animateCollapsePanels(int flags);
91        public void animateExpandSettingsPanel();
92        public void setSystemUiVisibility(int vis, int mask);
93        public void topAppWindowChanged(boolean visible);
94        public void setImeWindowStatus(IBinder token, int vis, int backDisposition);
95        public void setHardKeyboardStatus(boolean available, boolean enabled);
96        public void toggleRecentApps();
97        public void preloadRecentApps();
98        public void showSearchPanel();
99        public void hideSearchPanel();
100        public void cancelPreloadRecentApps();
101        public void setNavigationIconHints(int hints);
102        public void setWindowState(int window, int state);
103    }

}

发现这个方法继承IStatusBar.stub,里面有一连串的回调函数。这些回调函数在BaseStatusBar里面实现的

public abstract class BaseStatusBar extends SystemUI implements
79        CommandQueue.Callbacks {

10. 回到第6步,当在StatusBarManagerService中调用mBar.updateNotification时,根据7,8,9的分析,最终会调用在BaseStatusBar里面实现的UpdateNotification方法

 updateNotification(IBinder key, StatusBarNotification notification) {
......
}
在这里会将Notification显 示在StatusBar上面。


这里面主要涉及到两个NotificationManagerService和StatusBarManager的交互。

第一步。

系统启动时在ServerThread里生成StatusBarManagerService和NotificationManagerService,并将StatusBarManagerService对象作为一个参数传递到NotificationManagerService的构造方法中。

系统加载应用,SystemUI中, BaseStatusBar实现回调函数CommandQueue.Callbacks, 并调用StatusBarManagerService的registerStatusBar方法,将CommandQueue对象传递进去

第二步

Activity里调用notify方法,在NotificationManagerService将Notification封装成StatusBarNotification。

NotificationManagerService调用statusBarManagerService的updateNotification()。

第三步

StatusBarManagerService调用CommandQueue实现的回调函数,最终将Notification显示在SystemUI上面。


下一篇文章会讲怎么实现捕获Notification的内容,从而实现采集第三方播放器播放音乐的信息

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值