最近在搞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 源码分析(二)》