马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
前言
在做应用时,时常须要在关照栏表现一条关照,那么详细流程是怎样的呢,怀着如许的探究目标,来举行一步步源码分析。
源码梳理
- package com.android.server;
- ...
- public final class SystemServer implements Dumpable {
- ...
- private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
- ...
- if (mFactoryTestMode == FactoryTest.FACTORY_TEST_LOW_LEVEL) {
- dpms = null;
- } else {
- ...
- t.traceBegin("StartNotificationManager");
- mSystemServiceManager.startService(NotificationManagerService.class);
- SystemNotificationChannels.removeDeprecated(context);
- SystemNotificationChannels.createAll(context);
- notification = INotificationManager.Stub.asInterface(
- ServiceManager.getService(Context.NOTIFICATION_SERVICE));
- t.traceEnd();
- ...
- }
- ...
- }
- ...
- }
复制代码- package com.android.server.notification;
- ...
- public class NotificationManagerService extends SystemService {
- ...
- @Override
- public void onStart() {
- ...
- publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false,
- DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL);
- publishLocalService(NotificationManagerInternal.class, mInternalService);
- }
- ...
- @VisibleForTesting
- final IBinder mService = new INotificationManager.Stub() {
- ...
- }
- ...
- }
复制代码- package com.android.server;
- ...
- @SystemApi(client = Client.SYSTEM_SERVER)
- public abstract class SystemService {
- ...
- protected final void publishBinderService(String name, IBinder service,
- boolean allowIsolated, int dumpPriority) {
- ServiceManager.addService(name, service, allowIsolated, dumpPriority);
- }
- ...
- }
复制代码 应用开辟都比力认识,表现一条关照是调用NotificationManager的notify接口- package android.app;
- ...
- @SystemService(Context.NOTIFICATION_SERVICE)
- public class NotificationManager {
- ...
- /**
- * @hide
- */
- @UnsupportedAppUsage
- static public INotificationManager getService() {
- if (sService != null) {
- return sService;
- }
- IBinder b = ServiceManager.getService("notification");
- sService = INotificationManager.Stub.asInterface(b);
- return sService;
- }
- ...
- public void notify(int id, Notification notification) {
- notify(null, id, notification);
- }
- public void notify(String tag, int id, Notification notification) {
- notifyAsUser(tag, id, notification, mContext.getUser());
- }
- /**
- * @hide
- */
- @UnsupportedAppUsage
- public void notifyAsUser(String tag, int id, Notification notification, UserHandle user) {
- INotificationManager service = getService();
- String pkg = mContext.getPackageName();
- try {
- if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
- service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
- fixNotification(notification), user.getIdentifier());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
- ...
- }
复制代码 这里比力清朗,直接跳转至NotificationManagerService的mService#enqueueNotificationWithTag- package com.android.server.notification;
- ...
- public class NotificationManagerService extends SystemService {
- ...
- @VisibleForTesting
- final IBinder mService = new INotificationManager.Stub() {
- ...
- @Override
- public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
- Notification notification, int userId) throws RemoteException {
- enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
- Binder.getCallingPid(), tag, id, notification, userId);
- }
- ...
- }
- ...
- 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) {
- enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
- incomingUserId, false);
- }
- 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, boolean postSilently) {
- ...
- final StatusBarNotification n = new StatusBarNotification(
- pkg, opPkg, id, tag, notificationUid, callingPid, notification,
- user, null, System.currentTimeMillis());
- ...
- final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
- r.setIsAppImportanceLocked(mPreferencesHelper.getIsAppImportanceLocked(pkg, callingUid));
- r.setPostSilently(postSilently);
- r.setFlagBubbleRemoved(false);
- r.setPkgAllowedAsConvo(mMsgPkgsAllowedAsConvos.contains(pkg));
- ...
- mHandler.post(new EnqueueNotificationRunnable(userId, r, isAppForeground));
- }
- ...
- }
复制代码 终极,通过Handler调治EnqueueNotificationRunnable- package com.android.server.notification;
- ...
- public class NotificationManagerService extends SystemService {
- ...
- protected class EnqueueNotificationRunnable implements Runnable {
- private final NotificationRecord r;
- private final int userId;
- private final boolean isAppForeground;
- EnqueueNotificationRunnable(int userId, NotificationRecord r, boolean foreground) {
- this.userId = userId;
- this.r = r;
- this.isAppForeground = foreground;
- }
- @Override
- public void run() {
- synchronized (mNotificationLock) {
- ...
- // tell the assistant service about the notification
- if (mAssistants.isEnabled()) {
- mAssistants.onNotificationEnqueuedLocked(r);
- mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
- DELAY_FOR_ASSISTANT_TIME);
- } else {
- mHandler.post(new PostNotificationRunnable(r.getKey()));
- }
- }
- }
- }
- ...
- }
复制代码 接下来是PostNotificationRunnable- package com.android.server.notification;
- ...
- public class NotificationManagerService extends SystemService {
- ...
- private NotificationListeners mListeners;
- ...
- protected class PostNotificationRunnable implements Runnable {
- private final String key;
- PostNotificationRunnable(String key) {
- this.key = key;
- }
- @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;
- }
- }
- ...
- final StatusBarNotification n = r.getSbn();
- final Notification notification = n.getNotification();
- ...
- if (notification.getSmallIcon() != null) {
- StatusBarNotification oldSbn = (old != null) ? old.getSbn() : null;
- mListeners.notifyPostedLocked(r, old);
- ...
- } else {
- ...
- }
- ...
- } finally {
- ...
- }
- }
- }
- }
- ...
- }
复制代码 实行到mListeners.notifyPostedLocked(r, old);,继承跳转- package com.android.server.notification;
- ...
- public class NotificationManagerService extends SystemService {
- ...
- public class NotificationListeners extends ManagedServices {
- ...
- @GuardedBy("mNotificationLock")
- public void notifyPostedLocked(NotificationRecord r, NotificationRecord old) {
- notifyPostedLocked(r, old, true);
- }
- @GuardedBy("mNotificationLock")
- private void notifyPostedLocked(NotificationRecord r, NotificationRecord old,
- boolean notifyAllListeners) {
- try {
- ...
- for (final ManagedServiceInfo info : getServices()) {
- ...
- final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
- ...
- final StatusBarNotification sbnToPost = trimCache.ForListener(info);
- mHandler.post(() -> notifyPosted(info, sbnToPost, update));
- }
- } catch (Exception e) {
- Slog.e(TAG, "Could not notify listeners for " + r.getKey(), e);
- }
- }
- ...
- 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) {
- Slog.e(TAG, "unable to notify listener (posted): " + info, ex);
- }
- }
- ...
- }
- ...
- }
复制代码 走到这里,接下来就是通过aidl调用onNotificationPosted接口- package android.service.notification;
- ...
- public abstract class NotificationListenerService extends Service {
- ...
- private Handler mHandler;
- ...
- @Override
- protected void attachBaseContext(Context base) {
- super.attachBaseContext(base);
- mHandler = new MyHandler(getMainLooper());
- }
- ...
- protected class NotificationListenerWrapper extends INotificationListener.Stub {
- @Override
- public void onNotificationPosted(IStatusBarNotificationHolder sbnHolder,
- NotificationRankingUpdate update) {
- StatusBarNotification sbn;
- ...
- 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 {
- ...
- }
- }
- }
- ...
- }
- ...
- private final class MyHandler extends Handler {
- public static final int MSG_ON_NOTIFICATION_POSTED = 1;
- ...
- @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;
- ...
- }
- }
- }
- }
复制代码 到这里,接下来就是调用onNotificationPosted接口,那么就要转至SystemUI的NotificationListener中去
- 有时机单独纪录下为啥是NotificationListener
- package com.android.systemui.statusbar;
- ...
- public class NotificationListener extends NotificationListenerWithPlugins {
- ...
- @Override
- public void onNotificationPosted(final StatusBarNotification sbn,
- final RankingMap rankingMap) {
- if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn);
- if (sbn != null && !onPluginNotificationPosted(sbn, rankingMap)) {
- mMainHandler.post(() -> {
- processForRemoteInput(sbn.getNotification(), mContext);
- for (NotificationHandler handler : mNotificationHandlers) {
- handler.onNotificationPosted(sbn, rankingMap);
- }
- });
- }
- }
- ...
- }
复制代码 再转至这里的NotificationHandler中去- package com.android.systemui.statusbar.notification;
- ...
- public class NotificationEntryManager implements
- CommonNotifCollection,
- Dumpable,
- VisualStabilityManager.Callback {
- ...
- private final NotificationHandler mNotifListener = new NotificationHandler() {
- @Override
- public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
- final boolean isUpdateToInflatedNotif = mActiveNotifications.containsKey(sbn.getKey());
- if (isUpdateToInflatedNotif) {
- updateNotification(sbn, rankingMap);
- } else {
- addNotification(sbn, rankingMap);
- }
- }
- ...
- }
- ...
- }
复制代码 显然,接下来进入addNotification环节- package com.android.systemui.statusbar.notification;
- ...
- public class NotificationEntryManager implements
- CommonNotifCollection,
- Dumpable,
- VisualStabilityManager.Callback {
- ...
- private final Lazy<NotificationRowBinder> mNotificationRowBinderLazy;
- ...
- private void addNotificationInternal(
- StatusBarNotification notification,
- RankingMap rankingMap) throws InflationException {
- ...
- NotificationEntry entry = mPendingNotifications.get(key);
- ...
- // Construct the expanded view.
- if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
- mNotificationRowBinderLazy.get().inflateViews(entry, mInflationCallback);
- }
- ...
- }
- public void addNotification(StatusBarNotification notification, RankingMap ranking) {
- try {
- addNotificationInternal(notification, ranking);
- } catch (InflationException e) {
- handleInflationException(notification, e);
- }
- }
- ...
- }
复制代码 可以看到,这里开始调用NotificationRowBinder的inflateViews创建关照栏控件,而NotificationRowBinder接口的实现类是NotificationRowBinderImpl- package com.android.systemui.statusbar.notification.collection.inflation;
- ...
- public class NotificationRowBinderImpl implements NotificationRowBinder {
- ...
- private final Provider<RowInflaterTask> mRowInflaterTaskProvider;
- ...
- @Override
- public void inflateViews(
- NotificationEntry entry,
- NotificationRowContentBinder.InflationCallback callback)
- throws InflationException {
- ...
- if (entry.rowExists()) {
- ...
- } else {
- mIconManager.createIcons(entry);
- mRowInflaterTaskProvider.get().inflate(mContext, parent, entry,
- row -> {
- // Setup the controller for the view.
- ExpandableNotificationRowComponent component =
- mExpandableNotificationRowComponentBuilder
- .expandableNotificationRow(row)
- .notificationEntry(entry)
- .onExpandClickListener(mPresenter)
- .listContainer(mListContainer)
- .build();
- ExpandableNotificationRowController rowController =
- component.getExpandableNotificationRowController();
- rowController.init(entry);
- entry.setRowController(rowController);
- bindRow(entry, row);
- updateRow(entry, row);
- inflateContentViews(entry, row, callback);
- });
- }
- }
- ...
- }
复制代码 这里很好明白,调用RowInflaterTask的inflate接口,不出不测,终极会转至回调中inflateContentViews- package com.android.systemui.statusbar.notification.row;
- ...
- public class RowInflaterTask implements InflationTask, AsyncLayoutInflater.OnInflateFinishedListener {
- ...
- private RowInflationFinishedListener mListener;
- ...
- public void inflate(Context context, ViewGroup parent, NotificationEntry entry,
- RowInflationFinishedListener listener) {
- ...
- mListener = listener;
- AsyncLayoutInflater inflater = new AsyncLayoutInflater(context);
- ...
- inflater.inflate(R.layout.status_bar_notification_row, parent, this);
- }
- ...
- @Override
- public void onInflateFinished(View view, int resid, ViewGroup parent) {
- if (!mCancelled) {
- try {
- mEntry.onInflationTaskFinished();
- mListener.onInflationFinished((ExpandableNotificationRow) view);
- } catch (Throwable t) {
- ...
- }
- }
- }
- ...
- }
复制代码 果然,这里不出不测,返回NotificationRowBinderImpl的inflateContentViews- package com.android.systemui.statusbar.notification.collection.inflation;
- ...
- public class NotificationRowBinderImpl implements NotificationRowBinder {
- ...
- private final RowContentBindStage mRowContentBindStage;
- ...
- private void inflateContentViews(
- NotificationEntry entry,
- ExpandableNotificationRow row,
- @Nullable NotificationRowContentBinder.InflationCallback inflationCallback) {
- ...
- mRowContentBindStage.requestRebind(entry, en -> {
- ...
- if (inflationCallback != null) {
- inflationCallback.onAsyncInflationFinished(en);
- }
- });
- }
- ...
- }
复制代码 RowContentBindStage继承自BindRequester且未实现requestRebind- package com.android.systemui.statusbar.notification.row;
- ...
- public abstract class BindRequester {
- private @Nullable BindRequestListener mBindRequestListener;
- public final CancellationSignal requestRebind(
- @NonNull NotificationEntry entry,
- @Nullable BindCallback callback) {
- CancellationSignal signal = new CancellationSignal();
- if (mBindRequestListener != null) {
- mBindRequestListener.onBindRequest(entry, signal, callback);
- }
- return signal;
- }
- final void setBindRequestListener(BindRequestListener listener) {
- mBindRequestListener = listener;
- }
- }
复制代码 这里的mBindRequestListener是在NotifBindPipeline中举行设置- package com.android.systemui.statusbar.notification.row;
- ...
- public final class NotifBindPipeline {
- ...
- private BindStage mStage;
- ...
- public void setStage(
- BindStage stage) {
- mLogger.logStageSet(stage.getClass().getName());
- mStage = stage;
- mStage.setBindRequestListener(this::onBindRequested);
- }
- ...
- private void onBindRequested(
- @NonNull NotificationEntry entry,
- @NonNull CancellationSignal signal,
- @Nullable BindCallback callback) {
- ...
- requestPipelineRun(entry);
- }
- ...
- }
复制代码 上面的mStage就是RowContentBindStage实例
- 背面专门纪录下RowContentBindStage、BindRequester、BindStage以及NotifBindPipeline之间的接洽
接下来看requestPipelineRun的实现逻辑- package com.android.systemui.statusbar.notification.row;
- ...
- public final class NotifBindPipeline {
- ...
- NotifBindPipeline(
- CommonNotifCollection collection,
- NotifBindPipelineLogger logger,
- @Main Looper mainLooper) {
- ...
- mMainHandler = new NotifBindPipelineHandler(mainLooper);
- }
- ...
- private void requestPipelineRun(NotificationEntry entry) {
- ...
- if (!mMainHandler.hasMessages(START_PIPELINE_MSG, entry)) {
- Message msg = Message.obtain(mMainHandler, START_PIPELINE_MSG, entry);
- mMainHandler.sendMessage(msg);
- }
- }
- ...
- private static final int START_PIPELINE_MSG = 1;
- private class NotifBindPipelineHandler extends Handler {
- NotifBindPipelineHandler(Looper looper) {
- super(looper);
- }
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case START_PIPELINE_MSG:
- NotificationEntry entry = (NotificationEntry) msg.obj;
- startPipeline(entry);
- break;
- default:
- throw new IllegalArgumentException("Unknown message type: " + msg.what);
- }
- }
- }
- }
复制代码 调治调用到startPipeline- package com.android.systemui.statusbar.notification.row;
- ...
- public final class NotifBindPipeline {
- ...
- private void startPipeline(NotificationEntry entry) {
- ...
- mStage.executeStage(entry, row, (en) -> onPipelineComplete(en));
- }
- ...
- }
复制代码 上面相识到,这里的mStage是RowContentBindStage实例- package com.android.systemui.statusbar.notification.row;
- ...
- public class RowContentBindStage extends BindStage<RowContentBindParams> {
- private final NotificationRowContentBinder mBinder;
- ...
- @Override
- protected void executeStage(
- @NonNull NotificationEntry entry,
- @NonNull ExpandableNotificationRow row,
- @NonNull StageCallback callback) {
- ...
- mBinder.bindContent(entry, row, contentToBind, bindParams, forceInflate, inflationCallback);
- }
- ...
- }
复制代码 这里的NotificationRowContentBinder接口的实现类为NotificationContentInflater- package com.android.systemui.statusbar.notification.row;
- ...
- public class NotificationContentInflater implements NotificationRowContentBinder {
- ...
- @Override
- public void bindContent(
- NotificationEntry entry,
- ExpandableNotificationRow row,
- @InflationFlag int contentToBind,
- BindParams bindParams,
- boolean forceInflate,
- @Nullable InflationCallback callback) {
- if (row.isRemoved()) {
- // We don't want to reinflate anything for removed notifications. Otherwise views might
- // be readded to the stack, leading to leaks. This may happen with low-priority groups
- // where the removal of already removed children can lead to a reinflation.
- return;
- }
- StatusBarNotification sbn = entry.getSbn();
- // To check if the notification has inline image and preload inline image if necessary.
- row.getImageResolver().preloadImages(sbn.getNotification());
- if (forceInflate) {
- mRemoteViewCache.clearCache(entry);
- }
- // Cancel any pending frees on any view we're trying to bind since we should be bound after.
- cancelContentViewFrees(row, contentToBind);
- AsyncInflationTask task = new AsyncInflationTask(
- mBgExecutor,
- mInflateSynchronously,
- contentToBind,
- mRemoteViewCache,
- entry,
- mConversationProcessor,
- row,
- bindParams.isLowPriority,
- bindParams.usesIncreasedHeight,
- bindParams.usesIncreasedHeadsUpHeight,
- callback,
- mRemoteInputManager.getRemoteViewsOnClickHandler(),
- mIsMediaInQS,
- mSmartReplyStateInflater);
- if (mInflateSynchronously) {
- task.onPostExecute(task.doInBackground());
- } else {
- task.executeOnExecutor(mBgExecutor);
- }
- }
- ...
- }
复制代码 接下来是实行异步使命- package com.android.systemui.statusbar.notification.row;
- ...
- public class NotificationContentInflater implements NotificationRowContentBinder {
- ...
- private static CancellationSignal apply(
- Executor bgExecutor,
- boolean inflateSynchronously,
- InflationProgress result,
- @InflationFlag int reInflateFlags,
- NotifRemoteViewCache remoteViewCache,
- NotificationEntry entry,
- ExpandableNotificationRow row,
- RemoteViews.InteractionHandler remoteViewClickHandler,
- @Nullable InflationCallback callback) {
- ...
- int flag = FLAG_CONTENT_VIEW_CONTRACTED;
- if ((reInflateFlags & flag) != 0) {
- ...
- applyRemoteView(bgExecutor, inflateSynchronously, result, reInflateFlags, flag,
- remoteViewCache, entry, row, isNewView, remoteViewClickHandler, callback,
- privateLayout, privateLayout.getContractedChild(),
- privateLayout.getVisibleWrapper(
- NotificationContentView.VISIBLE_TYPE_CONTRACTED),
- runningInflations, applyCallback);
- }
- flag = FLAG_CONTENT_VIEW_EXPANDED;
- if ((reInflateFlags & flag) != 0) {
- if (result.newExpandedView != null) {
- ...
- applyRemoteView(bgExecutor, inflateSynchronously, result, reInflateFlags, flag,
- remoteViewCache, entry, row, isNewView, remoteViewClickHandler,
- callback, privateLayout, privateLayout.getExpandedChild(),
- privateLayout.getVisibleWrapper(
- NotificationContentView.VISIBLE_TYPE_EXPANDED), runningInflations,
- applyCallback);
- }
- }
- flag = FLAG_CONTENT_VIEW_HEADS_UP;
- if ((reInflateFlags & flag) != 0) {
- if (result.newHeadsUpView != null) {
- ...
- applyRemoteView(bgExecutor, inflateSynchronously, result, reInflateFlags, flag,
- remoteViewCache, entry, row, isNewView, remoteViewClickHandler,
- callback, privateLayout, privateLayout.getHeadsUpChild(),
- privateLayout.getVisibleWrapper(
- VISIBLE_TYPE_HEADSUP), runningInflations,
- applyCallback);
- }
- }
- flag = FLAG_CONTENT_VIEW_PUBLIC;
- if ((reInflateFlags & flag) != 0) {
- ...
- applyRemoteView(bgExecutor, inflateSynchronously, result, reInflateFlags, flag,
- remoteViewCache, entry, row, isNewView, remoteViewClickHandler, callback,
- publicLayout, publicLayout.getContractedChild(),
- publicLayout.getVisibleWrapper(NotificationContentView.VISIBLE_TYPE_CONTRACTED),
- runningInflations, applyCallback);
- }
- ...
- }
- ...
- public static class AsyncInflationTask extends AsyncTask<Void, Void, InflationProgress>
- implements InflationCallback, InflationTask {
- ...
- @Override
- protected void onPostExecute(InflationProgress result) {
- if (mError == null) {
- mCancellationSignal = apply(
- mBgExecutor,
- mInflateSynchronously,
- result,
- mReInflateFlags,
- mRemoteViewCache,
- mEntry,
- mRow,
- mRemoteViewClickHandler,
- this);
- } else {
- handleError(mError);
- }
- }
- ...
- }
- ...
- }
复制代码 可以看出,异步使命都指向了applyRemoteView接口- package com.android.systemui.statusbar.notification.row;
- ...
- public class NotificationContentInflater implements NotificationRowContentBinder {
- ...
- @VisibleForTesting
- static void applyRemoteView(
- Executor bgExecutor,
- boolean inflateSynchronously,
- final InflationProgress result,
- final @InflationFlag int reInflateFlags,
- @InflationFlag int inflationId,
- final NotifRemoteViewCache remoteViewCache,
- final NotificationEntry entry,
- final ExpandableNotificationRow row,
- boolean isNewView,
- RemoteViews.InteractionHandler remoteViewClickHandler,
- @Nullable final InflationCallback callback,
- NotificationContentView parentLayout,
- View existingView,
- NotificationViewWrapper existingWrapper,
- final HashMap<Integer, CancellationSignal> runningInflations,
- ApplyCallback applyCallback) {
- RemoteViews newContentView = applyCallback.getRemoteView();
- if (inflateSynchronously) {
- try {
- if (isNewView) {
- View v = newContentView.apply(
- result.packageContext,
- parentLayout,
- remoteViewClickHandler);
- v.setIsRootNamespace(true);
- applyCallback.setResultView(v);
- } else {
- newContentView.reapply(
- result.packageContext,
- existingView,
- remoteViewClickHandler);
- existingWrapper.onReinflated();
- }
- } catch (Exception e) {
- handleInflationError(runningInflations, e, row.getEntry(), callback);
- // Add a running inflation to make sure we don't trigger callbacks.
- // Safe to do because only happens in tests.
- runningInflations.put(inflationId, new CancellationSignal());
- }
- return;
- }
- RemoteViews.OnViewAppliedListener listener = new RemoteViews.OnViewAppliedListener() {
- @Override
- public void onViewInflated(View v) {
- if (v instanceof ImageMessageConsumer) {
- ((ImageMessageConsumer) v).setImageResolver(row.getImageResolver());
- }
- }
- @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, remoteViewCache, runningInflations,
- callback, entry, row);
- }
- @Override
- public void onError(Exception e) {
- // Uh oh the async inflation failed. Due to some bugs (see b/38190555), this could
- // actually also be a system issue, so let's try on the UI thread again to be safe.
- try {
- View newView = existingView;
- if (isNewView) {
- newView = newContentView.apply(
- result.packageContext,
- parentLayout,
- remoteViewClickHandler);
- } else {
- newContentView.reapply(
- result.packageContext,
- existingView,
- remoteViewClickHandler);
- }
- Log.wtf(TAG, "Async Inflation failed but normal inflation finished normally.",
- e);
- onViewApplied(newView);
- } catch (Exception anotherException) {
- runningInflations.remove(inflationId);
- handleInflationError(runningInflations, e, row.getEntry(),
- callback);
- }
- }
- };
- CancellationSignal cancellationSignal;
- if (isNewView) {
- cancellationSignal = newContentView.applyAsync(
- result.packageContext,
- parentLayout,
- bgExecutor,
- listener,
- remoteViewClickHandler);
- } else {
- cancellationSignal = newContentView.reapplyAsync(
- result.packageContext,
- existingView,
- bgExecutor,
- listener,
- remoteViewClickHandler);
- }
- runningInflations.put(inflationId, cancellationSignal);
- }
- ...
- }
复制代码 这里是要转调RemoteViews的applyAsync接口,而且传入了OnViewAppliedListener回调监听;我们知道RemoteViews是可以在差别线程或进程中创建和更新UI的组件,而且,在调用关照接口时,传入的自界说的结构参数也是RemoteViews- package android.app;
- ...
- public class Notification implements Parcelable {
- ...
- public static class Builder {
- ...
- @Deprecated
- public Builder setContent(RemoteViews views) {
- return setCustomContentView(views);
- }
- @NonNull
- public Builder setCustomContentView(RemoteViews contentView) {
- mN.contentView = contentView;
- return this;
- }
- ...
- }
- ...
- }
复制代码 那么就再来看下RemoteViews的applyAsync接口- package android.widget;
- ...
- public class RemoteViews implements Parcelable, Filter {
- ...
- public CancellationSignal applyAsync(Context context, ViewGroup parent,
- Executor executor, OnViewAppliedListener listener, InteractionHandler handler) {
- return applyAsync(context, parent, executor, listener, handler, null /* size */);
- }
- public CancellationSignal applyAsync(Context context, ViewGroup parent,
- Executor executor, OnViewAppliedListener listener, InteractionHandler handler,
- SizeF size) {
- return applyAsync(context, parent, executor, listener, handler, size,
- null /* themeColors */);
- }
- public CancellationSignal applyAsync(Context context, ViewGroup parent, Executor executor,
- OnViewAppliedListener listener, InteractionHandler handler, SizeF size,
- ColorResources colorResources) {
- return new AsyncApplyTask(getRemoteViewsToApply(context, size), parent, context, listener,
- handler, colorResources, null /* result */,
- true /* topLevel */).startTaskOnExecutor(executor);
- }
- ...
- private class AsyncApplyTask extends AsyncTask<Void, Void, ViewTree>
- implements CancellationSignal.OnCancelListener {
- ...
- final OnViewAppliedListener mListener;
- ...
- @Override
- protected void onPostExecute(ViewTree viewTree) {
- ...
- if (mListener != null) {
- if (mError != null) {
- mListener.onError(mError);
- } else {
- mListener.onViewApplied(viewTree.mRoot);
- }
- } else if (mError != null) {
- ...
- }
- }
- ...
- }
- ...
- }
复制代码 好了,这里开始走OnViewAppliedListener回调的onViewApplied接口- package com.android.systemui.statusbar.notification.row;
- ...
- public class NotificationContentInflater implements NotificationRowContentBinder {
- ...
- @VisibleForTesting
- static void applyRemoteView(
- Executor bgExecutor,
- boolean inflateSynchronously,
- final InflationProgress result,
- final @InflationFlag int reInflateFlags,
- @InflationFlag int inflationId,
- final NotifRemoteViewCache remoteViewCache,
- final NotificationEntry entry,
- final ExpandableNotificationRow row,
- boolean isNewView,
- RemoteViews.InteractionHandler remoteViewClickHandler,
- @Nullable final InflationCallback callback,
- 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, remoteViewCache, runningInflations,
- callback, entry, row);
- }
- ...
- };
- ...
- }
- ...
- private static boolean finishIfDone(InflationProgress result,
- @InflationFlag int reInflateFlags, NotifRemoteViewCache remoteViewCache,
- HashMap<Integer, CancellationSignal> runningInflations,
- @Nullable InflationCallback endListener, NotificationEntry entry,
- ExpandableNotificationRow row) {
- ...
- if (runningInflations.isEmpty()) {
- ...
- if (endListener != null) {
- endListener.onAsyncInflationFinished(entry);
- }
- return true;
- }
- return false;
- }
- ...
- }
复制代码 在finishIfDone中,末了回调InflationCallback的onAsyncInflationFinished,而这个回调就是AsyncInflationTask- package com.android.systemui.statusbar.notification.row;
- ...
- public class NotificationContentInflater implements NotificationRowContentBinder {
- ...
- public static class AsyncInflationTask extends AsyncTask<Void, Void, InflationProgress>
- implements InflationCallback, InflationTask {
- ...
- private final InflationCallback mCallback;
- ...
- @Override
- public void onAsyncInflationFinished(NotificationEntry entry) {
- mEntry.onInflationTaskFinished();
- mRow.onNotificationUpdated();
- if (mCallback != null) {
- mCallback.onAsyncInflationFinished(mEntry);
- }
- // Notify the resolver that the inflation task has finished,
- // try to purge unnecessary cached entries.
- mRow.getImageResolver().purgeCache();
- }
- ...
- }
- ...
- }
复制代码 回溯一下之前的回调- package com.android.systemui.statusbar.notification.row;
- ...
- public class RowContentBindStage extends BindStage<RowContentBindParams> {
- private final NotificationRowContentBinder mBinder;
- ...
- @Override
- protected void executeStage(
- @NonNull NotificationEntry entry,
- @NonNull ExpandableNotificationRow row,
- @NonNull StageCallback callback) {
- ...
- InflationCallback inflationCallback = new InflationCallback() {
- @Override
- public void handleInflationException(NotificationEntry entry, Exception e) {
- mNotifInflationErrorManager.setInflationError(entry, e);
- }
- @Override
- public void onAsyncInflationFinished(NotificationEntry entry) {
- mNotifInflationErrorManager.clearInflationError(entry);
- getStageParams(entry).clearDirtyContentViews();
- callback.onStageFinished(entry);
- }
- };
- mBinder.cancelBind(entry, row);
- mBinder.bindContent(entry, row, contentToBind, bindParams, forceInflate, inflationCallback);
- }
- ...
- }
复制代码 继承回溯callback.onStageFinished- package com.android.systemui.statusbar.notification.row;
- ...
- public final class NotifBindPipeline {
- ...
- private final List<BindCallback> mScratchCallbacksList = new ArrayList<>();
- ...
- private void startPipeline(NotificationEntry entry) {
- ...
- mStage.executeStage(entry, row, (en) -> onPipelineComplete(en));
- }
- private void onPipelineComplete(NotificationEntry entry) {
- final BindEntry bindEntry = getBindEntry(entry);
- final Set<BindCallback> callbacks = bindEntry.callbacks;
- mLogger.logFinishedPipeline(entry.getKey(), callbacks.size());
- bindEntry.invalidated = false;
- // Move all callbacks to separate list as callbacks may themselves add/remove callbacks.
- // TODO: Throw an exception for this re-entrant behavior once we deprecate
- // NotificationGroupAlertTransferHelper
- mScratchCallbacksList.addAll(callbacks);
- callbacks.clear();
- for (int i = 0; i < mScratchCallbacksList.size(); i++) {
- mScratchCallbacksList.get(i).onBindFinished(entry);
- }
- mScratchCallbacksList.clear();
- }
- ...
- }
复制代码 接下来回溯BindCallback的onBindFinished- package com.android.systemui.statusbar.notification.row;
- ...
- public final class NotifBindPipeline {
- ...
- private void onBindRequested(
- @NonNull NotificationEntry entry,
- @NonNull CancellationSignal signal,
- @Nullable BindCallback callback) {
- final BindEntry bindEntry = getBindEntry(entry);
- if (bindEntry == null) {
- // Invalidating views for a notification that is not active.
- return;
- }
- bindEntry.invalidated = true;
- // Put in new callback.
- if (callback != null) {
- final Set<BindCallback> callbacks = bindEntry.callbacks;
- callbacks.add(callback);
- signal.setOnCancelListener(() -> callbacks.remove(callback));
- }
- requestPipelineRun(entry);
- }
- ...
- }
复制代码- package com.android.systemui.statusbar.notification.collection.inflation;
- ...
- public class NotificationRowBinderImpl implements NotificationRowBinder {
- ...
- private final RowContentBindStage mRowContentBindStage;
- ...
- private void inflateContentViews(
- NotificationEntry entry,
- ExpandableNotificationRow row,
- @Nullable NotificationRowContentBinder.InflationCallback inflationCallback) {
- ...
- mRowContentBindStage.requestRebind(entry, en -> {
- ...
- if (inflationCallback != null) {
- inflationCallback.onAsyncInflationFinished(en);
- }
- });
- }
- ...
- }
复制代码 也就是要继承回溯inflationCallback.onAsyncInflationFinished(en)- package com.android.systemui.statusbar.notification;
- ...
- public class NotificationEntryManager implements
- CommonNotifCollection,
- Dumpable,
- VisualStabilityManager.Callback {
- ...
- private NotificationPresenter mPresenter;
- ...
- private final InflationCallback mInflationCallback = new InflationCallback() {
- ...
- @Override
- public void onAsyncInflationFinished(NotificationEntry entry) {
- ...
- if (!entry.isRowRemoved()) {
- ...
- if (isNew) {
- for (NotificationEntryListener listener : mNotificationEntryListeners) {
- listener.onEntryInflated(entry);
- }
- addActiveNotification(entry);
- updateNotifications("onAsyncInflationFinished");
- for (NotificationEntryListener listener : mNotificationEntryListeners) {
- listener.onNotificationAdded(entry);
- }
- } else {
- for (NotificationEntryListener listener : mNotificationEntryListeners) {
- listener.onEntryReinflated(entry);
- }
- }
- }
- }
- };
- ...
- private void addNotificationInternal(
- StatusBarNotification notification,
- RankingMap rankingMap) throws InflationException {
- ...
- // Construct the expanded view.
- if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
- mNotificationRowBinderLazy.get().inflateViews(entry, mInflationCallback);
- }
- ...
- }
- ...
- public void updateNotifications(String reason) {
- reapplyFilterAndSort(reason);
- if (mPresenter != null && !mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
- mPresenter.updateNotificationViews(reason);
- }
- }
- ...
- }
复制代码 这里的NotificationPresenter接口实现类为StatusBarNotificationPresenter- package com.android.systemui.statusbar.phone;
- ...
- public class StatusBarNotificationPresenter implements NotificationPresenter,
- ConfigurationController.ConfigurationListener,
- NotificationRowBinderImpl.BindRowCallback,
- CommandQueue.Callbacks {
- ...
- private final NotificationViewHierarchyManager mViewHierarchyManager;
- ...
- private final NotificationPanelViewController mNotificationPanel;
- ...
- @Override
- public void updateNotificationViews(final String reason) {
- ...
- mViewHierarchyManager.updateNotificationViews();
- mNotificationPanel.updateNotificationViews(reason);
- }
- ...
- }
复制代码 这里显然是开始调用更新关照栏接口了- package com.android.systemui.statusbar;
- ...
- public class NotificationViewHierarchyManager implements DynamicPrivacyController.Listener {
- ...
- private NotificationListContainer mListContainer;
- ...
- public void updateNotificationViews() {
- ...
- 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);
- } else if (!mListContainer.containsView(v)) {
- // the view is added somewhere else. Let's make sure
- // the ordering works properly below, by excluding these
- toShow.remove(v);
- i--;
- }
- }
- ...
- }
- ...
- }
复制代码 不难明白,这里开始添加关照栏控件了- package com.android.systemui.statusbar.notification.stack;
- ...
- public class NotificationStackScrollLayoutController {
- ...
- private NotificationStackScrollLayout mView;
- ...
- private class NotificationListContainerImpl implements NotificationListContainer {
- ...
- @Override
- public void addContainerView(View v) {
- mView.addContainerView(v);
- }
- ...
- }
- ...
- }
复制代码- package com.android.systemui.statusbar.notification.stack;
- ...
- public class NotificationStackScrollLayout extends ViewGroup implements Dumpable {
- ...
- public void addContainerView(View v) {
- Assert.isMainThread();
- addView(v);
- if (v instanceof ExpandableNotificationRow && mController.isShowingEmptyShadeView()) {
- mController.updateShowEmptyShadeView();
- updateFooter();
- }
- updateSpeedBumpIndex();
- }
- ...
- }
复制代码 自此,关照栏添加一条关照的流程算是简单梳理完成
|