本文主要分享 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#updateNotificationVIEwspublic 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#updateNotificationspublic voID updateNotifications() {
mNotificationData.filterandSort();
mPresenter.updateNotificationVIEws();
}
presenter 是 NotificationPresenter 对象,从 Statusbar#makeStatusbarVIEw 传过来了,继续看 NotificationEntryManager#updateNotifications 哪里被调用了,是 NotificationEntryManager#addNotificationVIEws。
NotificationEntryManager#addNotificationVIEwsprotected 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#notifynotificationmanager 调用 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#enqueueNotificationInternalvoID 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#runprotected 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#runprotected 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#onNotificationPostedprotected 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#handleMessageprivate 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#onNotificationPostedpublic 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#inflateVIEwsprivate 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#inflatepublic 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#updateNotificationpublic 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。
@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#initNotificationIconAreapublic 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#updateNotificationIconspublic 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所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)