Android O 8.0 Notification 源码分析(一)

最近在搞SystemUI。这几天把Notification的流程整理了一遍。好记性不如烂博客。

本编主要介绍生成过程:App create Notification --> System's  NotificationManagerService

另外一编介绍展示过程:System Notification --> SystemUI --> Display Notifications,

《Android O 8.0 Notification 源码分析(二)》

值得注意的是在AndroidO 8.0中,notification有了改变,使用NotificationChannel类。具体使用参加下面的demo.

下面直接上流程图。

上图为Apps产生Notification怎么发送到系统的中的流程图。

下面看代码:

步骤1,2,3,4 : MainActivity生产Notification准备工作。

 
  1.  
  2. @RequiresApi(api = Build.VERSION_CODES.O)

  3. public void sendNotification(View view) {

  4. String id = "channel_0";

  5. String des = "111";

  6. NotificationChannel channel = new NotificationChannel(id, des, NotificationManager.IMPORTANCE_MIN);

  7. notificationManager.createNotificationChannel(channel);

  8. Notification notification = new Notification.Builder(MainActivity.this, id)

  9. .setContentTitle("Base Notification View")

  10. .setContentText("您有一条新通知")

  11. .setSmallIcon(R.drawable.jd_icon)

  12. .setStyle(new Notification.MediaStyle())

  13. .setAutoCancel(false)

  14. .build();

  15. notificationManager.notify(1, notification);

  16. }

步骤5,6: NotificationManager发送notification。最后调用到notifyAsUser()方法:

 
  1. public void notifyAsUser(String tag, int id, Notification notification, UserHandle user)

  2. {

  3. // 获取NotificationManager的Service

  4. INotificationManager service = getService();

  5. String pkg = mContext.getPackageName();

  6. ...

  7. notification.reduceImageSizes(mContext);

  8. ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);

  9. boolean isLowRam = am.isLowRamDevice();

  10. final Notification copy = Builder.maybeCloneStrippedForDelivery(notification, isLowRam);

  11. try {

  12. service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id, copy, user.getIdentifier());

  13. } catch (RemoteException e) {

  14. throw e.rethrowFromSystemServer();

  15. }

  16. }

步骤7,8,9,10: 根据Android的规律,INotificationManager对应的service为NotificationManagerService.最后直接enqueueNotificationInternal()方法。

 
  1. void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid, final int callingPid, final String tag, final int id, final Notification notification, int incomingUserId) {

  2. if (DBG) {

  3. Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id

  4. + " notification=" + notification);

  5. }

  6. checkCallerIsSystemOrSameApp(pkg);

  7.  
  8. ...

  9.  
  10. final StatusBarNotification n = new StatusBarNotification(

  11. pkg, opPkg, id, tag, notificationUid, callingPid, notification,

  12. user, null, System.currentTimeMillis());

  13. // 把notification的对象做了备份

  14. final NotificationRecord r = new NotificationRecord(getContext(), n, channel);

  15.  
  16. if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0

  17. && (channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0

  18. && (r.getImportance() == IMPORTANCE_MIN || r.getImportance() == IMPORTANCE_NONE)) {

  19. // Increase the importance of foreground service notifications unless the user had an

  20. // opinion otherwise

  21. if (TextUtils.isEmpty(channelId)

  22. || NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {

  23. r.setImportance(IMPORTANCE_LOW, "Bumped for foreground service");

  24. } else {

  25. channel.setImportance(IMPORTANCE_LOW);

  26. mRankingHelper.updateNotificationChannel(pkg, notificationUid, channel, false);

  27. r.updateNotificationChannel(channel);

  28. }

  29. }

  30.  
  31. if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,

  32. r.sbn.getOverrideGroupKey() != null)) {

  33. return;

  34. }

  35.  
  36. // Whitelist pending intents.

  37. if (notification.allPendingIntents != null) {

  38. final int intentCount = notification.allPendingIntents.size();

  39. if (intentCount > 0) {

  40. final ActivityManagerInternal am = LocalServices

  41. .getService(ActivityManagerInternal.class);

  42. final long duration = LocalServices.getService(

  43. DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();

  44. for (int i = 0; i < intentCount; i++) {

  45. PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);

  46. if (pendingIntent != null) {

  47. am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),

  48. WHITELIST_TOKEN, duration);

  49. }

  50. }

  51. }

  52. }

  53.  
  54. mHandler.post(new EnqueueNotificationRunnable(userId, r));

  55. }

步骤11:handler.post( EnqueueNotificationRunnable run):

 
  1. @Override

  2. public void run() {

  3. synchronized (mNotificationLock) {

  4. mEnqueuedNotifications.add(r);

  5. scheduleTimeoutLocked(r);

  6.  
  7. final StatusBarNotification n = r.sbn;

  8. ...

  9.  
  10. // tell the assistant service about the notification

  11. if (mAssistants.isEnabled()) {

  12. mAssistants.onNotificationEnqueued(r);

  13. mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),

  14. DELAY_FOR_ASSISTANT_TIME);

  15. } else {

  16. mHandler.post(new PostNotificationRunnable(r.getKey()));

  17. }

  18. }

  19. }

步骤12,13:handler.post( PostNotificationRunnable run):

 
  1. @Override

  2. public void run() {

  3. synchronized (mNotificationLock) {

  4. try {

  5. NotificationRecord r = null;

  6. int N = mEnqueuedNotifications.size();

  7. for (int i = 0; i < N; i++) {

  8. final NotificationRecord enqueued = mEnqueuedNotifications.get(i);

  9. if (Objects.equals(key, enqueued.getKey())) {

  10. r = enqueued;

  11. break;

  12. }

  13. }

  14. ...

  15. mNotificationsByKey.put(n.getKey(), r);

  16. ...

  17. //没有SmallIcon会失败

  18. if (notification.getSmallIcon() != null) {

  19. StatusBarNotification oldSbn = (old != null) ? old.sbn : null;

  20. mListeners.notifyPostedLocked(n, oldSbn);

  21. ...

  22. } else {

  23. Slog.e(TAG, "Not posting notification without small icon: " + notification);

  24. ...

  25. }

  26.  
  27. buzzBeepBlinkLocked(r);

  28. } finally {

  29. int N = mEnqueuedNotifications.size();

  30. for (int i = 0; i < N; i++) {

  31. final NotificationRecord enqueued = mEnqueuedNotifications.get(i);

  32. if (Objects.equals(key, enqueued.getKey())) {

  33. mEnqueuedNotifications.remove(i);

  34. break;

  35. }

  36. }

  37. }

  38. }

  39. }

步骤14:调用NotificationManagerService.NotificationListeners --> notifyPostedLocked() --> notifyPosted() --> NotificationListenerService.onNotificationPosted();

OK,上面描述了Notification从App应用,产生到系统的流程。

另外一编讲诉的为SystemUI中怎样展示Notification

《Android O 8.0 Notification 源码分析(二)》

 

原文地址:https://blog.csdn.net/yangzs516/article/details/81490204

猜你喜欢

转载自blog.csdn.net/f2006116/article/details/82145853