Merge "Log lots more about notification inflation" into main
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index 5127d14..6c2ce7f 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -80,6 +80,14 @@
         return factory.create("NotifHeadsUpLog", 1000);
     }
 
+    /** Provides a logging buffer for logs related to inflation of notifications. */
+    @Provides
+    @SysUISingleton
+    @NotifInflationLog
+    public static LogBuffer provideNotifInflationLogBuffer(LogBufferFactory factory) {
+        return factory.create("NotifInflationLog", 100);
+    }
+
     /** Provides a logging buffer for notification interruption calculations. */
     @Provides
     @SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/NotifInflationLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/NotifInflationLog.java
new file mode 100644
index 0000000..9f201c3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/NotifInflationLog.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.log.dagger;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.android.systemui.log.LogBuffer;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+/** A {@link LogBuffer} for messages related to inflation of notifications. */
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface NotifInflationLog {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
index d248961..6e3b15d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
@@ -34,6 +34,7 @@
 import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.row.NotificationContentInflaterLogger
 import com.android.systemui.statusbar.notification.row.NotificationContentView
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator
 import com.android.systemui.statusbar.policy.HeadsUpManager
@@ -47,7 +48,11 @@
     private val launcherApps: LauncherApps,
     private val conversationNotificationManager: ConversationNotificationManager
 ) {
-    fun processNotification(entry: NotificationEntry, recoveredBuilder: Notification.Builder) {
+    fun processNotification(
+            entry: NotificationEntry,
+            recoveredBuilder: Notification.Builder,
+            logger: NotificationContentInflaterLogger
+    ) {
         val messagingStyle = recoveredBuilder.style as? Notification.MessagingStyle ?: return
         messagingStyle.conversationType =
                 if (entry.ranking.channel.isImportantConversation)
@@ -55,6 +60,7 @@
                 else
                     Notification.MessagingStyle.CONVERSATION_TYPE_NORMAL
         entry.ranking.conversationShortcutInfo?.let { shortcutInfo ->
+            logger.logAsyncTaskProgress(entry, "getting shortcut icon")
             messagingStyle.shortcutIcon = launcherApps.getShortcutIcon(shortcutInfo)
             shortcutInfo.label?.let { label ->
                 messagingStyle.conversationTitle = label
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java
index d1aa01b..98109f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java
@@ -36,12 +36,14 @@
 public class NotifInflaterImpl implements NotifInflater {
 
     private final NotifInflationErrorManager mNotifErrorManager;
+    private final NotifInflaterLogger mLogger;
 
     private NotificationRowBinderImpl mNotificationRowBinder;
 
     @Inject
-    public NotifInflaterImpl(NotifInflationErrorManager errorManager) {
+    public NotifInflaterImpl(NotifInflationErrorManager errorManager, NotifInflaterLogger logger) {
         mNotifErrorManager = errorManager;
+        mLogger = logger;
     }
 
     /**
@@ -51,12 +53,6 @@
         mNotificationRowBinder = rowBinder;
     }
 
-    @Override
-    public void rebindViews(@NonNull NotificationEntry entry, @NonNull Params params,
-            @NonNull InflationCallback callback) {
-        inflateViews(entry, params, callback);
-    }
-
     /**
      * Called to inflate the views of an entry.  Views are not considered inflated until all of its
      * views are bound.
@@ -64,23 +60,43 @@
     @Override
     public void inflateViews(@NonNull NotificationEntry entry, @NonNull Params params,
             @NonNull InflationCallback callback) {
+        mLogger.logInflatingViews(entry, params);
+        inflateViewsImpl(entry, params, callback);
+        mLogger.logInflatedViews(entry);
+    }
+    @Override
+    public void rebindViews(@NonNull NotificationEntry entry, @NonNull Params params,
+            @NonNull InflationCallback callback) {
+        mLogger.logRebindingViews(entry, params);
+        inflateViewsImpl(entry, params, callback);
+        mLogger.logReboundViews(entry);
+    }
+
+    private void inflateViewsImpl(@NonNull NotificationEntry entry, @NonNull Params params,
+            @NonNull InflationCallback callback) {
         try {
             requireBinder().inflateViews(
                     entry,
                     params,
                     wrapInflationCallback(callback));
         } catch (InflationException e) {
+            mLogger.logInflationException(entry, e);
             mNotifErrorManager.setInflationError(entry, e);
         }
     }
 
     @Override
     public boolean abortInflation(NotificationEntry entry) {
-        return entry.abortTask();
+        final boolean abortedTask = entry.abortTask();
+        if (abortedTask) {
+            mLogger.logAbortInflationAbortedTask(entry);
+        }
+        return abortedTask;
     }
 
     @Override
     public void releaseViews(@NonNull NotificationEntry entry) {
+        mLogger.logReleasingViews(entry);
         requireBinder().releaseViews(entry);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterLogger.kt
new file mode 100644
index 0000000..366c7d3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterLogger.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection
+
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.core.LogLevel
+import com.android.systemui.log.dagger.NotifInflationLog
+import com.android.systemui.statusbar.notification.InflationException
+import com.android.systemui.statusbar.notification.collection.inflation.NotifInflater.Params
+import com.android.systemui.statusbar.notification.logKey
+import javax.inject.Inject
+
+class NotifInflaterLogger @Inject constructor(@NotifInflationLog private val buffer: LogBuffer) {
+    fun logInflatingViews(entry: NotificationEntry, params: Params) {
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            {
+                str1 = entry.logKey
+                str2 = params.reason
+            },
+            { "inflating views for $str1: $str2" }
+        )
+    }
+
+    fun logInflatedViews(entry: NotificationEntry) {
+        buffer.log(TAG, LogLevel.DEBUG, { str1 = entry.logKey }, { "inflated views for $str1" })
+    }
+
+    fun logRebindingViews(entry: NotificationEntry, params: Params) {
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            {
+                str1 = entry.logKey
+                str2 = params.reason
+            },
+            { "rebinding views for $str1: $str2" }
+        )
+    }
+
+    fun logReboundViews(entry: NotificationEntry) {
+        buffer.log(TAG, LogLevel.DEBUG, { str1 = entry.logKey }, { "rebound views for $str1" })
+    }
+
+    fun logInflationException(entry: NotificationEntry, exc: InflationException) {
+        buffer.log(
+            TAG,
+            LogLevel.WARNING,
+            {
+                str1 = entry.logKey
+                str2 = exc.stackTraceToString()
+            },
+            { "exception inflating views for $str1: $str2" }
+        )
+    }
+
+    fun logAbortInflationAbortedTask(entry: NotificationEntry) {
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            { str1 = entry.logKey },
+            { "aborted task to abort inflation for $str1" }
+        )
+    }
+
+    fun logReleasingViews(entry: NotificationEntry) {
+        buffer.log(TAG, LogLevel.DEBUG, { str1 = entry.logKey }, { "aborting inflation for $str1" })
+    }
+}
+
+private const val TAG = "NotifInflater"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
index 9ecf50e..e206141 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
@@ -67,6 +67,7 @@
     private final ExpandableNotificationRowComponent.Builder
             mExpandableNotificationRowComponentBuilder;
     private final IconManager mIconManager;
+    private final NotificationRowBinderLogger mLogger;
 
     private NotificationPresenter mPresenter;
     private NotificationListContainer mListContainer;
@@ -84,6 +85,7 @@
             Provider<RowInflaterTask> rowInflaterTaskProvider,
             ExpandableNotificationRowComponent.Builder expandableNotificationRowComponentBuilder,
             IconManager iconManager,
+            NotificationRowBinderLogger logger,
             FeatureFlags featureFlags) {
         mContext = context;
         mNotifBindPipeline = notifBindPipeline;
@@ -94,6 +96,7 @@
         mRowInflaterTaskProvider = rowInflaterTaskProvider;
         mExpandableNotificationRowComponentBuilder = expandableNotificationRowComponentBuilder;
         mIconManager = iconManager;
+        mLogger = logger;
         mFeatureFlags = featureFlags;
     }
 
@@ -124,15 +127,19 @@
         ViewGroup parent = mListContainer.getViewParentForNotification(entry);
 
         if (entry.rowExists()) {
+            mLogger.logUpdatingRow(entry, params);
             mIconManager.updateIcons(entry);
             ExpandableNotificationRow row = entry.getRow();
             row.reset();
             updateRow(entry, row);
             inflateContentViews(entry, params, row, callback);
         } else {
+            mLogger.logCreatingRow(entry, params);
             mIconManager.createIcons(entry);
+            mLogger.logInflatingRow(entry);
             mRowInflaterTaskProvider.get().inflate(mContext, parent, entry,
                     row -> {
+                        mLogger.logInflatedRow(entry);
                         // Setup the controller for the view.
                         ExpandableNotificationRowComponent component =
                                 mExpandableNotificationRowComponentBuilder
@@ -154,8 +161,10 @@
     @Override
     public void releaseViews(NotificationEntry entry) {
         if (!entry.rowExists()) {
+            mLogger.logNotReleasingViewsRowDoesntExist(entry);
             return;
         }
+        mLogger.logReleasingViews(entry);
         final RowContentBindParams params = mRowContentBindStage.getStageParams(entry);
         params.markContentViewsFreeable(FLAG_CONTENT_VIEW_CONTRACTED);
         params.markContentViewsFreeable(FLAG_CONTENT_VIEW_EXPANDED);
@@ -220,7 +229,9 @@
         }
 
         params.rebindAllContentViews();
+        mLogger.logRequestingRebind(entry, inflaterParams);
         mRowContentBindStage.requestRebind(entry, en -> {
+            mLogger.logRebindComplete(entry);
             row.setUsesIncreasedCollapsedHeight(useIncreasedCollapsedHeight);
             row.setIsLowPriority(isLowPriority);
             if (inflationCallback != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderLogger.kt
new file mode 100644
index 0000000..7eafc59
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderLogger.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.inflation
+
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.core.LogLevel
+import com.android.systemui.log.dagger.NotifInflationLog
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.inflation.NotifInflater.Params
+import com.android.systemui.statusbar.notification.logKey
+import javax.inject.Inject
+
+class NotificationRowBinderLogger
+@Inject
+constructor(@NotifInflationLog private val buffer: LogBuffer) {
+    fun logCreatingRow(entry: NotificationEntry, params: Params) {
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            {
+                str1 = entry.logKey
+                str2 = params.reason
+            },
+            { "creating row for $str1: $str2" }
+        )
+    }
+
+    fun logInflatingRow(entry: NotificationEntry) {
+        buffer.log(TAG, LogLevel.DEBUG, { str1 = entry.logKey }, { "inflating row for $str1" })
+    }
+
+    fun logInflatedRow(entry: NotificationEntry) {
+        buffer.log(TAG, LogLevel.DEBUG, { str1 = entry.logKey }, { "inflated row for $str1" })
+    }
+
+    fun logUpdatingRow(entry: NotificationEntry, params: Params) {
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            {
+                str1 = entry.logKey
+                str2 = params.reason
+            },
+            { "updating row for $str1: $str2" }
+        )
+    }
+
+    fun logReleasingViews(entry: NotificationEntry) {
+        buffer.log(TAG, LogLevel.DEBUG, { str1 = entry.logKey }, { "releasing views for $str1" })
+    }
+
+    fun logNotReleasingViewsRowDoesntExist(entry: NotificationEntry) {
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            { str1 = entry.logKey },
+            { "not releasing views for $str1: row doesn't exist" }
+        )
+    }
+
+    fun logRequestingRebind(entry: NotificationEntry, params: Params) {
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            {
+                str1 = entry.key
+                str2 = params.reason
+            },
+            { "requesting rebind for $str1: $str2" }
+        )
+    }
+
+    fun logRebindComplete(entry: NotificationEntry) {
+        buffer.log(TAG, LogLevel.DEBUG, { str1 = entry.key }, { "rebind complete for $str1" })
+    }
+}
+
+private const val TAG = "NotificationRowBinder"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index 86f545d..f805183 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -80,6 +80,7 @@
     private final Executor mBgExecutor;
     private final SmartReplyStateInflater mSmartReplyStateInflater;
     private final NotifLayoutInflaterFactory.Provider mNotifLayoutInflaterFactoryProvider;
+    private final NotificationContentInflaterLogger mLogger;
 
     @Inject
     NotificationContentInflater(
@@ -89,7 +90,8 @@
             MediaFeatureFlag mediaFeatureFlag,
             @Background Executor bgExecutor,
             SmartReplyStateInflater smartRepliesInflater,
-            NotifLayoutInflaterFactory.Provider notifLayoutInflaterFactoryProvider) {
+            NotifLayoutInflaterFactory.Provider notifLayoutInflaterFactoryProvider,
+            NotificationContentInflaterLogger logger) {
         mRemoteViewCache = remoteViewCache;
         mRemoteInputManager = remoteInputManager;
         mConversationProcessor = conversationProcessor;
@@ -97,6 +99,7 @@
         mBgExecutor = bgExecutor;
         mSmartReplyStateInflater = smartRepliesInflater;
         mNotifLayoutInflaterFactoryProvider = notifLayoutInflaterFactoryProvider;
+        mLogger = logger;
     }
 
     @Override
@@ -111,9 +114,12 @@
             // 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.
+            mLogger.logNotBindingRowWasRemoved(entry);
             return;
         }
 
+        mLogger.logBinding(entry, contentToBind);
+
         StatusBarNotification sbn = entry.getSbn();
 
         // To check if the notification has inline image and preload inline image if necessary.
@@ -141,7 +147,8 @@
                 mRemoteInputManager.getRemoteViewsOnClickHandler(),
                 mIsMediaInQS,
                 mSmartReplyStateInflater,
-                mNotifLayoutInflaterFactoryProvider);
+                mNotifLayoutInflaterFactoryProvider,
+                mLogger);
         if (mInflateSynchronously) {
             task.onPostExecute(task.doInBackground());
         } else {
@@ -166,12 +173,11 @@
                 bindParams.usesIncreasedHeadsUpHeight,
                 packageContext,
                 row,
-                mNotifLayoutInflaterFactoryProvider);
+                mNotifLayoutInflaterFactoryProvider,
+                mLogger);
 
-        result = inflateSmartReplyViews(result, reInflateFlags, entry,
-                row.getContext(), packageContext,
-                row.getExistingSmartReplyState(),
-                smartRepliesInflater);
+        result = inflateSmartReplyViews(result, reInflateFlags, entry, row.getContext(),
+                packageContext, row.getExistingSmartReplyState(), smartRepliesInflater, mLogger);
 
         apply(
                 mBgExecutor,
@@ -182,15 +188,20 @@
                 entry,
                 row,
                 mRemoteInputManager.getRemoteViewsOnClickHandler(),
-                null);
+                null /* callback */,
+                mLogger);
         return result;
     }
 
     @Override
-    public void cancelBind(
+    public boolean cancelBind(
             @NonNull NotificationEntry entry,
             @NonNull ExpandableNotificationRow row) {
-        entry.abortTask();
+        final boolean abortedTask = entry.abortTask();
+        if (abortedTask) {
+            mLogger.logCancelBindAbortedTask(entry);
+        }
+        return abortedTask;
     }
 
     @Override
@@ -198,6 +209,7 @@
             @NonNull NotificationEntry entry,
             @NonNull ExpandableNotificationRow row,
             @InflationFlag int contentToUnbind) {
+        mLogger.logUnbinding(entry, contentToUnbind);
         int curFlag = 1;
         while (contentToUnbind != 0) {
             if ((contentToUnbind & curFlag) != 0) {
@@ -279,7 +291,8 @@
             Context context,
             Context packageContext,
             InflatedSmartReplyState previousSmartReplyState,
-            SmartReplyStateInflater inflater) {
+            SmartReplyStateInflater inflater,
+            NotificationContentInflaterLogger logger) {
         boolean inflateContracted = (reInflateFlags & FLAG_CONTENT_VIEW_CONTRACTED) != 0
                 && result.newContentView != null;
         boolean inflateExpanded = (reInflateFlags & FLAG_CONTENT_VIEW_EXPANDED) != 0
@@ -287,14 +300,17 @@
         boolean inflateHeadsUp = (reInflateFlags & FLAG_CONTENT_VIEW_HEADS_UP) != 0
                 && result.newHeadsUpView != null;
         if (inflateContracted || inflateExpanded || inflateHeadsUp) {
+            logger.logAsyncTaskProgress(entry, "inflating contracted smart reply state");
             result.inflatedSmartReplyState = inflater.inflateSmartReplyState(entry);
         }
         if (inflateExpanded) {
+            logger.logAsyncTaskProgress(entry, "inflating expanded smart reply state");
             result.expandedInflatedSmartReplies = inflater.inflateSmartReplyViewHolder(
                     context, packageContext, entry, previousSmartReplyState,
                     result.inflatedSmartReplyState);
         }
         if (inflateHeadsUp) {
+            logger.logAsyncTaskProgress(entry, "inflating heads up smart reply state");
             result.headsUpInflatedSmartReplies = inflater.inflateSmartReplyViewHolder(
                     context, packageContext, entry, previousSmartReplyState,
                     result.inflatedSmartReplyState);
@@ -306,22 +322,28 @@
             Notification.Builder builder, boolean isLowPriority, boolean usesIncreasedHeight,
             boolean usesIncreasedHeadsUpHeight, Context packageContext,
             ExpandableNotificationRow row,
-            NotifLayoutInflaterFactory.Provider notifLayoutInflaterFactoryProvider) {
+            NotifLayoutInflaterFactory.Provider notifLayoutInflaterFactoryProvider,
+            NotificationContentInflaterLogger logger) {
         InflationProgress result = new InflationProgress();
+        final NotificationEntry entryForLogging = row.getEntry();
 
         if ((reInflateFlags & FLAG_CONTENT_VIEW_CONTRACTED) != 0) {
+            logger.logAsyncTaskProgress(entryForLogging, "creating contracted remote view");
             result.newContentView = createContentView(builder, isLowPriority, usesIncreasedHeight);
         }
 
         if ((reInflateFlags & FLAG_CONTENT_VIEW_EXPANDED) != 0) {
+            logger.logAsyncTaskProgress(entryForLogging, "creating expanded remote view");
             result.newExpandedView = createExpandedView(builder, isLowPriority);
         }
 
         if ((reInflateFlags & FLAG_CONTENT_VIEW_HEADS_UP) != 0) {
+            logger.logAsyncTaskProgress(entryForLogging, "creating heads up remote view");
             result.newHeadsUpView = builder.createHeadsUpContentView(usesIncreasedHeadsUpHeight);
         }
 
         if ((reInflateFlags & FLAG_CONTENT_VIEW_PUBLIC) != 0) {
+            logger.logAsyncTaskProgress(entryForLogging, "creating public remote view");
             result.newPublicView = builder.makePublicContentView(isLowPriority);
         }
         setNotifsViewsInflaterFactory(result, row, notifLayoutInflaterFactoryProvider);
@@ -361,7 +383,8 @@
             NotificationEntry entry,
             ExpandableNotificationRow row,
             RemoteViews.InteractionHandler remoteViewClickHandler,
-            @Nullable InflationCallback callback) {
+            @Nullable InflationCallback callback,
+            NotificationContentInflaterLogger logger) {
         NotificationContentView privateLayout = row.getPrivateLayout();
         NotificationContentView publicLayout = row.getPublicLayout();
         final HashMap<Integer, CancellationSignal> runningInflations = new HashMap<>();
@@ -374,6 +397,7 @@
             ApplyCallback applyCallback = new ApplyCallback() {
                 @Override
                 public void setResultView(View v) {
+                    logger.logAsyncTaskProgress(entry, "contracted view applied");
                     result.inflatedContentView = v;
                 }
                 @Override
@@ -381,12 +405,13 @@
                     return result.newContentView;
                 }
             };
+            logger.logAsyncTaskProgress(entry, "applying contracted view");
             applyRemoteView(bgExecutor, inflateSynchronously, result, reInflateFlags, flag,
                     remoteViewCache, entry, row, isNewView, remoteViewClickHandler, callback,
                     privateLayout, privateLayout.getContractedChild(),
                     privateLayout.getVisibleWrapper(
                             NotificationContentView.VISIBLE_TYPE_CONTRACTED),
-                    runningInflations, applyCallback);
+                    runningInflations, applyCallback, logger);
         }
 
         flag = FLAG_CONTENT_VIEW_EXPANDED;
@@ -398,6 +423,7 @@
                 ApplyCallback applyCallback = new ApplyCallback() {
                     @Override
                     public void setResultView(View v) {
+                        logger.logAsyncTaskProgress(entry, "expanded view applied");
                         result.inflatedExpandedView = v;
                     }
 
@@ -406,12 +432,13 @@
                         return result.newExpandedView;
                     }
                 };
+                logger.logAsyncTaskProgress(entry, "applying expanded view");
                 applyRemoteView(bgExecutor, inflateSynchronously, result, reInflateFlags, flag,
                         remoteViewCache, entry, row, isNewView, remoteViewClickHandler,
                         callback, privateLayout, privateLayout.getExpandedChild(),
                         privateLayout.getVisibleWrapper(
                                 NotificationContentView.VISIBLE_TYPE_EXPANDED), runningInflations,
-                        applyCallback);
+                        applyCallback, logger);
             }
         }
 
@@ -424,6 +451,7 @@
                 ApplyCallback applyCallback = new ApplyCallback() {
                     @Override
                     public void setResultView(View v) {
+                        logger.logAsyncTaskProgress(entry, "heads up view applied");
                         result.inflatedHeadsUpView = v;
                     }
 
@@ -432,12 +460,13 @@
                         return result.newHeadsUpView;
                     }
                 };
+                logger.logAsyncTaskProgress(entry, "applying heads up view");
                 applyRemoteView(bgExecutor, inflateSynchronously, result, reInflateFlags, flag,
                         remoteViewCache, entry, row, isNewView, remoteViewClickHandler,
                         callback, privateLayout, privateLayout.getHeadsUpChild(),
                         privateLayout.getVisibleWrapper(
                                 VISIBLE_TYPE_HEADSUP), runningInflations,
-                        applyCallback);
+                        applyCallback, logger);
             }
         }
 
@@ -449,6 +478,7 @@
             ApplyCallback applyCallback = new ApplyCallback() {
                 @Override
                 public void setResultView(View v) {
+                    logger.logAsyncTaskProgress(entry, "public view applied");
                     result.inflatedPublicView = v;
                 }
 
@@ -457,19 +487,23 @@
                     return result.newPublicView;
                 }
             };
+            logger.logAsyncTaskProgress(entry, "applying public view");
             applyRemoteView(bgExecutor, inflateSynchronously, result, reInflateFlags, flag,
                     remoteViewCache, entry, row, isNewView, remoteViewClickHandler, callback,
                     publicLayout, publicLayout.getContractedChild(),
                     publicLayout.getVisibleWrapper(NotificationContentView.VISIBLE_TYPE_CONTRACTED),
-                    runningInflations, applyCallback);
+                    runningInflations, applyCallback, logger);
         }
 
         // Let's try to finish, maybe nobody is even inflating anything
         finishIfDone(result, reInflateFlags, remoteViewCache, runningInflations, callback, entry,
-                row);
+                row, logger);
         CancellationSignal cancellationSignal = new CancellationSignal();
         cancellationSignal.setOnCancelListener(
-                () -> runningInflations.values().forEach(CancellationSignal::cancel));
+                () -> {
+                    logger.logAsyncTaskProgress(entry, "apply cancelled");
+                    runningInflations.values().forEach(CancellationSignal::cancel);
+                });
 
         return cancellationSignal;
     }
@@ -491,7 +525,8 @@
             View existingView,
             NotificationViewWrapper existingWrapper,
             final HashMap<Integer, CancellationSignal> runningInflations,
-            ApplyCallback applyCallback) {
+            ApplyCallback applyCallback,
+            NotificationContentInflaterLogger logger) {
         RemoteViews newContentView = applyCallback.getRemoteView();
         if (inflateSynchronously) {
             try {
@@ -511,7 +546,8 @@
                     existingWrapper.onReinflated();
                 }
             } catch (Exception e) {
-                handleInflationError(runningInflations, e, row.getEntry(), callback);
+                handleInflationError(runningInflations, e, row.getEntry(), callback, logger,
+                        "applying view synchronously");
                 // 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());
@@ -532,7 +568,7 @@
                 String invalidReason = isValidView(v, entry, row.getResources());
                 if (invalidReason != null) {
                     handleInflationError(runningInflations, new InflationException(invalidReason),
-                            row.getEntry(), callback);
+                            row.getEntry(), callback, logger, "applied invalid view");
                     runningInflations.remove(inflationId);
                     return;
                 }
@@ -543,7 +579,7 @@
                 }
                 runningInflations.remove(inflationId);
                 finishIfDone(result, reInflateFlags, remoteViewCache, runningInflations,
-                        callback, entry, row);
+                        callback, entry, row, logger);
             }
 
             @Override
@@ -569,7 +605,7 @@
                 } catch (Exception anotherException) {
                     runningInflations.remove(inflationId);
                     handleInflationError(runningInflations, e, row.getEntry(),
-                            callback);
+                            callback, logger, "applying view");
                 }
             }
         };
@@ -653,8 +689,10 @@
 
     private static void handleInflationError(
             HashMap<Integer, CancellationSignal> runningInflations, Exception e,
-            NotificationEntry notification, @Nullable InflationCallback callback) {
+            NotificationEntry notification, @Nullable InflationCallback callback,
+            NotificationContentInflaterLogger logger, String logContext) {
         Assert.isMainThread();
+        logger.logAsyncTaskException(notification, logContext, e);
         runningInflations.values().forEach(CancellationSignal::cancel);
         if (callback != null) {
             callback.handleInflationException(notification, e);
@@ -670,11 +708,12 @@
             @InflationFlag int reInflateFlags, NotifRemoteViewCache remoteViewCache,
             HashMap<Integer, CancellationSignal> runningInflations,
             @Nullable InflationCallback endListener, NotificationEntry entry,
-            ExpandableNotificationRow row) {
+            ExpandableNotificationRow row, NotificationContentInflaterLogger logger) {
         Assert.isMainThread();
         NotificationContentView privateLayout = row.getPrivateLayout();
         NotificationContentView publicLayout = row.getPublicLayout();
         if (runningInflations.isEmpty()) {
+            logger.logAsyncTaskProgress(entry, "finishing");
             boolean setRepliesAndActions = true;
             if ((reInflateFlags & FLAG_CONTENT_VIEW_CONTRACTED) != 0) {
                 if (result.inflatedContentView != null) {
@@ -828,6 +867,7 @@
         private final boolean mIsMediaInQS;
         private final SmartReplyStateInflater mSmartRepliesInflater;
         private final NotifLayoutInflaterFactory.Provider mNotifLayoutInflaterFactoryProvider;
+        private final NotificationContentInflaterLogger mLogger;
 
         private AsyncInflationTask(
                 Executor bgExecutor,
@@ -844,7 +884,8 @@
                 RemoteViews.InteractionHandler remoteViewClickHandler,
                 boolean isMediaFlagEnabled,
                 SmartReplyStateInflater smartRepliesInflater,
-                NotifLayoutInflaterFactory.Provider notifLayoutInflaterFactoryProvider) {
+                NotifLayoutInflaterFactory.Provider notifLayoutInflaterFactoryProvider,
+                NotificationContentInflaterLogger logger) {
             mEntry = entry;
             mRow = row;
             mBgExecutor = bgExecutor;
@@ -861,6 +902,7 @@
             mConversationProcessor = conversationProcessor;
             mIsMediaInQS = isMediaFlagEnabled;
             mNotifLayoutInflaterFactoryProvider = notifLayoutInflaterFactoryProvider;
+            mLogger = logger;
             entry.setInflationTask(this);
         }
 
@@ -900,13 +942,16 @@
                     packageContext = new RtlEnabledContext(packageContext);
                 }
                 if (mEntry.getRanking().isConversation()) {
-                    mConversationProcessor.processNotification(mEntry, recoveredBuilder);
+                    mConversationProcessor.processNotification(mEntry, recoveredBuilder, mLogger);
                 }
                 InflationProgress inflationProgress = createRemoteViews(mReInflateFlags,
                         recoveredBuilder, mIsLowPriority, mUsesIncreasedHeight,
                         mUsesIncreasedHeadsUpHeight, packageContext, mRow,
-                        mNotifLayoutInflaterFactoryProvider);
+                        mNotifLayoutInflaterFactoryProvider, mLogger);
+                mLogger.logAsyncTaskProgress(mEntry,
+                        "getting existing smart reply state (on wrong thread!)");
                 InflatedSmartReplyState previousSmartReplyState = mRow.getExistingSmartReplyState();
+                mLogger.logAsyncTaskProgress(mEntry, "inflating smart reply views");
                 InflationProgress result = inflateSmartReplyViews(
                         inflationProgress,
                         mReInflateFlags,
@@ -914,14 +959,20 @@
                         mContext,
                         packageContext,
                         previousSmartReplyState,
-                        mSmartRepliesInflater);
+                        mSmartRepliesInflater,
+                        mLogger);
 
+                mLogger.logAsyncTaskProgress(mEntry,
+                        "getting row image resolver (on wrong thread!)");
+                final NotificationInlineImageResolver imageResolver = mRow.getImageResolver();
                 // wait for image resolver to finish preloading
-                mRow.getImageResolver().waitForPreloadedImages(IMG_PRELOAD_TIMEOUT_MS);
+                mLogger.logAsyncTaskProgress(mEntry, "waiting for preloaded images");
+                imageResolver.waitForPreloadedImages(IMG_PRELOAD_TIMEOUT_MS);
 
                 return result;
             } catch (Exception e) {
                 mError = e;
+                mLogger.logAsyncTaskException(mEntry, "inflating", e);
                 return null;
             }
         }
@@ -929,6 +980,7 @@
         @Override
         protected void onPostExecute(InflationProgress result) {
             if (mError == null) {
+                // Logged in detail in apply.
                 mCancellationSignal = apply(
                         mBgExecutor,
                         mInflateSynchronously,
@@ -938,7 +990,8 @@
                         mEntry,
                         mRow,
                         mRemoteViewClickHandler,
-                        this);
+                        this /* callback */,
+                        mLogger);
             } else {
                 handleError(mError);
             }
@@ -961,10 +1014,13 @@
 
         @Override
         public void abort() {
+            mLogger.logAsyncTaskProgress(mEntry, "cancelling inflate");
             cancel(true /* mayInterruptIfRunning */);
             if (mCancellationSignal != null) {
+                mLogger.logAsyncTaskProgress(mEntry, "cancelling apply");
                 mCancellationSignal.cancel();
             }
+            mLogger.logAsyncTaskProgress(mEntry, "aborted");
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterLogger.kt
new file mode 100644
index 0000000..4f5455d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterLogger.kt
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.row
+
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.core.LogLevel
+import com.android.systemui.log.dagger.NotifInflationLog
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.logKey
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_PUBLIC
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag
+import javax.inject.Inject
+
+class NotificationContentInflaterLogger
+@Inject
+constructor(@NotifInflationLog private val buffer: LogBuffer) {
+    fun logNotBindingRowWasRemoved(entry: NotificationEntry) {
+        buffer.log(
+            TAG,
+            LogLevel.INFO,
+            { str1 = entry.logKey },
+            { "not inflating $str1: row was removed" }
+        )
+    }
+
+    fun logBinding(entry: NotificationEntry, @InflationFlag flag: Int) {
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            {
+                str1 = entry.logKey
+                int1 = flag
+            },
+            { "binding views ${flagToString(int1)} for $str1" }
+        )
+    }
+
+    fun logCancelBindAbortedTask(entry: NotificationEntry) {
+        buffer.log(
+            TAG,
+            LogLevel.INFO,
+            { str1 = entry.logKey },
+            { "aborted task to cancel binding $str1" }
+        )
+    }
+
+    fun logUnbinding(entry: NotificationEntry, @InflationFlag flag: Int) {
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            {
+                str1 = entry.logKey
+                int1 = flag
+            },
+            { "unbinding views ${flagToString(int1)} for $str1" }
+        )
+    }
+
+    fun logAsyncTaskProgress(entry: NotificationEntry, progress: String) {
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            {
+                str1 = entry.logKey
+                str2 = progress
+            },
+            { "async task for $str1: $str2" }
+        )
+    }
+
+    fun logAsyncTaskException(entry: NotificationEntry, logContext: String, exception: Throwable) {
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            {
+                str1 = entry.logKey
+                str2 = logContext
+                str3 = exception.stackTraceToString()
+            },
+            { "async task for $str1 got exception $str2: $str3" }
+        )
+    }
+
+    companion object {
+        fun flagToString(@InflationFlag flag: Int): String {
+            if (flag == 0) {
+                return "NONE"
+            }
+            if (flag == FLAG_CONTENT_VIEW_ALL) {
+                return "ALL"
+            }
+
+            var l = mutableListOf<String>()
+            if (flag and FLAG_CONTENT_VIEW_CONTRACTED != 0) {
+                l.add("CONTRACTED")
+            }
+            if (flag and FLAG_CONTENT_VIEW_EXPANDED != 0) {
+                l.add("EXPANDED")
+            }
+            if (flag and FLAG_CONTENT_VIEW_HEADS_UP != 0) {
+                l.add("HEADS_UP")
+            }
+            if (flag and FLAG_CONTENT_VIEW_PUBLIC != 0) {
+                l.add("PUBLIC")
+            }
+            return l.joinToString("|")
+        }
+    }
+}
+
+private const val TAG = "NotificationContentInflater"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java
index a9f83c8..d7b7aa2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java
@@ -54,8 +54,9 @@
      *
      * @param entry notification
      * @param row notification row to cancel bind on
+     * @return true if an on-going bind operation was cancelled
      */
-    void cancelBind(
+    boolean cancelBind(
             @NonNull NotificationEntry entry,
             @NonNull ExpandableNotificationRow row);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java
index 81cf146..b70da00 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java
@@ -57,7 +57,7 @@
             @NonNull StageCallback callback) {
         RowContentBindParams params = getStageParams(entry);
 
-        mLogger.logStageParams(entry, params);
+        mLogger.logExecutingStage(entry, params);
 
         // Resolve content to bind/unbind.
         @InflationFlag int inflationFlags = params.getContentViews();
@@ -96,7 +96,10 @@
     protected void abortStage(
             @NonNull NotificationEntry entry,
             @NonNull ExpandableNotificationRow row) {
-        mBinder.cancelBind(entry, row);
+        final boolean cancelledBind = mBinder.cancelBind(entry, row);
+        if (cancelledBind) {
+            mLogger.logAbortStageCancelledBind(entry);
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStageLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStageLogger.kt
index 02627fd..1b961cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStageLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStageLogger.kt
@@ -16,22 +16,30 @@
 
 package com.android.systemui.statusbar.notification.row
 
-import com.android.systemui.log.dagger.NotificationLog
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.core.LogLevel.INFO
+import com.android.systemui.log.dagger.NotifInflationLog
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.logKey
 import javax.inject.Inject
 
 class RowContentBindStageLogger @Inject constructor(
-    @NotificationLog private val buffer: LogBuffer
+    @NotifInflationLog private val buffer: LogBuffer
 ) {
-    fun logStageParams(entry: NotificationEntry, stageParams: RowContentBindParams) {
+    fun logExecutingStage(entry: NotificationEntry, stageParams: RowContentBindParams) {
         buffer.log(TAG, INFO, {
             str1 = entry.logKey
             str2 = stageParams.toString()
         }, {
-            "Invalidated notif $str1 with params: $str2"
+            "executing bind stage for $str1 with params $str2"
+        })
+    }
+
+    fun logAbortStageCancelledBind(entry: NotificationEntry) {
+        buffer.log(TAG, INFO, {
+            str1 = entry.logKey
+        }, {
+            "cancelled bind to abort stage for $str1"
         })
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
index ea87c80..e52cb57 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
@@ -135,7 +135,8 @@
                 mock(MediaFeatureFlag.class),
                 mock(Executor.class),
                 mSmartReplyStateInflater,
-                mNotifLayoutInflaterFactoryProvider);
+                mNotifLayoutInflaterFactoryProvider,
+                mock(NotificationContentInflaterLogger.class));
     }
 
     @Test
@@ -258,7 +259,8 @@
                         return new AsyncFailRemoteView(mContext.getPackageName(),
                                 R.layout.custom_view_dark);
                     }
-                });
+                },
+                mock(NotificationContentInflaterLogger.class));
         assertTrue(countDownLatch.await(500, TimeUnit.MILLISECONDS));
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index 9dfcb3f..6386940 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -174,7 +174,8 @@
                 mock(MediaFeatureFlag.class),
                 mock(Executor.class),
                 new MockSmartReplyInflater(),
-                mock(NotifLayoutInflaterFactory.Provider.class));
+                mock(NotifLayoutInflaterFactory.Provider.class),
+                mock(NotificationContentInflaterLogger.class));
         contentBinder.setInflateSynchronously(true);
         mBindStage = new RowContentBindStage(contentBinder,
                 mock(NotifInflationErrorManager.class),