Android 9.0 SystemUI Notification

Android 9.0 SystemUI Notification,第1张

概述本文主要分享SystemUINotification具体如何呈现的?基于AOSP9.0分析。概述在《Android9.0SystemUI主要视图SystemBars》知道通知在折叠时状态栏、下拉状态栏、锁屏都有通知,其中锁屏和下拉状态栏是一个布局,折叠状态栏是在 CollapsedStatusBarFragment,status_bar.xml,PhoneS

本文主要分享 systemUI Notification 具体如何呈现的?基于 AOSP 9.0 分析。

概述

在《AndroID 9.0 systemUI 主要视图 Systembars》知道通知在折叠时状态栏、下拉状态栏、锁屏都有通知,其中锁屏和下拉状态栏是一个布局,折叠状态栏 是在 CollapsedStatusbarFragment,status_bar.xml,PhonestatusbarVIEw,锁屏是 NotificationStackScrollLayout,@+ID/notification_stack_scroller,先来看看锁屏的通知,NotificationStackScrollLayout 是 VIEwGroup,如果来了条通知,肯定是有地方进行 addVIEw,我们就沿着这个思路去 AOSP 寻找答案。

序列图

序列图为来通知到 systemUI 锁屏通知呈现整个流程。

锁屏通知NotificationStackScrollLayout#addContainerVIEw

锁屏是 NotificationStackScrollLayout,直接找 NotificationStackScrollLayout,看到有个 addContainerVIEw方法,一看,果然是目标 addVIEw:

@OverrIDe
public voID addContainerVIEw(VIEw v) {
   addVIEw(v);
}

反查,看到  addContainerVIEw 被 NotificationVIEwHIErarchyManager#updateNotificationVIEws 方法调用了。

NotificationVIEwHIErarchyManager#updateNotificationVIEws
public voID updateNotificationVIEws() {
   ArrayList<NotificationData.Entry> activeNotifications = mEntryManager.getNotificationData()
           .getActiveNotifications();
   ArrayList<ExpandableNotificationRow> toShow = new ArrayList<>(activeNotifications.size());
  //省略其他代码
   for (int i = 0; i < toShow.size(); i++) {
       VIEw v = toShow.get(i);
       if (v.getParent() == null) {
           mVisualStabilityManager.notifyVIEwAddition(v);
           mListContainer.addContainerVIEw(v);
       }
   }
  //省略其他代码
}

这里 mListContainer 是 NotificationListContainer,NotificationStackScrollLayout#addContainerVIEw 进行了重写。

反查, NotificationVIEwHIErarchyManager#updateNotificationVIEws 被 Statusbar#updateNotificationVIEws 方法调用了。

Statusbar#updateNotificationVIEws
@OverrIDe
public voID updateNotificationVIEws() {
   //省略其他代码
   mVIEwHIErarchyManager.updateNotificationVIEws();
   //省略其他代码
   //这里和折叠状态栏相关
   mNotificationIconAreaController.updateNotificationIcons();
}

Statusbar#updateNotificationVIEws 被 NotificationEntryManager#updateNotifications 调用了。

NotificationEntryManager#updateNotifications
public voID updateNotifications() {
   mNotificationData.filterandSort();
   mPresenter.updateNotificationVIEws();
}

presenter 是 NotificationPresenter 对象,从 Statusbar#makeStatusbarVIEw 传过来了,继续看 NotificationEntryManager#updateNotifications 哪里被调用了,是 NotificationEntryManager#addNotificationVIEws。

NotificationEntryManager#addNotificationVIEws
protected voID addNotificationVIEws(NotificationData.Entry entry) {
   if (entry == null) {
       return;
   }
   // Add the expanded vIEw and icon.
   mNotificationData.add(entry);
   tagForeground(entry.notification);
   updateNotifications();
}

//NotificationEntryManager#addNotificationVIEws 由 addEntry 调用了
private voID addEntry(NotificationData.Entry shadeEntry) {
   boolean isheadsUped = shouldPeek(shadeEntry);
   if (isheadsUped) {
       mheadsUpManager.showNotification(shadeEntry);
       // Mark as seen immediately
       setNotificationShown(shadeEntry.notification);
   }
   addNotificationVIEws(shadeEntry);
   mCallback.onNotificationAdded(shadeEntry);
}

NotificationEntryManager#addEntry 由 NotificationEntryManager#onAsyncInflationFinished 调用了。

NotificationEntryManager#onAsyncInflationFinished
@OverrIDe
public voID onAsyncInflationFinished(NotificationData.Entry entry) {
   mPendingNotifications.remove(entry.key);
   // If there was an async task started after the removal, we don't want to add it back to
   // the List, otherwise we might get leaks.
   boolean isNew = mNotificationData.get(entry.key) == null;
   if (isNew && !entry.row.isRemoved()) {
       addEntry(entry);
   } else if (!isNew && entry.row.hasLowPriorityStateUpdated()) {
       mVisualStabilityManager.onLowPriorityUpdated(entry);
       mPresenter.updateNotificationVIEws();
   }
   entry.row.setLowPriorityStateUpdated(false);
}

问题来了,NotificationEntryManager#onAsyncInflationFinished 哪里被调到了,似乎断掉了,是怎么和来通知关联起来的?这得需要看看通知的流程。

通知流程

这部分分析按照正常的调用顺序来分析。

notificationmanager#notify

notificationmanager 调用 notify 方法发送 notification,最后调用到 notifyAsUser() 方法:

@UnsupportedAppUsage
public voID notifyAsUser(String tag, int ID, Notification notification, UserHandle user)
{
   Inotificationmanager service = getService();
   String pkg = mContext.getPackagename();
   // Fix the notification as best we can.
   Notification.addFIEldsFromContext(mContext, notification);
   if (notification.sound != null) {
       notification.sound = notification.sound.getCanonicalUri();
       if (StrictMode.vmfileUrIExposureEnabled()) {
           notification.sound.checkfileUrIExposed("Notification.sound");
       }
   }
   fixLegacySmallicon(notification, pkg);
   if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.LolliPOP_MR1) {
       if (notification.getSmallicon() == null) {
           throw new IllegalArgumentException("InvalID notification (no valID small icon): "
                   + notification);
       }
   }
   if (localLOGV) Log.v(TAG, pkg + ": notify(" + ID + ", " + notification + ")");
   notification.reduceImageSizes(mContext);
   ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
   boolean isLowRam = am.isLowRamDevice();
   final Notification copy = Builder.maybeClonestrippedForDelivery(notification, isLowRam,
           mContext);
   try {
       service.enqueueNotificationWithTag(pkg, mContext.getopPackagename(), tag, ID,
               copy, user.getIDentifIEr());
   } catch (remoteexception e) {
       throw e.rethrowFromSystemServer();
   }
}

这里 service 是 Inotificationmanager,对应的是 notificationmanagerService,看 notificationmanagerService#enqueueNotificationWithTag,又调用了 notificationmanagerService#enqueueNotificationInternal。

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) {
   //省略其他代码
   final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
   r.setIsAppimportanceLocked(mRankingHelper.getIsAppimportanceLocked(pkg, callingUID));
   //省略其他代码
   mHandler.post(new EnqueueNotificationRunnable(userID, r));
}
EnqueueNotificationRunnable#run
protected class EnqueueNotificationRunnable implements Runnable {
   private final NotificationRecord r;
   private final int userID;
   EnqueueNotificationRunnable(int userID, NotificationRecord r) {
       this.userID = userID;
       this.r = r;
   };
   @OverrIDe
   public voID run() {
       synchronized (mNotificationLock) {
           // 省略其他代码
           if (mAssistants.isEnabled()) {
               mAssistants.onNotificationEnqueued(r);
               mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
                       DELAY_FOR_ASSISTANT_TIME);
           } else {
               mHandler.post(new PostNotificationRunnable(r.getKey()));
           }
       }
   }
}
PostNotificationRunnable#run
protected class PostNotificationRunnable implements Runnable {
   private final String key;
   PostNotificationRunnable(String key) {
       this.key = key;
   }
   @OverrIDe
   public voID run() {
       synchronized (mNotificationLock) {
           try {
               // 省略其他代码
               if (notification.getSmallicon() != null) {
                   StatusbarNotification oldSbn = (old != null) ? old.sbn : null;
                   mListeners.notifyPostedLocked(r, old);
                   if (oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup())) {
                       mHandler.post(new Runnable() {
                           @OverrIDe
                           public voID run() {
                               mGroupHelper.onNotificationPosted(
                                       n, hasautoGroupSummaryLocked(n));
                           }
                       });
                   }
               }  // 省略其他代码
           } finally {
               // 省略其他代码
           }
       }
   }
}

mListeners 是 NotificationListeners,调用 notificationmanagerService#notifyPostedLocked。

notificationmanagerService#notifyPostedLocked
@GuardedBy("mNotificationLock")
public voID notifyPostedLocked(NotificationRecord r, NotificationRecord old) {
   notifyPostedLocked(r, old, true);
}

@GuardedBy("mNotificationLock")
private voID notifyPostedLocked(NotificationRecord r, NotificationRecord old,
       boolean notifyAllListeners) {
   // Lazily initialized snapshots of the notification.
   StatusbarNotification sbn = r.sbn;
   StatusbarNotification oldSbn = (old != null) ? old.sbn : null;
   TrimCache trimCache = new TrimCache(sbn);
   for (final ManagedServiceInfo info : getServices()) {
       //省略其他代码
       final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
       // This notification became invisible -> remove the old one.
       if (oldSbnVisible && !sbnVisible) {
           final StatusbarNotification oldSbnlightClone = oldSbn.clonelight();
           mHandler.post(new Runnable() {
               @OverrIDe
               public voID run() {
                   notifyRemoved(
                           info, oldSbnlightClone, update, null, REASON_USER_StopPED);
               }
           });
           continue;
       }
       // Grant access before Listener is notifIEd
       final int targetUserID = (info.userID == UserHandle.USER_ALL)
               ? UserHandle.USER_SYstem : info.userID;
       updateUriPermissions(r, old, info.component.getPackagename(), targetUserID);
       final StatusbarNotification sbntopost = trimCache.ForListener(info);
       mHandler.post(new Runnable() {
           @OverrIDe
           public voID run() {
           //调用notificationmanagerService#notifyPosted
               notifyPosted(info, sbntopost, update);
           }
       });
   }
}

private voID notifyPosted(final ManagedServiceInfo info,
       final StatusbarNotification sbn, NotificationRankingUpdate rankingUpdate) {
   final INotificationListener Listener = (INotificationListener) info.service;
   StatusbarNotificationHolder sbnHolder = new StatusbarNotificationHolder(sbn);
   try {
       Listener.onNotificationPosted(sbnHolder, rankingUpdate);
   } catch (remoteexception ex) {
       Log.e(TAG, "unable to notify Listener (posted): " + Listener, ex);
   }
}

这里 service 是 INotificationListener,对应的是 NotificationListenerWrapper,看 NotificationListenerWrapper#onNotificationPosted。

NotificationListenerWrapper#onNotificationPosted
protected class NotificationListenerWrapper extends INotificationListener.Stub {
   @OverrIDe
   public voID onNotificationPosted(IStatusbarNotificationHolder sbnHolder,
           NotificationRankingUpdate update) {
       StatusbarNotification sbn;
       try {
           sbn = sbnHolder.get();
       } catch (remoteexception e) {
           Log.w(TAG, "onNotificationPosted: Error receiving StatusbarNotification", e);
           return;
       }
       try {
           // convert icon Metadata to legacy format for older clIEnts
           createLegacyIconExtras(sbn.getNotification());
           maybePopulateRemoteVIEws(sbn.getNotification());
           maybePopulatePeople(sbn.getNotification());
       } catch (IllegalArgumentException e) {
           // warn and drop corrupt notification
           Log.w(TAG, "onNotificationPosted: can't rebuild notification from " +
                   sbn.getPackagename());
           sbn = null;
       }
       // protect subclass from concurrent modifications of (@link mNotificationKeys}.
       synchronized (mlock) {
           applyUpdateLocked(update);
           if (sbn != null) {
               SomeArgs args = SomeArgs.obtain();
               args.arg1 = sbn;
               args.arg2 = mRankingMap;
               mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_POSTED,
                       args).sendToTarget();
           } else {
               // still pass along the ranking map, it may contain other information
               mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_RANKING_UPDATE,
                       mRankingMap).sendToTarget();
           }
       }
   }
}
 

看 MyHandler 处理中的 MSG_ON_NOTIFICATION_POSTED。

MyHandler#handleMessage
private final class MyHandler extends Handler {
   public static final int MSG_ON_NOTIFICATION_POSTED = 1;
   public static final int MSG_ON_NOTIFICATION_REMOVED = 2;
   public static final int MSG_ON_ListENER_CONNECTED = 3;
   public static final int MSG_ON_NOTIFICATION_RANKING_UPDATE = 4;
   public static final int MSG_ON_ListENER_HINTS_CHANGED = 5;
   public static final int MSG_ON_INTERRUPTION_FILTER_CHANGED = 6;
   public static final int MSG_ON_NOTIFICATION_CHANNEL_MODIFIED = 7;
   public static final int MSG_ON_NOTIFICATION_CHANNEL_GROUP_MODIFIED = 8;
   public MyHandler(Looper looper) {
       super(looper, null, false);
   }
   @OverrIDe
   public voID handleMessage(Message msg) {
       if (!isConnected) {
           return;
       }
       switch (msg.what) {
           case MSG_ON_NOTIFICATION_POSTED: {
               SomeArgs args = (SomeArgs) msg.obj;
               StatusbarNotification sbn = (StatusbarNotification) args.arg1;
               RankingMap rankingMap = (RankingMap) args.arg2;
               args.recycle();
               onNotificationPosted(sbn, rankingMap);
           } break;
          //省略其他代码
       }
   }
}
NotificationListenerService#onNotificationPosted
public voID onNotificationPosted(StatusbarNotification sbn, RankingMap rankingMap) {
   onNotificationPosted(sbn);
}

NotificationListenerService 是抽象类,NotificationListenerService#onNotificationPosted 在 NotificationListener##onNotificationPosted 有重写。

NotificationListener#onNotificationPosted
@OverrIDe
public voID onNotificationPosted(final StatusbarNotification sbn,
       final RankingMap rankingMap) {
   if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn);
   if (sbn != null && !onPluginNotificationPosted(sbn, rankingMap)) {
       mPresenter.getHandler().post(() -> {
           //省略其他代码
           if (isUpdate) {
               mEntryManager.updateNotification(sbn, rankingMap);
           } else {
               mEntryManager.addNotification(sbn, rankingMap);
           }
       });
   }
}

调用了 NotificationEntryManager#addNotification。

NotificationEntryManager#addNotification
@OverrIDe
public voID addNotification(StatusbarNotification notification,
       NotificationListenerService.RankingMap ranking) {
   try {
       addNotificationInternal(notification, ranking);
   } catch (InflationException e) {
       handleInflationException(notification, e);
   }
}

private voID addNotificationInternal(StatusbarNotification notification,
       NotificationListenerService.RankingMap ranking) throws InflationException {
   String key = notification.getKey();
   if (DEBUG) Log.d(TAG, "addNotification key=" + key);
   mNotificationData.updateranking(ranking);
   //继续看 createNotificationVIEws
   NotificationData.Entry shadeEntry = createNotificationVIEws(notification);
   //省略其他代码
}

protected NotificationData.Entry createNotificationVIEws(StatusbarNotification sbn)
       throws InflationException {
   if (DEBUG) {
       Log.d(TAG, "createNotificationVIEws(notification=" + sbn);
   }
   NotificationData.Entry entry = new NotificationData.Entry(sbn);
   Dependency.get(LeakDetector.class).trackInstance(entry);
   entry.createIcons(mContext, sbn);
   // Construct the expanded vIEw.
   inflateVIEws(entry, mListContainer.getVIEwParentForNotification(entry));
   return entry;
}

从 NotificationEntryManager#addNotification 到 NotificationEntryManager#addNotificationInternal 再到 NotificationEntryManager#inflateVIEws 方法。

NotificationEntryManager#inflateVIEws
private voID inflateVIEws(NotificationData.Entry entry, VIEwGroup parent) {
   PackageManager pmUser = Statusbar.getPackageManagerForUser(mContext,
           entry.notification.getUser().getIDentifIEr());
   final StatusbarNotification sbn = entry.notification;
   if (entry.row != null) {
       entry.reset();
       updateNotification(entry, pmUser, sbn, entry.row);
   } else {
   //来通知会走到这里
       new RowInflaterTask().inflate(mContext, parent, entry,
               row -> {
                   bindRow(entry, pmUser, sbn, row);
                   updateNotification(entry, pmUser, sbn, row);
               });
   }
}
RowInflaterTask#inflate
public voID inflate(Context context, VIEwGroup parent, NotificationData.Entry entry,
       RowInflationFinishedListener Listener) {
   if (TRACE_ORIGIN) {
       mInflateOrigin = new Throwable("inflate requested here");
   }
   mListener = Listener;
   AsyncLayoutInflater inflater = new AsyncLayoutInflater(context);
   mEntry = entry;
   entry.setInflationTask(this);
   //这里是Notification布局文件
   inflater.inflate(R.layout.status_bar_notification_row, parent, this);
}

再看 RowInflaterTask#onInflateFinished:

@OverrIDe
public voID onInflateFinished(VIEw vIEw, int resID, VIEwGroup parent) {
   if (!mCancelled) {
       try {
           mEntry.onInflationTaskFinished();
           //1. 调 RowInflationFinishedListener#onInflationFinished
           mListener.onInflationFinished((ExpandableNotificationRow) vIEw);
       } catch (Throwable t) {
           if (mInflateOrigin != null) {
               Log.e(TAG, "Error in inflation finished Listener: " + t, mInflateOrigin);
               t.addSuppressed(mInflateOrigin);
           }
           throw t;
       }
   }
}
public interface RowInflationFinishedListener {
//2. 在 NotificationEntryManager#row 实现
   voID onInflationFinished(ExpandableNotificationRow row);
}

看 NotificationEntryManager#row 会调用 bindRow 和 updateNotification,看 updateNotification方法最终会调用 ExpandableNotificationRow#updateNotification。

ExpandableNotificationRow#updateNotification
public voID updateNotification(NotificationData.Entry entry) {
   mEntry = entry;
   mStatusbarNotification = entry.notification;
   mNotificationInflater.inflateNotificationVIEws();
   cacheIsSystemNotification();
}

继续跟,到 NotificationInflater#inflateNotificationVIEws。

NotificationInflater#inflateNotificationVIEws
@VisibleForTesting
voID inflateNotificationVIEws(int reInflateFlags) {
   if (mRow.isRemoved()) {
      return;
   }
   StatusbarNotification sbn = mRow.getEntry().notification;
   AsyncInflationTask task = new AsyncInflationTask(sbn, reInflateFlags, mRow,
           mIsLowPriority,
           mIsChildInGroup, mUsesIncreasedHeight, mUsesIncreasedheadsUpHeight, mRedactAmbIEnt,
           mCallback, mRemoteVIEwClickHandler);
   if (mCallback != null && mCallback.doInflateSynchronous()) {
       task.onPostExecute(task.doInBackground());
   } else {
       task.execute();
   }
}

看 AsyncInflationTask 执行的结果:

public static class AsyncInflationTask extends AsyncTask<VoID, VoID, InflationProgress>
       implements InflationCallback, InflationTask {
  //省略其他代码
   @OverrIDe
   protected InflationProgress doInBackground(VoID... params) {
       //省略其他代码
   }
   @OverrIDe
   protected voID onPostExecute(InflationProgress result) {
       if (mError == null) {
           mCancellationSignal = apply(result, mReInflateFlags, mRow, mRedactAmbIEnt,
                   mRemoteVIEwClickHandler, this);
       } else {
           handleError(mError);
       }
   }
}

调用 NotificationInflater#apply,最终会到 NotificationInflater#applyRemoteVIEw

@VisibleForTesting
static voID applyRemoteVIEw(final InflationProgress result,
       final int reInflateFlags, int inflationID,
       final ExpandableNotificationRow row,
       final boolean redactAmbIEnt, boolean isNewVIEw,
       RemoteVIEws.OnClickHandler remoteVIEwClickHandler,
       @Nullable final InflationCallback callback, NotificationData.Entry entry,
       NotificationContentVIEw parentLayout, VIEw existingVIEw,
       NotificationVIEwWrapper existingWrapper,
       final HashMap<Integer, CancellationSignal> runningInflations,
       ApplyCallback applyCallback) {
   RemoteVIEws newContentVIEw = applyCallback.getRemoteVIEw();
   //省略其他代码
   RemoteVIEws.OnVIEwApplIEdListener Listener
           = new RemoteVIEws.OnVIEwApplIEdListener() {
       @OverrIDe
       public voID onVIEwApplIEd(VIEw v) {
           if (isNewVIEw) {
               v.setIsRootnamespace(true);
               applyCallback.setResultVIEw(v);
           } else if (existingWrapper != null) {
               existingWrapper.onReinflated();
           }
           runningInflations.remove(inflationID);
           finishIfDone(result, reInflateFlags, runningInflations, callback, row,
                   redactAmbIEnt);
       }
       //
   };
   CancellationSignal cancellationSignal;
   if (isNewVIEw) {
   //调用RemoteVIEws#applyAsync,最终回调了上面的onVIEwApplIEd方法。
       cancellationSignal = newContentVIEw.applyAsync(
               result.packageContext,
               parentLayout,
               EXECUTOR,
               Listener,
               remoteVIEwClickHandler);
   }//省略其他代码
   runningInflations.put(inflationID, cancellationSignal);
}

继续看 NotificationInflater#finishIfDone,这个方法看到最后的endListener.onAsyncInflationFinished(row.getEntry()); 实现方法在 NotificationEntryManager#onAsyncInflationFinished。

NotificationEntryManager#onAsyncInflationFinished
@OverrIDe
public voID onAsyncInflationFinished(NotificationData.Entry entry) {
   mPendingNotifications.remove(entry.key);
   // If there was an async task started after the removal, we don't want to add it back to
   // the List, otherwise we might get leaks.
   boolean isNew = mNotificationData.get(entry.key) == null;
   if (isNew && !entry.row.isRemoved()) {
       addEntry(entry);
   } else if (!isNew && entry.row.hasLowPriorityStateUpdated()) {
       mVisualStabilityManager.onLowPriorityUpdated(entry);
       mPresenter.updateNotificationVIEws();
   }
   entry.row.setLowPriorityStateUpdated(false);
}

这里的 addEntry 方法调用了addNotificationVIEws,好了,终于和 systemUI 的通知关联起来了,这样,锁屏来通知分析结束。

折叠状态栏通知

有了以上锁屏通知分析,再来分析折叠状态栏通知就简单很多了,先看来折叠状态栏初始化部分。

status_bar.xml

折叠状态栏对应的布局文件是 status_bar.xml:

<com.androID.systemUI.statusbar.AlphaOptimizedFrameLayout
   androID:ID="@+ID/notification_icon_area"
   androID:layout_wIDth="0dp"
   androID:layout_height="match_parent"
   androID:layout_weight="1"
   androID:orIEntation="horizontal"
   androID:clipChildren="false"/>

如果来通知,就在 notification_icon_area 进行 addVIEw 填充。再看看代码初始化。

Statusbar#makeStatusbarVIEw
//NotificationIconAreaController 初始化
mNotificationIconAreaController = systemUIFactory.getInstance()
       .createNotificationIconAreaController(context, this);
inflateShelf();
mNotificationIconAreaController.setupShelf(mNotificationShelf);
mStackScroller.setIconAreaController(mNotificationIconAreaController);
Dependency.get(DarkIcondispatcher.class).addDarkReceiver(mNotificationIconAreaController);
FragmentHostManager.get(mStatusbarWindow)
       .addTagListener(CollapsedStatusbarFragment.TAG, (tag, fragment) -> {
           CollapsedStatusbarFragment statusbarFragment =
                   (CollapsedStatusbarFragment) fragment;
           statusbarFragment.initNotificationIconArea(mNotificationIconAreaController);
           //省略其他代码
       }).getFragmentManager()
       .beginTransaction()
       .replace(R.ID.status_bar_container, new CollapsedStatusbarFragment(),
               CollapsedStatusbarFragment.TAG)
       .commit();
CollapsedStatusbarFragment#initNotificationIconArea
public voID initNotificationIconArea(NotificationIconAreaController
       notificationIconAreaController) {
   VIEwGroup notificationIconArea = mStatusbar.findVIEwByID(R.ID.notification_icon_area);
   mNotificationIconAreaInner =
           notificationIconAreaController.getNotificationInnerAreaVIEw();
   if (mNotificationIconAreaInner.getParent() != null) {
       ((VIEwGroup) mNotificationIconAreaInner.getParent())
               .removeVIEw(mNotificationIconAreaInner);
   }
   notificationIconArea.addVIEw(mNotificationIconAreaInner);
   // Default to showing until we kNow otherwise.
   showNotificationIconArea(false);
}

看到这里的notificationIconArea.addVIEw(mNotificationIconAreaInner); ,notificationIconArea 被 mNotificationIconAreaInner 填充,因此我们要重点关注 NotificationIconAreaController 什么时候被填充。

有以上锁屏通知分析知道有通知来最后会调用 Statusbar#updateNotificationVIEws。

Statusbar#updateNotificationVIEws
@OverrIDe
public voID updateNotificationVIEws() {
   // 省略其他代码
   mNotificationIconAreaController.updateNotificationIcons();
}

调用 NotificationIconAreaController#updateNotificationIcons。

NotificationIconAreaController#updateNotificationIcons
public voID updateNotificationIcons() {
   updateStatusbarIcons();
   updateShelfIcons();
   updateHasShelfIconsWhenFullyDark();
   applyNotificationIconsTint();
}

public voID updateStatusbarIcons() {
   updateIconsForLayout(entry -> entry.icon, mNotificationIcons,
           false /* showAmbIEnt */, true /* hIDedismissed */, true /* hIDeReplIEdMessages */);
}

private voID updateIconsForLayout(Function<NotificationData.Entry, StatusbarIconVIEw> function,
       NotificationIconContainer hostLayout, boolean showAmbIEnt, boolean hIDedismissed,
       boolean hIDeReplIEdMessages) {
   ArrayList<StatusbarIconVIEw> toShow = new ArrayList<>(
           mNotificationScrollLayout.getChildCount());
   //省略其他代码
   final FrameLayout.LayoutParams params = generateIconLayoutParams();
   for (int i = 0; i < toShow.size(); i++) {
       StatusbarIconVIEw v = toShow.get(i);
       // The vIEw might still be transIEntly added if it was just removed and added again
       hostLayout.removeTransIEntVIEw(v);
       if (v.getParent() == null) {
           if (hIDedismissed) {
               v.setondismissListener(mUpdateStatusbarIcons);
           }
           hostLayout.addVIEw(v, i, params);
       }
   }
   hostLayout.setChangingVIEwpositions(true);
   // Re-sort notification icons
   final int childCount = hostLayout.getChildCount();
   for (int i = 0; i < childCount; i++) {
       VIEw actual = hostLayout.getChildAt(i);
       StatusbarIconVIEw expected = toShow.get(i);
       if (actual == expected) {
           continue;
       }
       hostLayout.removeVIEw(expected);
       hostLayout.addVIEw(expected, i);
   }
   hostLayout.setChangingVIEwpositions(false);
   hostLayout.setReplacingIcons(null);
}

OK,折叠状态栏通知分析结束。

结语

本篇梳理了 systemUI Notification 大致流程,分为锁屏的通知和状态栏通知,代码很多,细节没有去纠结,省略了很多代码,有兴趣,可以自己去 AOSP 查看。

总结

以上是内存溢出为你收集整理的Android 9.0 SystemUI Notification全部内容,希望文章能够帮你解决Android 9.0 SystemUI Notification所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1006958.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-22
下一篇 2022-05-22

发表评论

登录后才能评论

评论列表(0条)

保存