最近在搞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准备工作。
@RequiresApi(api = Build.VERSION_CODES.O)
public void sendNotification(View view) {
String id = "channel_0";
String des = "111";
NotificationChannel channel = new NotificationChannel(id, des, NotificationManager.IMPORTANCE_MIN);
notificationManager.createNotificationChannel(channel);
Notification notification = new Notification.Builder(MainActivity.this, id)
.setContentTitle("Base Notification View")
.setContentText("您有一条新通知")
.setSmallIcon(R.drawable.jd_icon)
.setStyle(new Notification.MediaStyle())
.setAutoCancel(false)
.build();
notificationManager.notify(1, notification);
}
步骤5,6: NotificationManager发送notification。最后调用到notifyAsUser()方法:
public void notifyAsUser(String tag, int id, Notification notification, UserHandle user)
{
// 获取NotificationManager的Service
INotificationManager service = getService();
String pkg = mContext.getPackageName();
...
notification.reduceImageSizes(mContext);
ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
boolean isLowRam = am.isLowRamDevice();
final Notification copy = Builder.maybeCloneStrippedForDelivery(notification, isLowRam);
try {
service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id, copy, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
步骤7,8,9,10: 根据Android的规律,INotificationManager对应的service为NotificationManagerService.最后直接enqueueNotificationInternal()方法。
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) {
if (DBG) {
Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
+ " notification=" + notification);
}
checkCallerIsSystemOrSameApp(pkg);
...
final StatusBarNotification n = new StatusBarNotification(
pkg, opPkg, id, tag, notificationUid, callingPid, notification,
user, null, System.currentTimeMillis());
// 把notification的对象做了备份
final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0
&& (channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0
&& (r.getImportance() == IMPORTANCE_MIN || r.getImportance() == IMPORTANCE_NONE)) {
// Increase the importance of foreground service notifications unless the user had an
// opinion otherwise
if (TextUtils.isEmpty(channelId)
|| NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
r.setImportance(IMPORTANCE_LOW, "Bumped for foreground service");
} else {
channel.setImportance(IMPORTANCE_LOW);
mRankingHelper.updateNotificationChannel(pkg, notificationUid, channel, false);
r.updateNotificationChannel(channel);
}
}
if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
r.sbn.getOverrideGroupKey() != null)) {
return;
}
// Whitelist pending intents.
if (notification.allPendingIntents != null) {
final int intentCount = notification.allPendingIntents.size();
if (intentCount > 0) {
final ActivityManagerInternal am = LocalServices
.getService(ActivityManagerInternal.class);
final long duration = LocalServices.getService(
DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
for (int i = 0; i < intentCount; i++) {
PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
if (pendingIntent != null) {
am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
WHITELIST_TOKEN, duration);
}
}
}
}
mHandler.post(new EnqueueNotificationRunnable(userId, r));
}
步骤11:handler.post( EnqueueNotificationRunnable run):
@Override
public void run() {
synchronized (mNotificationLock) {
mEnqueuedNotifications.add(r);
scheduleTimeoutLocked(r);
final StatusBarNotification n = r.sbn;
...
// tell the assistant service about the notification
if (mAssistants.isEnabled()) {
mAssistants.onNotificationEnqueued(r);
mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
DELAY_FOR_ASSISTANT_TIME);
} else {
mHandler.post(new PostNotificationRunnable(r.getKey()));
}
}
}
步骤12,13:handler.post( PostNotificationRunnable run):
@Override
public void run() {
synchronized (mNotificationLock) {
try {
NotificationRecord r = null;
int N = mEnqueuedNotifications.size();
for (int i = 0; i < N; i++) {
final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
if (Objects.equals(key, enqueued.getKey())) {
r = enqueued;
break;
}
}
...
mNotificationsByKey.put(n.getKey(), r);
...
//没有SmallIcon会失败
if (notification.getSmallIcon() != null) {
StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
mListeners.notifyPostedLocked(n, oldSbn);
...
} else {
Slog.e(TAG, "Not posting notification without small icon: " + notification);
...
}
buzzBeepBlinkLocked(r);
} finally {
int N = mEnqueuedNotifications.size();
for (int i = 0; i < N; i++) {
final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
if (Objects.equals(key, enqueued.getKey())) {
mEnqueuedNotifications.remove(i);
break;
}
}
}
}
}
步骤14:调用NotificationManagerService.NotificationListeners --> notifyPostedLocked() --> notifyPosted() --> NotificationListenerService.onNotificationPosted();
OK,上面描述了Notification从App应用,产生到系统的流程。
另外一编讲诉的为SystemUI中怎样展示Notification
《Android O 8.0 Notification 源码分析(二)》。