Merge "Add flag for considering flags in PackageCacher" into main
diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig
index 11e8850..37fa9a26 100644
--- a/core/java/android/app/notification.aconfig
+++ b/core/java/android/app/notification.aconfig
@@ -6,6 +6,14 @@
 # flag relates to.
 
 flag {
+  name: "notifications_redesign_app_icons"
+  namespace: "systemui"
+  description: "Notifications Redesign: Use app icons in notification rows (not to be confused with"
+    " notifications_use_app_icons, notifications_use_app_icon_in_row which are just experiments)."
+  bug: "371174789"
+}
+
+flag {
   name: "modes_api"
   is_exported: true
   namespace: "systemui"
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index d08873c..59c6653 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -22,6 +22,7 @@
 import static android.view.InsetsControllerProto.STATE;
 import static android.view.InsetsSource.ID_IME;
 import static android.view.InsetsSource.ID_IME_CAPTION_BAR;
+import static android.view.ViewProtoLogGroups.IME_INSETS_CONTROLLER;
 import static android.view.WindowInsets.Type.FIRST;
 import static android.view.WindowInsets.Type.LAST;
 import static android.view.WindowInsets.Type.all;
@@ -69,6 +70,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.inputmethod.ImeTracing;
 import com.android.internal.inputmethod.SoftInputShowHideReason;
+import com.android.internal.protolog.ProtoLog;
 import com.android.internal.util.function.TriFunction;
 
 import java.io.PrintWriter;
@@ -1920,6 +1922,8 @@
         final @InsetsType int requestedVisibleTypes =
                 (mRequestedVisibleTypes & ~mask) | (visibleTypes & mask);
         if (mRequestedVisibleTypes != requestedVisibleTypes) {
+            ProtoLog.d(IME_INSETS_CONTROLLER, "Setting requestedVisibleTypes to %d (was %d)",
+                    requestedVisibleTypes, mRequestedVisibleTypes);
             mRequestedVisibleTypes = requestedVisibleTypes;
         }
     }
diff --git a/core/java/android/view/ViewProtoLogGroups.java b/core/java/android/view/ViewProtoLogGroups.java
new file mode 100644
index 0000000..099f761
--- /dev/null
+++ b/core/java/android/view/ViewProtoLogGroups.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2024 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 android.view;
+
+import android.annotation.NonNull;
+import android.view.inputmethod.Flags;
+
+import com.android.internal.protolog.ProtoLogGroup;
+
+import java.util.UUID;
+
+/**
+ * Defines logging groups for ProtoLog.
+ *
+ * This file is used by the ProtoLogTool to generate optimized logging code. All of its dependencies
+ * must be included in services.core.wm.protologgroups build target.
+ *
+ * @hide
+ */
+final class ViewProtoLogGroups {
+    final static ProtoLogGroup IME_INSETS_CONTROLLER = new ProtoLogGroup(
+        "IME_INSETS_CONTROLLER", "InsetsController", Flags.refactorInsetsController());
+
+    final static ProtoLogGroup[] ALL_GROUPS = {
+        IME_INSETS_CONTROLLER
+    };
+}
+
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 3be9a82..182ed1e 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -279,6 +279,7 @@
 import com.android.internal.os.SomeArgs;
 import com.android.internal.policy.DecorView;
 import com.android.internal.policy.PhoneFallbackEventHandler;
+import com.android.internal.protolog.ProtoLog;
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.view.BaseSurfaceHolder;
 import com.android.internal.view.RootViewSurfaceTaker;
@@ -1282,6 +1283,8 @@
         mIsStylusPointerIconEnabled =
                 InputSettings.isStylusPointerIconEnabled(mContext);
 
+        initializeProtoLogInProcess();
+
         String processorOverrideName = context.getResources().getString(
                                     R.string.config_inputEventCompatProcessorOverrideClassName);
         if (processorOverrideName.isEmpty()) {
@@ -13403,4 +13406,13 @@
 
         mCurrentColorMode = colorMode;
     }
+
+    private static boolean sProtoLogInitialized = false;
+
+    private void initializeProtoLogInProcess() {
+        if (!sProtoLogInitialized) {
+            ProtoLog.init(ViewProtoLogGroups.ALL_GROUPS);
+            sProtoLogInitialized = true;
+        }
+    }
 }
diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java
index 18c8eb4..de7ad34 100644
--- a/core/java/com/android/internal/app/ResolverListAdapter.java
+++ b/core/java/com/android/internal/app/ResolverListAdapter.java
@@ -1195,7 +1195,12 @@
 
         @Nullable
         protected Drawable loadIconFromResource(Resources res, int resId) {
-            return res.getDrawableForDensity(resId, mIconDpi);
+            try {
+                return res.getDrawableForDensity(resId, mIconDpi);
+            } catch (Resources.NotFoundException e) {
+                Log.e(TAG, "Resource not found", e);
+                return null;
+            }
         }
 
     }
diff --git a/core/java/com/android/internal/widget/NotificationRowIconView.java b/core/java/com/android/internal/widget/NotificationRowIconView.java
index 98e6e85..adcc0f6 100644
--- a/core/java/com/android/internal/widget/NotificationRowIconView.java
+++ b/core/java/com/android/internal/widget/NotificationRowIconView.java
@@ -39,17 +39,24 @@
 
 /**
  * An image view that holds the icon displayed at the start of a notification row.
+ * This can generally either display the "small icon" of a notification set via
+ * {@link this#setImageIcon(Icon)}, or an app icon controlled and fetched by the provider set
+ * through {@link this#setIconProvider(NotificationIconProvider)}.
  */
 @RemoteViews.RemoteView
 public class NotificationRowIconView extends CachingIconView {
+    private NotificationIconProvider mIconProvider;
+
     private boolean mApplyCircularCrop = false;
     private boolean mShouldShowAppIcon = false;
+    private Drawable mAppIcon = null;
 
-    // Padding and background set on the view prior to being changed by setShouldShowAppIcon(true),
-    // to be restored if shouldShowAppIcon becomes false again.
+    // Padding, background and colors set on the view prior to being overridden when showing the app
+    // icon, to be restored if we're showing the small icon again.
     private Rect mOriginalPadding = null;
     private Drawable mOriginalBackground = null;
-
+    private int mOriginalBackgroundColor = ColoredIconHelper.COLOR_INVALID;
+    private int mOriginalIconColor = ColoredIconHelper.COLOR_INVALID;
 
     public NotificationRowIconView(Context context) {
         super(context);
@@ -81,6 +88,71 @@
         super.onFinishInflate();
     }
 
+    /**
+     * Sets the icon provider for this view. This is used to determine whether we should show the
+     * app icon instead of the small icon, and to fetch the app icon if needed.
+     */
+    public void setIconProvider(NotificationIconProvider iconProvider) {
+        mIconProvider = iconProvider;
+    }
+
+    private Drawable loadAppIcon() {
+        if (mIconProvider != null && mIconProvider.shouldShowAppIcon()) {
+            return mIconProvider.getAppIcon();
+        }
+        return null;
+    }
+
+    @RemotableViewMethod(asyncImpl = "setImageIconAsync")
+    @Override
+    public void setImageIcon(Icon icon) {
+        if (Flags.notificationsRedesignAppIcons()) {
+            if (mAppIcon != null) {
+                // We already know that we should be using the app icon, and we already loaded it.
+                // We assume that cannot change throughout the lifetime of a notification, so
+                // there's nothing to do here.
+                return;
+            }
+            mAppIcon = loadAppIcon();
+            if (mAppIcon != null) {
+                setImageDrawable(mAppIcon);
+                adjustViewForAppIcon();
+            } else {
+                super.setImageIcon(icon);
+                restoreViewForSmallIcon();
+            }
+            return;
+        }
+        super.setImageIcon(icon);
+    }
+
+    @RemotableViewMethod
+    @Override
+    public Runnable setImageIconAsync(Icon icon) {
+        if (Flags.notificationsRedesignAppIcons()) {
+            if (mAppIcon != null) {
+                // We already know that we should be using the app icon, and we already loaded it.
+                // We assume that cannot change throughout the lifetime of a notification, so
+                // there's nothing to do here.
+                return () -> {
+                };
+            }
+            mAppIcon = loadAppIcon();
+            if (mAppIcon != null) {
+                return () -> {
+                    setImageDrawable(mAppIcon);
+                    adjustViewForAppIcon();
+                };
+            } else {
+                return () -> {
+                    super.setImageIcon(icon);
+                    restoreViewForSmallIcon();
+                };
+            }
+        }
+        return super.setImageIconAsync(icon);
+    }
+
     /** Whether the icon represents the app icon (instead of the small icon). */
     @RemotableViewMethod
     public void setShouldShowAppIcon(boolean shouldShowAppIcon) {
@@ -91,35 +163,122 @@
 
             mShouldShowAppIcon = shouldShowAppIcon;
             if (mShouldShowAppIcon) {
-                if (mOriginalPadding == null && mOriginalBackground == null) {
-                    mOriginalPadding = new Rect(getPaddingLeft(), getPaddingTop(),
-                            getPaddingRight(), getPaddingBottom());
-                    mOriginalBackground = getBackground();
-                }
-
-                setPadding(0, 0, 0, 0);
-
-                // Make the background white in case the icon itself doesn't have one.
-                ColorFilter colorFilter = new PorterDuffColorFilter(Color.WHITE,
-                        PorterDuff.Mode.SRC_ATOP);
-
-                if (mOriginalBackground == null) {
-                    setBackground(getContext().getDrawable(R.drawable.notification_icon_circle));
-                }
-                getBackground().mutate().setColorFilter(colorFilter);
+                adjustViewForAppIcon();
             } else {
                 // Restore original padding and background if needed
-                if (mOriginalPadding != null) {
-                    setPadding(mOriginalPadding.left, mOriginalPadding.top, mOriginalPadding.right,
-                            mOriginalPadding.bottom);
-                    mOriginalPadding = null;
-                }
-                setBackground(mOriginalBackground);
-                mOriginalBackground = null;
+                restoreViewForSmallIcon();
             }
         }
     }
 
+    /**
+     * Override padding and background from the view to display the app icon.
+     */
+    private void adjustViewForAppIcon() {
+        removePadding();
+
+        if (Flags.notificationsUseAppIconInRow()) {
+            addWhiteBackground();
+        } else {
+            // No need to set the background for notification redesign, since the icon
+            // factory already does that for us.
+            removeBackground();
+        }
+    }
+
+    /**
+     * Restore padding and background overridden by {@link this#adjustViewForAppIcon}.
+     * Does nothing if they were not overridden.
+     */
+    private void restoreViewForSmallIcon() {
+        restorePadding();
+        restoreBackground();
+        restoreColors();
+    }
+
+    private void removePadding() {
+        if (mOriginalPadding == null) {
+            mOriginalPadding = new Rect(getPaddingLeft(), getPaddingTop(),
+                    getPaddingRight(), getPaddingBottom());
+        }
+        setPadding(0, 0, 0, 0);
+    }
+
+    private void restorePadding() {
+        if (mOriginalPadding != null) {
+            setPadding(mOriginalPadding.left, mOriginalPadding.top,
+                    mOriginalPadding.right,
+                    mOriginalPadding.bottom);
+            mOriginalPadding = null;
+        }
+    }
+
+    private void removeBackground() {
+        if (mOriginalBackground == null) {
+            mOriginalBackground = getBackground();
+        }
+
+        setBackground(null);
+    }
+
+    private void addWhiteBackground() {
+        if (mOriginalBackground == null) {
+            mOriginalBackground = getBackground();
+        }
+
+        // Make the background white in case the icon itself doesn't have one.
+        ColorFilter colorFilter = new PorterDuffColorFilter(Color.WHITE,
+                PorterDuff.Mode.SRC_ATOP);
+
+        if (mOriginalBackground == null) {
+            setBackground(getContext().getDrawable(R.drawable.notification_icon_circle));
+        }
+        getBackground().mutate().setColorFilter(colorFilter);
+    }
+
+    private void restoreBackground() {
+        // NOTE: This will not work if the original background was null, but that's better than
+        //  accidentally clearing the background. We expect that there's generally going to be one
+        //  anyway unless we manually clear it.
+        if (mOriginalBackground != null) {
+            setBackground(mOriginalBackground);
+            mOriginalBackground = null;
+        }
+    }
+
+    private void restoreColors() {
+        if (mOriginalBackgroundColor != ColoredIconHelper.COLOR_INVALID) {
+            super.setBackgroundColor(mOriginalBackgroundColor);
+            mOriginalBackgroundColor = ColoredIconHelper.COLOR_INVALID;
+        }
+        if (mOriginalIconColor != ColoredIconHelper.COLOR_INVALID) {
+            super.setOriginalIconColor(mOriginalIconColor);
+            mOriginalIconColor = ColoredIconHelper.COLOR_INVALID;
+        }
+    }
+
+    @RemotableViewMethod
+    @Override
+    public void setBackgroundColor(int color) {
+        // Ignore color overrides if we're showing the app icon.
+        if (mAppIcon == null) {
+            super.setBackgroundColor(color);
+        } else {
+            mOriginalBackgroundColor = color;
+        }
+    }
+
+    @RemotableViewMethod
+    @Override
+    public void setOriginalIconColor(int color) {
+        // Ignore color overrides if we're showing the app icon.
+        if (mAppIcon == null) {
+            super.setOriginalIconColor(color);
+        } else {
+            mOriginalIconColor = color;
+        }
+    }
+
     @Nullable
     @Override
     Drawable loadSizeRestrictedIcon(@Nullable Icon icon) {
@@ -197,4 +356,17 @@
 
         return bitmap;
     }
+
+    /**
+     * A provider that allows this view to verify whether it should use the app icon instead of the
+     * icon provided to it via setImageIcon, as well as actually fetching the app icon. It should
+     * primarily be called on the background thread.
+     */
+    public interface NotificationIconProvider {
+        /** Whether this notification should use the app icon instead of the small icon. */
+        boolean shouldShowAppIcon();
+
+        /** Get the app icon for this notification. */
+        Drawable getAppIcon();
+    }
 }
diff --git a/core/res/res/drawable/ic_zen_mode_icon_piano.xml b/core/res/res/drawable/ic_zen_mode_icon_piano.xml
new file mode 100644
index 0000000..012b939
--- /dev/null
+++ b/core/res/res/drawable/ic_zen_mode_icon_piano.xml
@@ -0,0 +1,25 @@
+<!--
+Copyright (C) 2024 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:tint="?android:attr/colorControlNormal"
+    android:viewportHeight="960"
+    android:viewportWidth="960">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M200,840Q167,840 143.5,816.5Q120,793 120,760L120,200Q120,167 143.5,143.5Q167,120 200,120L760,120Q793,120 816.5,143.5Q840,167 840,200L840,760Q840,793 816.5,816.5Q793,840 760,840L200,840ZM200,760L330,760L330,580L320,580Q303,580 291.5,568.5Q280,557 280,540L280,200L200,200Q200,200 200,200Q200,200 200,200L200,760Q200,760 200,760Q200,760 200,760ZM630,760L760,760Q760,760 760,760Q760,760 760,760L760,200Q760,200 760,200Q760,200 760,200L680,200L680,540Q680,557 668.5,568.5Q657,580 640,580L630,580L630,760ZM390,760L570,760L570,580L560,580Q543,580 531.5,568.5Q520,557 520,540L520,200L440,200L440,540Q440,557 428.5,568.5Q417,580 400,580L390,580L390,760Z" />
+</vector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index c81ffda..eb9cdab 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -1246,9 +1246,12 @@
      */
     public void dragBubbleToDismiss(String bubbleKey, long timestamp) {
         String selectedBubbleKey = mBubbleData.getSelectedBubbleKey();
-        if (mBubbleData.hasAnyBubbleWithKey(bubbleKey)) {
+        Bubble bubbleToDismiss = mBubbleData.getAnyBubbleWithkey(bubbleKey);
+        if (bubbleToDismiss != null) {
             mBubbleData.dismissBubbleWithKey(
                     bubbleKey, Bubbles.DISMISS_USER_GESTURE_FROM_LAUNCHER, timestamp);
+            mLogger.log(bubbleToDismiss,
+                    BubbleLogger.Event.BUBBLE_BAR_BUBBLE_DISMISSED_DRAG_BUBBLE);
         }
         if (mBubbleData.hasBubbles()) {
             // We still have bubbles, if we dragged an individual bubble to dismiss we were expanded
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java
index 0b2b3e7..8592170 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java
@@ -87,7 +87,7 @@
     private final boolean mCalculateRatiosBasedOnAvailableSpace;
     /** Allows split ratios that go offscreen (a.k.a. "flexible split") */
     private final boolean mAllowOffscreenRatios;
-    private final boolean mIsHorizontalDivision;
+    private final boolean mIsLeftRightSplit;
 
     /** The first target which is still splitting the screen */
     private final SnapTarget mFirstSplitTarget;
@@ -101,13 +101,13 @@
 
 
     public DividerSnapAlgorithm(Resources res, int displayWidth, int displayHeight, int dividerSize,
-        boolean isHorizontalDivision, Rect insets, int dockSide) {
-        this(res, displayWidth, displayHeight, dividerSize, isHorizontalDivision, insets,
-            dockSide, false /* minimized */, true /* resizable */);
+            boolean isLeftRightSplit, Rect insets, int dockSide) {
+        this(res, displayWidth, displayHeight, dividerSize, isLeftRightSplit, insets,
+                dockSide, false /* minimized */, true /* resizable */);
     }
 
     public DividerSnapAlgorithm(Resources res, int displayWidth, int displayHeight, int dividerSize,
-            boolean isHorizontalDivision, Rect insets, int dockSide, boolean isMinimizedMode,
+            boolean isLeftRightSplit, Rect insets, int dockSide, boolean isMinimizedMode,
             boolean isHomeResizable) {
         mMinFlingVelocityPxPerSecond =
                 MIN_FLING_VELOCITY_DP_PER_SECOND * res.getDisplayMetrics().density;
@@ -116,7 +116,7 @@
         mDividerSize = dividerSize;
         mDisplayWidth = displayWidth;
         mDisplayHeight = displayHeight;
-        mIsHorizontalDivision = isHorizontalDivision;
+        mIsLeftRightSplit = isLeftRightSplit;
         mInsets.set(insets);
         mSnapMode = isMinimizedMode ? SNAP_MODE_MINIMIZED :
                 res.getInteger(com.android.internal.R.integer.config_dockedStackDividerSnapMode);
@@ -133,7 +133,7 @@
                 Flags.enableFlexibleTwoAppSplit() && SplitScreenUtils.allowOffscreenRatios(res);
         mTaskHeightInMinimizedMode = isHomeResizable ? res.getDimensionPixelSize(
                 com.android.internal.R.dimen.task_height_of_minimized_mode) : 0;
-        calculateTargets(isHorizontalDivision, dockSide);
+        calculateTargets(isLeftRightSplit, dockSide);
         mFirstSplitTarget = mTargets.get(1);
         mLastSplitTarget = mTargets.get(mTargets.size() - 2);
         mDismissStartTarget = mTargets.get(0);
@@ -218,18 +218,18 @@
     }
 
     private int getStartInset() {
-        if (mIsHorizontalDivision) {
-            return mInsets.top;
-        } else {
+        if (mIsLeftRightSplit) {
             return mInsets.left;
+        } else {
+            return mInsets.top;
         }
     }
 
     private int getEndInset() {
-        if (mIsHorizontalDivision) {
-            return mInsets.bottom;
-        } else {
+        if (mIsLeftRightSplit) {
             return mInsets.right;
+        } else {
+            return mInsets.bottom;
         }
     }
 
@@ -269,11 +269,11 @@
         return mTargets.get(minIndex);
     }
 
-    private void calculateTargets(boolean isHorizontalDivision, int dockedSide) {
+    private void calculateTargets(boolean isLeftRightSplit, int dockedSide) {
         mTargets.clear();
-        int dividerMax = isHorizontalDivision
-                ? mDisplayHeight
-                : mDisplayWidth;
+        int dividerMax = isLeftRightSplit
+                ? mDisplayWidth
+                : mDisplayHeight;
         int startPos = -mDividerSize;
         if (dockedSide == DOCKED_RIGHT) {
             startPos += mInsets.left;
@@ -281,38 +281,38 @@
         mTargets.add(new SnapTarget(startPos, SNAP_TO_START_AND_DISMISS, 0.35f));
         switch (mSnapMode) {
             case SNAP_MODE_16_9:
-                addRatio16_9Targets(isHorizontalDivision, dividerMax);
+                addRatio16_9Targets(isLeftRightSplit, dividerMax);
                 break;
             case SNAP_FIXED_RATIO:
-                addFixedDivisionTargets(isHorizontalDivision, dividerMax);
+                addFixedDivisionTargets(isLeftRightSplit, dividerMax);
                 break;
             case SNAP_ONLY_1_1:
-                addMiddleTarget(isHorizontalDivision);
+                addMiddleTarget(isLeftRightSplit);
                 break;
             case SNAP_MODE_MINIMIZED:
-                addMinimizedTarget(isHorizontalDivision, dockedSide);
+                addMinimizedTarget(isLeftRightSplit, dockedSide);
                 break;
         }
         mTargets.add(new SnapTarget(dividerMax, SNAP_TO_END_AND_DISMISS, 0.35f));
     }
 
-    private void addNonDismissingTargets(boolean isHorizontalDivision, int topPosition,
+    private void addNonDismissingTargets(boolean isLeftRightSplit, int topPosition,
             int bottomPosition, int dividerMax) {
         @PersistentSnapPosition int firstTarget =
                 mAllowOffscreenRatios ? SNAP_TO_2_10_90 : SNAP_TO_2_33_66;
         @PersistentSnapPosition int lastTarget =
                 mAllowOffscreenRatios ? SNAP_TO_2_90_10 : SNAP_TO_2_66_33;
         maybeAddTarget(topPosition, topPosition - getStartInset(), firstTarget);
-        addMiddleTarget(isHorizontalDivision);
+        addMiddleTarget(isLeftRightSplit);
         maybeAddTarget(bottomPosition,
                 dividerMax - getEndInset() - (bottomPosition + mDividerSize), lastTarget);
     }
 
-    private void addFixedDivisionTargets(boolean isHorizontalDivision, int dividerMax) {
-        int start = isHorizontalDivision ? mInsets.top : mInsets.left;
-        int end = isHorizontalDivision
-                ? mDisplayHeight - mInsets.bottom
-                : mDisplayWidth - mInsets.right;
+    private void addFixedDivisionTargets(boolean isLeftRightSplit, int dividerMax) {
+        int start = isLeftRightSplit ? mInsets.left : mInsets.top;
+        int end = isLeftRightSplit
+                ? mDisplayWidth - mInsets.right
+                : mDisplayHeight - mInsets.bottom;
         int size = (int) (mFixedRatio * (end - start)) - mDividerSize / 2;
 
         if (mAllowOffscreenRatios) {
@@ -323,23 +323,23 @@
         }
         int topPosition = start + size;
         int bottomPosition = end - size - mDividerSize;
-        addNonDismissingTargets(isHorizontalDivision, topPosition, bottomPosition, dividerMax);
+        addNonDismissingTargets(isLeftRightSplit, topPosition, bottomPosition, dividerMax);
     }
 
-    private void addRatio16_9Targets(boolean isHorizontalDivision, int dividerMax) {
-        int start = isHorizontalDivision ? mInsets.top : mInsets.left;
-        int end = isHorizontalDivision
-                ? mDisplayHeight - mInsets.bottom
-                : mDisplayWidth - mInsets.right;
-        int startOther = isHorizontalDivision ? mInsets.left : mInsets.top;
-        int endOther = isHorizontalDivision
+    private void addRatio16_9Targets(boolean isLeftRightSplit, int dividerMax) {
+        int start = isLeftRightSplit ? mInsets.left : mInsets.top;
+        int end = isLeftRightSplit
                 ? mDisplayWidth - mInsets.right
                 : mDisplayHeight - mInsets.bottom;
+        int startOther = isLeftRightSplit ? mInsets.top : mInsets.left;
+        int endOther = isLeftRightSplit
+                ? mDisplayHeight - mInsets.bottom
+                : mDisplayWidth - mInsets.right;
         float size = 9.0f / 16.0f * (endOther - startOther);
         int sizeInt = (int) Math.floor(size);
         int topPosition = start + sizeInt;
         int bottomPosition = end - sizeInt - mDividerSize;
-        addNonDismissingTargets(isHorizontalDivision, topPosition, bottomPosition, dividerMax);
+        addNonDismissingTargets(isLeftRightSplit, topPosition, bottomPosition, dividerMax);
     }
 
     /**
@@ -352,17 +352,17 @@
         }
     }
 
-    private void addMiddleTarget(boolean isHorizontalDivision) {
-        int position = DockedDividerUtils.calculateMiddlePosition(isHorizontalDivision,
+    private void addMiddleTarget(boolean isLeftRightSplit) {
+        int position = DockedDividerUtils.calculateMiddlePosition(isLeftRightSplit,
                 mInsets, mDisplayWidth, mDisplayHeight, mDividerSize);
         mTargets.add(new SnapTarget(position, SNAP_TO_2_50_50));
     }
 
-    private void addMinimizedTarget(boolean isHorizontalDivision, int dockedSide) {
+    private void addMinimizedTarget(boolean isLeftRightSplit, int dockedSide) {
         // In portrait offset the position by the statusbar height, in landscape add the statusbar
         // height as well to match portrait offset
         int position = mTaskHeightInMinimizedMode + mInsets.top;
-        if (!isHorizontalDivision) {
+        if (isLeftRightSplit) {
             if (dockedSide == DOCKED_LEFT) {
                 position += mInsets.left;
             } else if (dockedSide == DOCKED_RIGHT) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DockedDividerUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DockedDividerUtils.java
index f25dfea..25157c0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DockedDividerUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DockedDividerUtils.java
@@ -97,12 +97,12 @@
         }
     }
 
-    public static int calculateMiddlePosition(boolean isHorizontalDivision, Rect insets,
+    public static int calculateMiddlePosition(boolean isLeftRightSplit, Rect insets,
             int displayWidth, int displayHeight, int dividerSize) {
-        int start = isHorizontalDivision ? insets.top : insets.left;
-        int end = isHorizontalDivision
-                ? displayHeight - insets.bottom
-                : displayWidth - insets.right;
+        int start = isLeftRightSplit ? insets.left : insets.top;
+        int end = isLeftRightSplit
+                ? displayWidth - insets.right
+                : displayHeight - insets.bottom;
         return start + (end - start) / 2 - dividerSize / 2;
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index c9c3aa0..f73065ea 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -665,7 +665,7 @@
                 rootBounds.width(),
                 rootBounds.height(),
                 mDividerSize,
-                !mIsLeftRightSplit,
+                mIsLeftRightSplit,
                 insets,
                 mIsLeftRightSplit ? DOCKED_LEFT : DOCKED_TOP /* dockSide */);
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index 2c621b1f..d3b7ca1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -514,8 +514,12 @@
             ));
         } else {
             mWindowDecorViewHolder.bindData(new AppHeaderViewHolder.HeaderData(
-                    mTaskInfo, TaskInfoKt.getRequestingImmersive(mTaskInfo), inFullImmersive,
-                    hasGlobalFocus
+                    mTaskInfo,
+                    TaskInfoKt.getRequestingImmersive(mTaskInfo),
+                    inFullImmersive,
+                    hasGlobalFocus,
+                    /* maximizeHoverEnabled= */ canOpenMaximizeMenu(
+                            /* animatingTaskResizeOrReposition= */ false)
             ));
         }
         Trace.endSection();
@@ -1616,8 +1620,14 @@
 
     void setAnimatingTaskResizeOrReposition(boolean animatingTaskResizeOrReposition) {
         if (mRelayoutParams.mLayoutResId == R.layout.desktop_mode_app_handle) return;
-        asAppHeader(mWindowDecorViewHolder)
-                .setAnimatingTaskResizeOrReposition(animatingTaskResizeOrReposition);
+        final boolean inFullImmersive =
+                mDesktopRepository.isTaskInFullImmersiveState(mTaskInfo.taskId);
+        asAppHeader(mWindowDecorViewHolder).bindData(new AppHeaderViewHolder.HeaderData(
+                mTaskInfo,
+                TaskInfoKt.getRequestingImmersive(mTaskInfo),
+                inFullImmersive,
+                isFocused(),
+                /* maximizeHoverEnabled= */ canOpenMaximizeMenu(animatingTaskResizeOrReposition)));
     }
 
     /**
@@ -1634,6 +1644,16 @@
         asAppHeader(mWindowDecorViewHolder).onMaximizeWindowHoverEnter();
     }
 
+    private boolean canOpenMaximizeMenu(boolean animatingTaskResizeOrReposition) {
+        if (!Flags.enableFullyImmersiveInDesktop()) {
+            return !animatingTaskResizeOrReposition;
+        }
+        final boolean inImmersiveAndRequesting =
+                mDesktopRepository.isTaskInFullImmersiveState(mTaskInfo.taskId)
+                        && TaskInfoKt.getRequestingImmersive(mTaskInfo);
+        return !animatingTaskResizeOrReposition && !inImmersiveAndRequesting;
+    }
+
     @Override
     public String toString() {
         return "{"
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt
index cf03b3f..d943918 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt
@@ -70,7 +70,7 @@
         rootView: View,
         onCaptionTouchListener: View.OnTouchListener,
         onCaptionButtonClickListener: View.OnClickListener,
-        onLongClickListener: OnLongClickListener,
+        private val onLongClickListener: OnLongClickListener,
         onCaptionGenericMotionListener: View.OnGenericMotionListener,
         appName: CharSequence,
         appIconBitmap: Bitmap,
@@ -81,7 +81,8 @@
         val taskInfo: RunningTaskInfo,
         val isRequestingImmersive: Boolean,
         val inFullImmersiveState: Boolean,
-        val hasGlobalFocus: Boolean
+        val hasGlobalFocus: Boolean,
+        val enableMaximizeLongClick: Boolean,
     ) : Data()
 
     private val decorThemeUtil = DecorThemeUtil(context)
@@ -160,19 +161,30 @@
     }
 
     override fun bindData(data: HeaderData) {
-        bindData(data.taskInfo, data.isRequestingImmersive, data.inFullImmersiveState,
-            data.hasGlobalFocus)
+        bindData(
+            data.taskInfo,
+            data.isRequestingImmersive,
+            data.inFullImmersiveState,
+            data.hasGlobalFocus,
+            data.enableMaximizeLongClick
+        )
     }
 
     private fun bindData(
         taskInfo: RunningTaskInfo,
         isRequestingImmersive: Boolean,
         inFullImmersiveState: Boolean,
-        hasGlobalFocus: Boolean
+        hasGlobalFocus: Boolean,
+        enableMaximizeLongClick: Boolean,
     ) {
         if (DesktopModeFlags.ENABLE_THEMED_APP_HEADERS.isTrue()) {
-            bindDataWithThemedHeaders(taskInfo, isRequestingImmersive, inFullImmersiveState,
-                hasGlobalFocus)
+            bindDataWithThemedHeaders(
+                taskInfo,
+                isRequestingImmersive,
+                inFullImmersiveState,
+                hasGlobalFocus,
+                enableMaximizeLongClick,
+            )
         } else {
             bindDataLegacy(taskInfo, hasGlobalFocus)
         }
@@ -215,7 +227,8 @@
         taskInfo: RunningTaskInfo,
         requestingImmersive: Boolean,
         inFullImmersiveState: Boolean,
-        hasGlobalFocus: Boolean
+        hasGlobalFocus: Boolean,
+        enableMaximizeLongClick: Boolean,
     ) {
         val header = fillHeaderInfo(taskInfo, hasGlobalFocus)
         val headerStyle = getHeaderStyle(header)
@@ -281,6 +294,16 @@
                 drawableInsets = closeDrawableInsets
             )
         }
+        if (!enableMaximizeLongClick) {
+            maximizeButtonView.cancelHoverAnimation()
+        }
+        maximizeButtonView.hoverDisabled = !enableMaximizeLongClick
+        maximizeWindowButton.onLongClickListener = if (enableMaximizeLongClick) {
+            onLongClickListener
+        } else {
+            // Disable long-click to open maximize menu when in immersive.
+            null
+        }
     }
 
     override fun onHandleMenuOpened() {}
@@ -291,14 +314,6 @@
         }
     }
 
-    fun setAnimatingTaskResizeOrReposition(animatingTaskResizeOrReposition: Boolean) {
-        // If animating a task resize or reposition, cancel any running hover animations
-        if (animatingTaskResizeOrReposition) {
-            maximizeButtonView.cancelHoverAnimation()
-        }
-        maximizeButtonView.hoverDisabled = animatingTaskResizeOrReposition
-    }
-
     fun onMaximizeWindowHoverExit() {
         maximizeButtonView.cancelHoverAnimation()
     }
@@ -364,6 +379,11 @@
     private fun shouldShowExitFullImmersiveIcon(
         requestingImmersive: Boolean,
         inFullImmersiveState: Boolean
+    ): Boolean = isInFullImmersiveStateAndRequesting(requestingImmersive, inFullImmersiveState)
+
+    private fun isInFullImmersiveStateAndRequesting(
+        requestingImmersive: Boolean,
+        inFullImmersiveState: Boolean
     ): Boolean = Flags.enableFullyImmersiveInDesktop()
             && requestingImmersive && inFullImmersiveState
 
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt
index 54497f6..2a91bd8 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt
@@ -133,7 +133,14 @@
     Column(
         verticalArrangement = Arrangement.spacedBy(QuickSettingsShade.Dimensions.Padding),
         horizontalAlignment = Alignment.CenterHorizontally,
-        modifier = modifier.fillMaxWidth().padding(QuickSettingsShade.Dimensions.Padding),
+        modifier =
+            modifier
+                .fillMaxWidth()
+                .padding(
+                    start = QuickSettingsShade.Dimensions.Padding,
+                    end = QuickSettingsShade.Dimensions.Padding,
+                    top = QuickSettingsShade.Dimensions.Padding,
+                ),
     ) {
         BrightnessSliderContainer(
             viewModel = viewModel.brightnessSliderViewModel,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
index 7e288dd..9f99c37 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
@@ -631,7 +631,13 @@
                     return@PriorityNestedScrollConnection false
                 }
 
-                _lastPointersInfo = pointersInfoOwner.pointersInfo()
+                val pointersInfo = pointersInfoOwner.pointersInfo()
+
+                if (pointersInfo.isMouseWheel) {
+                    // Do not support mouse wheel interactions
+                    return@PriorityNestedScrollConnection false
+                }
+                _lastPointersInfo = pointersInfo
 
                 // If the current swipe transition is *not* closed to 0f or 1f, then we want the
                 // scroll events to intercept the current transition to continue the scene
@@ -650,7 +656,12 @@
                 val isZeroOffset =
                     if (isExternalOverscrollGesture()) false else offsetBeforeStart == 0f
 
-                _lastPointersInfo = pointersInfoOwner.pointersInfo()
+                val pointersInfo = pointersInfoOwner.pointersInfo()
+                if (pointersInfo.isMouseWheel) {
+                    // Do not support mouse wheel interactions
+                    return@PriorityNestedScrollConnection false
+                }
+                _lastPointersInfo = pointersInfo
 
                 val canStart =
                     when (behavior) {
@@ -685,7 +696,12 @@
                 // We could start an overscroll animation
                 canChangeScene = false
 
-                _lastPointersInfo = pointersInfoOwner.pointersInfo()
+                val pointersInfo = pointersInfoOwner.pointersInfo()
+                if (pointersInfo.isMouseWheel) {
+                    // Do not support mouse wheel interactions
+                    return@PriorityNestedScrollConnection false
+                }
+                _lastPointersInfo = pointersInfo
 
                 val canStart = behavior.canStartOnPostFling && hasNextScene(velocityAvailable)
                 if (canStart) {
@@ -707,6 +723,12 @@
             onScroll = { offsetAvailable, _ ->
                 val controller = dragController ?: error("Should be called after onStart")
 
+                val pointersInfo = pointersInfoOwner.pointersInfo()
+                if (pointersInfo.isMouseWheel) {
+                    // Do not support mouse wheel interactions
+                    return@PriorityNestedScrollConnection 0f
+                }
+
                 // TODO(b/297842071) We should handle the overscroll or slow drag if the gesture is
                 // initiated in a nested child.
                 controller.onDrag(delta = offsetAvailable)
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
index aa70a0c..8613f6d 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
@@ -29,6 +29,7 @@
 import androidx.compose.ui.input.pointer.AwaitPointerEventScope
 import androidx.compose.ui.input.pointer.PointerEvent
 import androidx.compose.ui.input.pointer.PointerEventPass
+import androidx.compose.ui.input.pointer.PointerEventType
 import androidx.compose.ui.input.pointer.PointerId
 import androidx.compose.ui.input.pointer.PointerInputChange
 import androidx.compose.ui.input.pointer.PointerInputScope
@@ -184,6 +185,7 @@
 
     private var startedPosition: Offset? = null
     private var pointersDown: Int = 0
+    private var isMouseWheel: Boolean = false
 
     internal fun pointersInfo(): PointersInfo {
         return PointersInfo(
@@ -191,6 +193,7 @@
             startedPosition = startedPosition,
             // We could have 0 pointers during fling or for other reasons.
             pointersDown = pointersDown.coerceAtLeast(1),
+            isMouseWheel = isMouseWheel,
         )
     }
 
@@ -202,8 +205,15 @@
             // [requireAncestorPointersInfoOwner], to our descendants.
             while (currentContext.isActive) {
                 // During the Initial pass, we receive the event after our ancestors.
-                val changes = awaitPointerEvent(PointerEventPass.Initial).changes
+                val pointerEvent = awaitPointerEvent(PointerEventPass.Initial)
+
+                // Ignore cursor has entered the input region.
+                // This will only be sent after the cursor is hovering when in the input region.
+                if (pointerEvent.type == PointerEventType.Enter) continue
+
+                val changes = pointerEvent.changes
                 pointersDown = changes.countDown()
+                isMouseWheel = pointerEvent.type == PointerEventType.Scroll
 
                 when {
                     // There are no more pointers down.
@@ -223,7 +233,8 @@
 
                     // The first pointer down, startedPosition was not set.
                     startedPosition == null -> {
-                        val firstPointerDown = changes.single()
+                        // Mouse wheel could start with multiple pointer down
+                        val firstPointerDown = changes.first()
                         velocityPointerId = firstPointerDown.id
                         velocityTracker.resetTracking()
                         velocityTracker.addPointerInputChange(firstPointerDown)
@@ -647,4 +658,8 @@
     fun pointersInfo(): PointersInfo
 }
 
-internal data class PointersInfo(val startedPosition: Offset?, val pointersDown: Int)
+internal data class PointersInfo(
+    val startedPosition: Offset?,
+    val pointersDown: Int,
+    val isMouseWheel: Boolean,
+)
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
index 2657d7c..3c3c612 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
@@ -430,6 +430,10 @@
                     // Replace the transition.
                     transitionStates =
                         transitionStates.subList(0, transitionStates.lastIndex) + transition
+
+                    // Make sure it is removed from the finishedTransitions set if it was already
+                    // finished.
+                    finishedTransitions.remove(currentState)
                 } else {
                     // Append the new transition.
                     transitionStates = transitionStates + transition
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
index 57b9423..a0fed90 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
@@ -127,7 +127,7 @@
         val horizontalDraggableHandler = layoutImpl.draggableHandler(Orientation.Horizontal)
 
         var pointerInfoOwner: () -> PointersInfo = {
-            PointersInfo(startedPosition = Offset.Zero, pointersDown = 1)
+            PointersInfo(startedPosition = Offset.Zero, pointersDown = 1, isMouseWheel = false)
         }
 
         fun nestedScrollConnection(
@@ -1187,7 +1187,9 @@
         val nestedScroll = nestedScrollConnection(nestedScrollBehavior = EdgeAlways)
 
         // Drag from the **top** of the screen
-        pointerInfoOwner = { PointersInfo(startedPosition = Offset(0f, 0f), pointersDown = 1) }
+        pointerInfoOwner = {
+            PointersInfo(startedPosition = Offset(0f, 0f), pointersDown = 1, isMouseWheel = false)
+        }
         assertIdle(currentScene = SceneC)
 
         nestedScroll.scroll(available = upOffset(fractionOfScreen = 0.1f))
@@ -1205,7 +1207,11 @@
 
         // Drag from the **bottom** of the screen
         pointerInfoOwner = {
-            PointersInfo(startedPosition = Offset(0f, SCREEN_SIZE), pointersDown = 1)
+            PointersInfo(
+                startedPosition = Offset(0f, SCREEN_SIZE),
+                pointersDown = 1,
+                isMouseWheel = false,
+            )
         }
         assertIdle(currentScene = SceneC)
 
@@ -1220,6 +1226,22 @@
     }
 
     @Test
+    fun ignoreMouseWheel() = runGestureTest {
+        // Start at scene C.
+        navigateToSceneC()
+        val nestedScroll = nestedScrollConnection(nestedScrollBehavior = EdgeAlways)
+
+        // Use mouse wheel
+        pointerInfoOwner = {
+            PointersInfo(startedPosition = Offset(0f, 0f), pointersDown = 1, isMouseWheel = true)
+        }
+        assertIdle(currentScene = SceneC)
+
+        nestedScroll.scroll(available = upOffset(fractionOfScreen = 0.1f))
+        assertIdle(currentScene = SceneC)
+    }
+
+    @Test
     fun transitionIsImmediatelyUpdatedWhenReleasingFinger() = runGestureTest {
         // Swipe up from the middle to transition to scene B.
         val middle = Offset(SCREEN_SIZE / 2f, SCREEN_SIZE / 2f)
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
index f3a3488..f5bb5ba 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
@@ -727,4 +727,45 @@
         // The previous job is cancelled and does not infinitely collect the progress.
         job.join()
     }
+
+    @Test
+    fun replacedTransitionIsRemovedFromFinishedTransitions() = runTest {
+        val state = MutableSceneTransitionLayoutState(SceneA)
+
+        val aToB =
+            transition(
+                SceneA,
+                SceneB,
+                onFreezeAndAnimate = {
+                    // Do nothing, so that this transition stays in the transitionStates list and we
+                    // can finish() it manually later.
+                },
+            )
+        val replacingAToB = transition(SceneB, SceneC)
+        val replacingBToC = transition(SceneB, SceneC, replacedTransition = replacingAToB)
+
+        // Start A => B.
+        val aToBJob = state.startTransitionImmediately(animationScope = this, aToB)
+
+        // Start B => C and immediately finish it. It will be flagged as finished in
+        // STLState.finishedTransitions given that A => B is not finished yet.
+        val bToCJob = state.startTransitionImmediately(animationScope = this, replacingAToB)
+        replacingAToB.finish()
+        bToCJob.join()
+
+        // Start a new B => C that replaces the previously finished B => C.
+        val replacingBToCJob =
+            state.startTransitionImmediately(animationScope = this, replacingBToC)
+
+        // Finish A => B.
+        aToB.finish()
+        aToBJob.join()
+
+        // Finish the new B => C.
+        replacingBToC.finish()
+        replacingBToCJob.join()
+
+        assertThat(state.transitionState).isIdle()
+        assertThat(state.transitionState).hasCurrentScene(SceneC)
+    }
 }
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
index 1711f31..3001505 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
@@ -17,6 +17,8 @@
 package com.android.compose.animation.scene
 
 import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.gestures.rememberScrollableState
+import androidx.compose.foundation.gestures.scrollable
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxSize
@@ -39,12 +41,14 @@
 import androidx.compose.ui.platform.LocalLayoutDirection
 import androidx.compose.ui.platform.LocalViewConfiguration
 import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.ScrollWheel
 import androidx.compose.ui.test.assertPositionInRootIsEqualTo
 import androidx.compose.ui.test.assertTextEquals
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.compose.ui.test.onNodeWithTag
 import androidx.compose.ui.test.onRoot
 import androidx.compose.ui.test.performClick
+import androidx.compose.ui.test.performMouseInput
 import androidx.compose.ui.test.performTouchInput
 import androidx.compose.ui.test.swipeRight
 import androidx.compose.ui.test.swipeUp
@@ -498,6 +502,89 @@
     }
 
     @Test
+    fun mouseWheel_pointerInputApi_ignoredByStl() {
+        val layoutState = layoutState()
+        var touchSlop = 0f
+        rule.setContent {
+            touchSlop = LocalViewConfiguration.current.touchSlop
+            TestContent(layoutState)
+        }
+
+        rule.onRoot().performMouseInput {
+            enter(middle)
+            scroll(touchSlop, ScrollWheel.Vertical)
+        }
+
+        // Mouse wheel scroll are ignored
+        assertThat(layoutState.currentTransition).isNull()
+    }
+
+    @Test
+    fun mouseWheel_scrollableCannotScroll_ignoredByStl() {
+        val layoutState = layoutState()
+        var touchSlop = 0f
+        rule.setContent {
+            touchSlop = LocalViewConfiguration.current.touchSlop
+            SceneTransitionLayout(layoutState, Modifier.size(LayoutWidth, LayoutHeight)) {
+                scene(SceneA, userActions = mapOf(Swipe.Down to SceneB)) {
+                    Box(
+                        Modifier.fillMaxSize()
+                            // A scrollable that does not consume the scroll gesture
+                            .scrollable(rememberScrollableState { 0f }, Orientation.Vertical)
+                    )
+                }
+                scene(SceneB) { Box(Modifier.fillMaxSize()) }
+            }
+        }
+
+        rule.onRoot().performMouseInput {
+            enter(middle)
+            scroll(touchSlop, ScrollWheel.Vertical)
+        }
+
+        // Mouse wheel scroll are ignored
+        assertThat(layoutState.currentTransition).isNull()
+    }
+
+    @Test
+    fun mouseWheel_scrollableConsume_ignoredByStl() {
+        val layoutState = layoutState()
+        var touchSlop = 0f
+        var lastScroll = 0f
+        rule.setContent {
+            touchSlop = LocalViewConfiguration.current.touchSlop
+            SceneTransitionLayout(layoutState, Modifier.size(LayoutWidth, LayoutHeight)) {
+                scene(SceneA, userActions = mapOf(Swipe.Down to SceneB)) {
+                    Box(
+                        Modifier.fillMaxSize()
+                            // A scrollable that consumes the scroll gesture
+                            .scrollable(
+                                rememberScrollableState {
+                                    lastScroll = it
+                                    it
+                                },
+                                Orientation.Vertical,
+                            )
+                    )
+                }
+                scene(SceneB) { Box(Modifier.fillMaxSize()) }
+            }
+        }
+
+        rule.onRoot().performMouseInput {
+            enter(middle)
+            scroll(touchSlop * 10, ScrollWheel.Vertical)
+        }
+
+        // Mouse wheel scroll are ignored
+        assertThat(layoutState.currentTransition).isNull()
+
+        // Mouse wheel scroll can still be consumed by the scrollable
+        assertThat(lastScroll).isNotEqualTo(0f)
+        assertThat(touchSlop).isNotEqualTo(0f)
+    }
+
+    @Test
     fun transitionKey() {
         val transitionkey = TransitionKey(debugName = "foo")
         val state =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
index 8d678ef..bf14472 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelTest.kt
@@ -21,7 +21,6 @@
 import android.platform.test.annotations.EnableFlags
 import android.platform.test.flag.junit.FlagsParameterization
 import androidx.test.filters.SmallTest
-import com.android.app.tracing.coroutines.flow.map
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.flags.DisableSceneContainer
@@ -51,6 +50,7 @@
 import com.android.systemui.util.ui.value
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt
index b8f5815..a4b3916 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt
@@ -35,7 +35,7 @@
         val drawable =
             BitmapDrawable(
                 resources,
-                Bitmap.createBitmap(resources.displayMetrics, 150, 150, Bitmap.Config.ARGB_8888)
+                Bitmap.createBitmap(resources.displayMetrics, 150, 150, Bitmap.Config.ARGB_8888),
             )
         val result = DrawableSize.downscaleToSize(resources, drawable, 300, 300)
         assertThat(result).isSameInstanceAs(drawable)
@@ -48,7 +48,7 @@
         val drawable =
             BitmapDrawable(
                 resources,
-                Bitmap.createBitmap(resources.displayMetrics, 150, 75, Bitmap.Config.ARGB_8888)
+                Bitmap.createBitmap(resources.displayMetrics, 150, 75, Bitmap.Config.ARGB_8888),
             )
 
         val result = DrawableSize.downscaleToSize(resources, drawable, 75, 75)
@@ -64,4 +64,31 @@
         val result = DrawableSize.downscaleToSize(resources, drawable, 1, 1)
         assertThat(result).isSameInstanceAs(drawable)
     }
+
+    @Test
+    fun testDownscaleToSize_layerDrawable_allLayersSameType_resized() {
+        val drawable =
+            resources.getDrawable(
+                com.android.systemui.tests.R.drawable.layer_drawable_all_same_type,
+                resources.newTheme(),
+            )
+
+        val result = DrawableSize.downscaleToSize(resources, drawable, 1, 1)
+
+        assertThat(result).isNotSameInstanceAs(drawable)
+    }
+
+    /** Regression test for b/244282477. */
+    @Test
+    fun testDownscaleToSize_layerDrawable_layersAreDifferentTypes_unchanged() {
+        val drawable =
+            resources.getDrawable(
+                com.android.systemui.tests.R.drawable.layer_drawable_different_types,
+                resources.newTheme(),
+            )
+
+        val result = DrawableSize.downscaleToSize(resources, drawable, 1, 1)
+
+        assertThat(result).isSameInstanceAs(drawable)
+    }
 }
diff --git a/packages/SystemUI/res/layout/super_notification_shade.xml b/packages/SystemUI/res/layout/super_notification_shade.xml
index 22d34eb..fbb07be 100644
--- a/packages/SystemUI/res/layout/super_notification_shade.xml
+++ b/packages/SystemUI/res/layout/super_notification_shade.xml
@@ -58,6 +58,14 @@
              android:layout_height="match_parent"
              android:visibility="invisible" />
 
+    <!-- Root for all keyguard content. It was previously located within the shade. -->
+    <com.android.systemui.keyguard.ui.view.KeyguardRootView
+        android:id="@id/keyguard_root_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:clipChildren="false"
+        />
+
     <!-- Shared container for the notification stack. Can be positioned by either
          the keyguard_root_view or notification_panel -->
     <com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
@@ -68,14 +76,6 @@
         android:clipToPadding="false"
         />
 
-    <!-- Root for all keyguard content. It was previously located within the shade. -->
-    <com.android.systemui.keyguard.ui.view.KeyguardRootView
-        android:id="@id/keyguard_root_view"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:clipChildren="false"
-        />
-
     <include layout="@layout/brightness_mirror_container" />
 
     <com.android.systemui.scrim.ScrimView
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModel.kt
index 4185aed..148b9ea 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/AuthMethodBouncerViewModel.kt
@@ -17,7 +17,6 @@
 package com.android.systemui.bouncer.ui.viewmodel
 
 import android.annotation.StringRes
-import com.android.app.tracing.coroutines.flow.collectLatest
 import com.android.systemui.authentication.domain.interactor.AuthenticationResult
 import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
 import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
@@ -28,6 +27,7 @@
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.collectLatest
 import kotlinx.coroutines.flow.receiveAsFlow
 
 sealed class AuthMethodBouncerViewModel(
diff --git a/packages/SystemUI/src/com/android/systemui/common/usagestats/data/repository/UsageStatsRepository.kt b/packages/SystemUI/src/com/android/systemui/common/usagestats/data/repository/UsageStatsRepository.kt
index e3f1174..a695163 100644
--- a/packages/SystemUI/src/com/android/systemui/common/usagestats/data/repository/UsageStatsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/usagestats/data/repository/UsageStatsRepository.kt
@@ -19,7 +19,7 @@
 import android.app.usage.UsageEvents
 import android.app.usage.UsageEventsQuery
 import android.app.usage.UsageStatsManager
-import com.android.app.tracing.coroutines.withContext
+import com.android.app.tracing.coroutines.withContextTraced as withContext
 import com.android.systemui.common.usagestats.data.model.UsageStatsQuery
 import com.android.systemui.common.usagestats.shared.model.ActivityEventModel
 import com.android.systemui.common.usagestats.shared.model.ActivityEventModel.Lifecycle
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
index 3a04d02..dc24805 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
@@ -23,7 +23,7 @@
 import android.os.UserHandle
 import android.os.UserManager
 import android.provider.Settings
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.compose.animation.scene.SceneKey
 import com.android.compose.animation.scene.TransitionKey
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt
index 3826fb4..428b83d 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt
@@ -16,7 +16,7 @@
 
 package com.android.systemui.communal.domain.interactor
 
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.compose.animation.scene.SceneKey
 import com.android.compose.animation.scene.TransitionKey
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/binder/CommunalAppWidgetHostViewBinder.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/binder/CommunalAppWidgetHostViewBinder.kt
index ba96f4e..71bfe0c 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/binder/CommunalAppWidgetHostViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/binder/CommunalAppWidgetHostViewBinder.kt
@@ -24,8 +24,7 @@
 import android.widget.FrameLayout
 import androidx.compose.ui.unit.IntSize
 import androidx.core.view.doOnLayout
-import com.android.app.tracing.coroutines.flow.flowOn
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.Flags.communalWidgetResizing
 import com.android.systemui.common.ui.view.onLayoutChanged
 import com.android.systemui.communal.domain.model.CommunalContentModel
@@ -41,6 +40,7 @@
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOn
 
 object CommunalAppWidgetHostViewBinder {
     private const val TAG = "CommunalAppWidgetHostViewBinder"
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/ResizeableItemFrameViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/ResizeableItemFrameViewModel.kt
index 87fcdd7..a519649 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/ResizeableItemFrameViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/ResizeableItemFrameViewModel.kt
@@ -19,7 +19,7 @@
 import androidx.compose.foundation.gestures.AnchoredDraggableState
 import androidx.compose.foundation.gestures.DraggableAnchors
 import androidx.compose.runtime.snapshotFlow
-import com.android.app.tracing.coroutines.coroutineScope
+import com.android.app.tracing.coroutines.coroutineScopeTraced as coroutineScope
 import com.android.systemui.lifecycle.ExclusiveActivatable
 import kotlinx.coroutines.awaitCancellation
 import kotlinx.coroutines.flow.Flow
diff --git a/packages/SystemUI/src/com/android/systemui/communal/util/WidgetViewFactory.kt b/packages/SystemUI/src/com/android/systemui/communal/util/WidgetViewFactory.kt
index 07a7c7cb..d5d3a92 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/util/WidgetViewFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/util/WidgetViewFactory.kt
@@ -19,7 +19,7 @@
 import android.content.Context
 import android.os.Bundle
 import android.util.SizeF
-import com.android.app.tracing.coroutines.withContext
+import com.android.app.tracing.coroutines.withContextTraced as withContext
 import com.android.systemui.communal.domain.model.CommunalContentModel
 import com.android.systemui.communal.widgets.AppWidgetHostListenerDelegate
 import com.android.systemui.communal.widgets.CommunalAppWidgetHost
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetInteractionHandler.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetInteractionHandler.kt
index 542b988..c894267 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetInteractionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetInteractionHandler.kt
@@ -21,7 +21,7 @@
 import android.content.Intent
 import android.view.View
 import android.widget.RemoteViews
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.systemui.Flags.communalWidgetTrampolineFix
 import com.android.systemui.animation.ActivityTransitionAnimator
diff --git a/packages/SystemUI/src/com/android/systemui/coroutines/Tracing.kt b/packages/SystemUI/src/com/android/systemui/coroutines/Tracing.kt
new file mode 100644
index 0000000..5b1c9c8b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/coroutines/Tracing.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 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.coroutines
+
+import com.android.app.tracing.coroutines.createCoroutineTracingContext
+import kotlin.coroutines.CoroutineContext
+
+fun newTracingContext(name: String): CoroutineContext {
+    return createCoroutineTracingContext(name) { className ->
+        className.startsWith("com.android.systemui.util.kotlin.JavaAdapter") ||
+            className.startsWith("com.android.systemui.lifecycle.RepeatWhenAttached")
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayScopeRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayScopeRepository.kt
index 3062475..e3fce00 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayScopeRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayScopeRepository.kt
@@ -17,8 +17,8 @@
 package com.android.systemui.display.data.repository
 
 import android.view.Display
-import com.android.app.tracing.coroutines.createCoroutineTracingContext
 import com.android.systemui.CoreStartable
+import com.android.systemui.coroutines.newTracingContext
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
@@ -69,7 +69,7 @@
             backgroundApplicationScope
         } else {
             CoroutineScope(
-                backgroundDispatcher + createCoroutineTracingContext("DisplayScope$displayId")
+                backgroundDispatcher + newTracingContext("DisplayScope$displayId")
             )
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/homecontrols/HomeControlsDreamService.kt b/packages/SystemUI/src/com/android/systemui/dreams/homecontrols/HomeControlsDreamService.kt
index 3992c3f..724f1c5 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/homecontrols/HomeControlsDreamService.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/homecontrols/HomeControlsDreamService.kt
@@ -22,6 +22,7 @@
 import android.service.dreams.DreamService
 import android.window.TaskFragmentInfo
 import com.android.systemui.controls.settings.ControlsSettingsRepository
+import com.android.systemui.coroutines.newTracingContext
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dreams.DreamLogger
 import com.android.systemui.dreams.homecontrols.domain.interactor.HomeControlsComponentInteractor
@@ -39,7 +40,6 @@
 import kotlinx.coroutines.cancel
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.launch
-import com.android.app.tracing.coroutines.createCoroutineTracingContext
 
 class HomeControlsDreamService
 @Inject
@@ -54,7 +54,8 @@
 ) : DreamService() {
 
     private val serviceJob = SupervisorJob()
-    private val serviceScope = CoroutineScope(bgDispatcher + serviceJob + createCoroutineTracingContext("HomeControlsDreamService"))
+    private val serviceScope =
+        CoroutineScope(bgDispatcher + serviceJob + newTracingContext("HomeControlsDreamService"))
     private val logger = DreamLogger(logBuffer, TAG)
     private lateinit var taskFragmentComponent: TaskFragmentComponent
     private val wakeLock: WakeLock by lazy {
diff --git a/packages/SystemUI/src/com/android/systemui/education/dagger/ContextualEducationModule.kt b/packages/SystemUI/src/com/android/systemui/education/dagger/ContextualEducationModule.kt
index 4caf95b..7fa7da1 100644
--- a/packages/SystemUI/src/com/android/systemui/education/dagger/ContextualEducationModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/education/dagger/ContextualEducationModule.kt
@@ -16,10 +16,10 @@
 
 package com.android.systemui.education.dagger
 
-import com.android.app.tracing.coroutines.createCoroutineTracingContext
 import com.android.systemui.CoreStartable
 import com.android.systemui.Flags
 import com.android.systemui.contextualeducation.GestureType
+import com.android.systemui.coroutines.newTracingContext
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.education.data.repository.ContextualEducationRepository
 import com.android.systemui.education.data.repository.UserContextualEducationRepository
@@ -57,7 +57,9 @@
         fun provideEduDataStoreScope(
             @Background bgDispatcher: CoroutineDispatcher
         ): CoroutineScope {
-            return CoroutineScope(bgDispatcher + SupervisorJob() + createCoroutineTracingContext("EduDataStoreScope"))
+            return CoroutineScope(
+                bgDispatcher + SupervisorJob() + newTracingContext("EduDataStoreScope")
+            )
         }
 
         @EduClock
diff --git a/packages/SystemUI/src/com/android/systemui/haptics/slider/compose/ui/SliderHapticsViewModel.kt b/packages/SystemUI/src/com/android/systemui/haptics/slider/compose/ui/SliderHapticsViewModel.kt
index e396767..1dbcb3df 100644
--- a/packages/SystemUI/src/com/android/systemui/haptics/slider/compose/ui/SliderHapticsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/haptics/slider/compose/ui/SliderHapticsViewModel.kt
@@ -22,7 +22,7 @@
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.input.pointer.util.VelocityTracker
 import androidx.compose.ui.unit.Velocity
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.haptics.slider.SeekableSliderTrackerConfig
 import com.android.systemui.haptics.slider.SliderDragVelocityProvider
 import com.android.systemui.haptics.slider.SliderEventType
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt b/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
index 6df8355..a94df09 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/CustomizationProvider.kt
@@ -30,7 +30,7 @@
 import android.os.Binder
 import android.os.Bundle
 import android.util.Log
-import com.android.app.tracing.coroutines.runBlocking
+import com.android.app.tracing.coroutines.runBlockingTraced as runBlocking
 import com.android.systemui.SystemUIAppComponentFactoryBase
 import com.android.systemui.SystemUIAppComponentFactoryBase.ContextAvailableCallback
 import com.android.systemui.dagger.qualifiers.Main
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
index 690ae71..b7d0d45 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
@@ -24,7 +24,7 @@
 import android.os.Trace
 import android.util.Log
 import com.android.app.animation.Interpolators
-import com.android.app.tracing.coroutines.withContext
+import com.android.app.tracing.coroutines.withContextTraced as withContext
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.keyguard.shared.model.KeyguardState
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
index 4cf9ec8..9896365 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
@@ -19,7 +19,7 @@
 import android.animation.ValueAnimator
 import android.util.Log
 import com.android.app.animation.Interpolators
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
index 9a0a858..7b75765 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
@@ -20,7 +20,7 @@
 import android.annotation.SuppressLint
 import android.app.DreamManager
 import com.android.app.animation.Interpolators
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.Flags.communalSceneKtfRefactor
 import com.android.systemui.communal.domain.interactor.CommunalInteractor
 import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
index 6b6a3dce..a6f0db5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
@@ -18,7 +18,7 @@
 
 import android.animation.ValueAnimator
 import com.android.app.animation.Interpolators
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.Flags.communalSceneKtfRefactor
 import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
 import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
index 58c8a04..606a7a9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
@@ -18,7 +18,7 @@
 
 import android.animation.ValueAnimator
 import com.android.app.animation.Interpolators
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index 6d1d9cb..4d37276 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -19,7 +19,7 @@
 import android.animation.ValueAnimator
 import android.util.MathUtils
 import com.android.app.animation.Interpolators
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.Flags.communalSceneKtfRefactor
 import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor
 import com.android.systemui.dagger.SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
index 2c3b481..26bf26b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
@@ -22,7 +22,7 @@
 import android.content.Context
 import android.content.Intent
 import android.util.Log
-import com.android.app.tracing.coroutines.withContext
+import com.android.app.tracing.coroutines.withContextTraced as withContext
 import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.internal.widget.LockPatternUtils
 import com.android.keyguard.logging.KeyguardQuickAffordancesLogger
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerMessageAreaViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerMessageAreaViewBinder.kt
index fe5f632..23b7b66 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerMessageAreaViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerMessageAreaViewBinder.kt
@@ -18,7 +18,7 @@
 
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.keyguard.AuthKeyguardMessageArea
 import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerMessageAreaViewModel
 import com.android.systemui.lifecycle.repeatWhenAttached
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerUdfpsViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerUdfpsViewBinder.kt
index 7ca2c20..6ef9863 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerUdfpsViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerUdfpsViewBinder.kt
@@ -21,7 +21,7 @@
 import android.view.View
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.keyguard.ui.view.DeviceEntryIconView
 import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerUdfpsIconViewModel
 import com.android.systemui.lifecycle.repeatWhenAttached
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt
index 1891af2..7a36899 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt
@@ -29,7 +29,7 @@
 import androidx.constraintlayout.widget.ConstraintSet
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.CoreStartable
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
index a3f3342..6c104a0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
@@ -28,7 +28,7 @@
 import androidx.core.view.isInvisible
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.common.ui.view.LongPressHandlingView
 import com.android.systemui.keyguard.ui.view.DeviceEntryIconView
 import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryBackgroundViewModel
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt
index 0470e08..5bad016 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBlueprintViewBinder.kt
@@ -22,7 +22,7 @@
 import androidx.constraintlayout.widget.ConstraintSet
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.customization.R as customR
 import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
 import com.android.systemui.keyguard.shared.model.KeyguardBlueprint
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
index 660a650..3bdf7da 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
@@ -36,7 +36,7 @@
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
 import com.android.app.animation.Interpolators
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.settingslib.Utils
 import com.android.systemui.animation.ActivityTransitionAnimator
 import com.android.systemui.animation.Expandable
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardIndicationAreaBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardIndicationAreaBinder.kt
index ba94f45..8b947a3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardIndicationAreaBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardIndicationAreaBinder.kt
@@ -22,7 +22,7 @@
 import android.widget.TextView
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.keyguard.KeyguardBottomAreaRefactor
 import com.android.systemui.keyguard.MigrateClocksToBlueprint
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardIndicationAreaViewModel
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressViewBinder.kt
index 76d3389..2fd9818 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardLongPressViewBinder.kt
@@ -22,7 +22,7 @@
 import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.common.ui.view.LongPressHandlingView
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardTouchHandlingViewModel
 import com.android.systemui.lifecycle.repeatWhenAttached
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt
index 2d22556..210f4cd 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt
@@ -33,7 +33,7 @@
 import androidx.core.view.isVisible
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.internal.policy.SystemBarUtils
 import com.android.systemui.customization.R as customR
 import com.android.systemui.keyguard.shared.model.ClockSizeSetting
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewSmartspaceViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewSmartspaceViewBinder.kt
index 4b75b80..baa6812 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewSmartspaceViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewSmartspaceViewBinder.kt
@@ -22,7 +22,7 @@
 import androidx.core.view.isInvisible
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.keyguard.shared.model.ClockSizeSetting
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardPreviewSmartspaceViewModel
 import com.android.systemui.lifecycle.repeatWhenAttached
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt
index 27dd18d..cfd6481 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardQuickAffordanceViewBinder.kt
@@ -30,7 +30,7 @@
 import androidx.core.view.updateLayoutParams
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.keyguard.logging.KeyguardQuickAffordancesLogger
 import com.android.settingslib.Utils
 import com.android.systemui.animation.Expandable
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
index ea70fd0..89bca0c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
@@ -39,7 +39,7 @@
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
 import com.android.app.animation.Interpolators
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.internal.jank.InteractionJankMonitor
 import com.android.internal.jank.InteractionJankMonitor.CUJ_SCREEN_OFF_SHOW_AOD
 import com.android.keyguard.AuthInteractionProperties
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSettingsViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSettingsViewBinder.kt
index 4150ceb..79360370 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSettingsViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSettingsViewBinder.kt
@@ -22,7 +22,7 @@
 import androidx.core.view.isVisible
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.animation.ActivityTransitionAnimator
 import com.android.systemui.common.ui.binder.IconViewBinder
 import com.android.systemui.common.ui.binder.TextViewBinder
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt
index 8b74f5d..de4a1b0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt
@@ -21,7 +21,7 @@
 import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.keyguard.MigrateClocksToBlueprint
 import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor
 import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Config
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindViewBinder.kt
index fd27dc3..3934917 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSurfaceBehindViewBinder.kt
@@ -16,7 +16,7 @@
 
 package com.android.systemui.keyguard.ui.binder
 
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.keyguard.WindowManagerLockscreenVisibilityManager
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardSurfaceBehindViewModel
 import kotlinx.coroutines.CoroutineScope
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/LightRevealScrimViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/LightRevealScrimViewBinder.kt
index b2ee689..2df17c3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/LightRevealScrimViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/LightRevealScrimViewBinder.kt
@@ -18,7 +18,7 @@
 
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.keyguard.ui.viewmodel.LightRevealScrimViewModel
 import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.statusbar.LightRevealScrim
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityViewBinder.kt
index ae46dd3..b1ce47e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityViewBinder.kt
@@ -16,7 +16,7 @@
 
 package com.android.systemui.keyguard.ui.binder
 
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.keyguard.WindowManagerLockscreenVisibilityManager
 import com.android.systemui.keyguard.ui.viewmodel.WindowManagerLockscreenVisibilityViewModel
 import kotlinx.coroutines.CoroutineScope
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
index dd8980d..08d35a7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
@@ -47,7 +47,6 @@
 import androidx.constraintlayout.widget.ConstraintSet.START
 import androidx.constraintlayout.widget.ConstraintSet.TOP
 import androidx.core.view.isInvisible
-import com.android.app.tracing.coroutines.createCoroutineTracingContext
 import com.android.internal.policy.SystemBarUtils
 import com.android.keyguard.ClockEventController
 import com.android.keyguard.KeyguardClockSwitch
@@ -57,6 +56,7 @@
 import com.android.systemui.common.ui.ConfigurationState
 import com.android.systemui.communal.ui.binder.CommunalTutorialIndicatorViewBinder
 import com.android.systemui.communal.ui.viewmodel.CommunalTutorialIndicatorViewModel
+import com.android.systemui.coroutines.newTracingContext
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
@@ -189,7 +189,7 @@
             CoroutineScope(
                 applicationScope.coroutineContext +
                     Job() +
-                    createCoroutineTracingContext("KeyguardPreviewRenderer")
+                    newTracingContext("KeyguardPreviewRenderer")
             )
         disposables += DisposableHandle { coroutineScope.cancel() }
         clockController.setFallbackWeatherData(WeatherData.getPlaceholderWeatherData())
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt
index 075a1d2..9355200 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt
@@ -25,7 +25,7 @@
 import android.util.ArrayMap
 import android.util.Log
 import androidx.annotation.VisibleForTesting
-import com.android.app.tracing.coroutines.runBlocking
+import com.android.app.tracing.coroutines.runBlockingTraced as runBlocking
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt
index 0d55709..f765e60 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordancesCombinedViewModel.kt
@@ -19,6 +19,7 @@
 
 import androidx.annotation.VisibleForTesting
 import com.android.app.tracing.FlowTracing.traceEmissionCount
+import com.android.app.tracing.coroutines.flow.flowName
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
 import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
@@ -141,6 +142,7 @@
                 fadeInAlpha,
                 fadeOutAlpha,
             )
+            .flowName("transitionAlpha")
             .stateIn(
                 scope = applicationScope,
                 started = SharingStarted.WhileSubscribed(),
diff --git a/packages/SystemUI/src/com/android/systemui/lifecycle/Hydrator.kt b/packages/SystemUI/src/com/android/systemui/lifecycle/Hydrator.kt
index df1394b..7c02f28 100644
--- a/packages/SystemUI/src/com/android/systemui/lifecycle/Hydrator.kt
+++ b/packages/SystemUI/src/com/android/systemui/lifecycle/Hydrator.kt
@@ -19,7 +19,7 @@
 import androidx.compose.runtime.State
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.snapshots.StateFactoryMarker
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.app.tracing.coroutines.traceCoroutine
 import kotlinx.coroutines.awaitCancellation
 import kotlinx.coroutines.coroutineScope
diff --git a/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt b/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt
index 5559698..a86bfb1 100644
--- a/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt
+++ b/packages/SystemUI/src/com/android/systemui/lifecycle/RepeatWhenAttached.kt
@@ -17,7 +17,6 @@
 
 package com.android.systemui.lifecycle
 
-import android.os.Trace
 import android.view.View
 import android.view.ViewTreeObserver
 import androidx.annotation.MainThread
@@ -25,11 +24,8 @@
 import androidx.lifecycle.LifecycleOwner
 import androidx.lifecycle.LifecycleRegistry
 import androidx.lifecycle.lifecycleScope
-import com.android.app.tracing.coroutines.createCoroutineTracingContext
-import com.android.app.tracing.coroutines.traceCoroutine
-import com.android.systemui.Flags.coroutineTracing
+import com.android.systemui.coroutines.newTracingContext
 import com.android.systemui.util.Assert
-import com.android.systemui.util.Compile
 import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
 import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated
 import kotlin.coroutines.CoroutineContext
@@ -83,25 +79,13 @@
     // default behavior. Instead, we want it to run on the view's UI thread since the user will
     // presumably want to call view methods that require being called from said UI thread.
     val lifecycleCoroutineContext = MAIN_DISPATCHER_SINGLETON + coroutineContext
-    val traceName =
-        if (Compile.IS_DEBUG && coroutineTracing()) {
-            inferTraceSectionName()
-        } else {
-            DEFAULT_TRACE_NAME
-        }
     var lifecycleOwner: ViewLifecycleOwner? = null
     val onAttachListener =
         object : View.OnAttachStateChangeListener {
             override fun onViewAttachedToWindow(v: View) {
                 Assert.isMainThread()
                 lifecycleOwner?.onDestroy()
-                lifecycleOwner =
-                    createLifecycleOwnerAndRun(
-                        traceName,
-                        view,
-                        lifecycleCoroutineContext,
-                        block,
-                    )
+                lifecycleOwner = createLifecycleOwnerAndRun(view, lifecycleCoroutineContext, block)
             }
 
             override fun onViewDetachedFromWindow(v: View) {
@@ -112,13 +96,7 @@
 
     addOnAttachStateChangeListener(onAttachListener)
     if (view.isAttachedToWindow) {
-        lifecycleOwner =
-            createLifecycleOwnerAndRun(
-                traceName,
-                view,
-                lifecycleCoroutineContext,
-                block,
-            )
+        lifecycleOwner = createLifecycleOwnerAndRun(view, lifecycleCoroutineContext, block)
     }
 
     return DisposableHandle {
@@ -131,14 +109,15 @@
 }
 
 private fun createLifecycleOwnerAndRun(
-    nameForTrace: String,
     view: View,
     coroutineContext: CoroutineContext,
     block: suspend LifecycleOwner.(View) -> Unit,
 ): ViewLifecycleOwner {
     return ViewLifecycleOwner(view).apply {
         onCreate()
-        lifecycleScope.launch(coroutineContext) { traceCoroutine(nameForTrace) { block(view) } }
+        // TODO(b/370595466): Refactor to support installing CoroutineTracingContext on the
+        //                    top-level CoroutineScope used as the lifecycleScope
+        lifecycleScope.launch(coroutineContext) { block(view) }
     }
 }
 
@@ -167,9 +146,7 @@
  * └───────────────┴───────────────────┴──────────────┴─────────────────┘
  * ```
  */
-class ViewLifecycleOwner(
-    private val view: View,
-) : LifecycleOwner {
+class ViewLifecycleOwner(private val view: View) : LifecycleOwner {
 
     private val windowVisibleListener =
         ViewTreeObserver.OnWindowVisibilityChangeListener { updateState() }
@@ -205,28 +182,6 @@
     }
 }
 
-private fun isFrameInteresting(frame: StackWalker.StackFrame): Boolean =
-    frame.className != CURRENT_CLASS_NAME && frame.className != JAVA_ADAPTER_CLASS_NAME
-
-/** Get a name for the trace section include the name of the call site. */
-private fun inferTraceSectionName(): String {
-    try {
-        Trace.traceBegin(Trace.TRACE_TAG_APP, "RepeatWhenAttachedKt#inferTraceSectionName")
-        val interestingFrame =
-            StackWalker.getInstance().walk { stream ->
-                stream.filter(::isFrameInteresting).limit(5).findFirst()
-            }
-        return if (interestingFrame.isPresent) {
-            val f = interestingFrame.get()
-            "${f.className}#${f.methodName}:${f.lineNumber} [$DEFAULT_TRACE_NAME]"
-        } else {
-            DEFAULT_TRACE_NAME
-        }
-    } finally {
-        Trace.traceEnd(Trace.TRACE_TAG_APP)
-    }
-}
-
 /**
  * Runs the given [block] in a new coroutine when `this` [View]'s Window's [WindowLifecycleState] is
  * at least at [state] (or immediately after calling this function if the window is already at least
@@ -368,8 +323,7 @@
  * an extension function, and plumbing dagger-injected instances for static usage has little
  * benefit.
  */
-private val MAIN_DISPATCHER_SINGLETON =
-    Dispatchers.Main + createCoroutineTracingContext("RepeatWhenAttached")
+private val MAIN_DISPATCHER_SINGLETON = Dispatchers.Main + newTracingContext("RepeatWhenAttached")
 private const val DEFAULT_TRACE_NAME = "repeatWhenAttached"
 private const val CURRENT_CLASS_NAME = "com.android.systemui.lifecycle.RepeatWhenAttachedKt"
 private const val JAVA_ADAPTER_CLASS_NAME = "com.android.systemui.util.kotlin.JavaAdapterKt"
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt
index 544dbdd..f40ad06 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt
@@ -16,13 +16,13 @@
 
 package com.android.systemui.mediaprojection.appselector
 
-import com.android.app.tracing.coroutines.createCoroutineTracingContext
 import android.app.Activity
 import android.content.ComponentName
 import android.content.Context
 import android.os.UserHandle
 import androidx.lifecycle.DefaultLifecycleObserver
 import com.android.launcher3.icons.IconFactory
+import com.android.systemui.coroutines.newTracingContext
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.mediaprojection.appselector.data.ActivityTaskManagerLabelLoader
 import com.android.systemui.mediaprojection.appselector.data.ActivityTaskManagerThumbnailLoader
@@ -134,7 +134,11 @@
         @MediaProjectionAppSelector
         @MediaProjectionAppSelectorScope
         fun provideCoroutineScope(@Application applicationScope: CoroutineScope): CoroutineScope =
-            CoroutineScope(applicationScope.coroutineContext + SupervisorJob() + createCoroutineTracingContext("MediaProjectionAppSelectorScope"))
+            CoroutineScope(
+                applicationScope.coroutineContext +
+                    SupervisorJob() +
+                    newTracingContext("MediaProjectionAppSelectorScope")
+            )
     }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/domain/GestureInteractor.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/domain/GestureInteractor.kt
index 96386e5..0166176 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/domain/GestureInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/domain/GestureInteractor.kt
@@ -16,7 +16,6 @@
 
 package com.android.systemui.navigationbar.gestural.domain
 
-import com.android.app.tracing.coroutines.flow.flowOn
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
@@ -35,6 +34,7 @@
 import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.mapLatest
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
index 3aa9daa..d0f6f79 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
@@ -37,7 +37,7 @@
 import android.provider.Settings
 import android.widget.Toast
 import androidx.annotation.VisibleForTesting
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
index 9c5231d..49b44cb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
@@ -23,7 +23,9 @@
 import android.os.Bundle
 import android.util.IndentingPrintWriter
 import android.view.LayoutInflater
+import android.view.MotionEvent
 import android.view.View
+import android.view.ViewConfiguration
 import android.view.ViewGroup
 import android.widget.FrameLayout
 import androidx.activity.OnBackPressedDispatcher
@@ -35,6 +37,7 @@
 import androidx.compose.animation.fadeIn
 import androidx.compose.animation.fadeOut
 import androidx.compose.animation.togetherWith
+import androidx.compose.foundation.ScrollState
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Spacer
@@ -43,6 +46,7 @@
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.navigationBars
 import androidx.compose.foundation.layout.windowInsetsPadding
+import androidx.compose.foundation.verticalScroll
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.LaunchedEffect
@@ -83,6 +87,7 @@
 import com.android.systemui.compose.modifiers.sysuiResTag
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.lifecycle.setSnapshotBinding
 import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager
 import com.android.systemui.media.controls.ui.view.MediaHost
 import com.android.systemui.media.dagger.MediaModule.QS_PANEL
@@ -145,6 +150,7 @@
     private val qqsVisible = MutableStateFlow(false)
     private val qqsPositionOnRoot = Rect()
     private val composeViewPositionOnScreen = Rect()
+    private val scrollState = ScrollState(0)
 
     // Inside object for namespacing
     private val notificationScrimClippingParams =
@@ -210,6 +216,9 @@
                 context,
                 { notificationScrimClippingParams.isEnabled },
                 { notificationScrimClippingParams.params.top },
+                // Only allow scrolling when we are fully expanded. That way, we don't intercept
+                // swipes in lockscreen (when somehow QS is receiving touches).
+                { scrollState.canScrollForward && viewModel.expansionState.value.progress >= 1f },
             )
         frame.addView(
             composeView,
@@ -488,12 +497,8 @@
     private fun setListenerCollections() {
         lifecycleScope.launch {
             lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
-                launch {
-                    //                    TODO
-                    //                    setListenerJob(
-                    //                            scrollListener,
-                    //
-                    //                    )
+                this@QSFragmentCompose.view?.setSnapshotBinding {
+                    scrollListener.value?.onQsPanelScrollChanged(scrollState.value)
                 }
                 launch {
                     setListenerJob(
@@ -528,6 +533,7 @@
             viewModel.containerViewModel.quickQuickSettingsViewModel.squishinessViewModel
                 .squishiness
                 .collectAsStateWithLifecycle()
+
         Column(modifier = Modifier.sysuiResTag("quick_qs_panel")) {
             Box(
                 modifier =
@@ -591,7 +597,12 @@
                     modifier =
                         Modifier.element(ElementKeys.QuickSettingsContent).fillMaxSize().weight(1f)
                 ) {
-                    Column {
+                    DisposableEffect(Unit) {
+                        lifecycleScope.launch { scrollState.scrollTo(0) }
+                        onDispose { lifecycleScope.launch { scrollState.scrollTo(0) } }
+                    }
+
+                    Column(modifier = Modifier.verticalScroll(scrollState)) {
                         Spacer(
                             modifier = Modifier.height { qqsPadding + qsExtraPadding.roundToPx() }
                         )
@@ -601,15 +612,14 @@
                         )
                     }
                 }
-                QuickSettingsTheme {
-                    FooterActions(
-                        viewModel = viewModel.footerActionsViewModel,
-                        qsVisibilityLifecycleOwner = this@QSFragmentCompose,
-                        modifier =
-                            Modifier.sysuiResTag("qs_footer_actions")
-                                .element(ElementKeys.FooterActions),
-                    )
-                }
+            }
+            QuickSettingsTheme {
+                FooterActions(
+                    viewModel = viewModel.footerActionsViewModel,
+                    qsVisibilityLifecycleOwner = this@QSFragmentCompose,
+                    modifier =
+                        Modifier.sysuiResTag("qs_footer_actions").element(ElementKeys.FooterActions),
+                )
             }
         }
     }
@@ -791,13 +801,17 @@
 private const val EDIT_MODE_TIME_MILLIS = 500
 
 /**
- * Ignore touches below the value returned by [clippingTopProvider], when clipping is enabled, as
- * per [clippingEnabledProvider].
+ * Performs different touch handling based on the state of the ComposeView:
+ * * Ignore touches below the value returned by [clippingTopProvider], when clipping is enabled, as
+ *   per [clippingEnabledProvider].
+ * * Intercept touches that would overscroll QS forward and instead allow them to be used to close
+ *   the shade.
  */
 private class FrameLayoutTouchPassthrough(
     context: Context,
     private val clippingEnabledProvider: () -> Boolean,
     private val clippingTopProvider: () -> Int,
+    private val canScrollForwardQs: () -> Boolean,
 ) : FrameLayout(context) {
     override fun isTransformedTouchPointInView(
         x: Float,
@@ -811,4 +825,32 @@
             super.isTransformedTouchPointInView(x, y, child, outLocalPoint)
         }
     }
+
+    val touchSlop = ViewConfiguration.get(context).scaledTouchSlop
+    var downY = 0f
+
+    override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
+        // If there's a touch on this view and we can scroll down, we don't want to be intercepted
+        val action = ev.actionMasked
+
+        when (action) {
+            MotionEvent.ACTION_DOWN -> {
+                // If we can scroll down, make sure none of our parents intercepts us.
+                if (canScrollForwardQs()) {
+                    parent?.requestDisallowInterceptTouchEvent(true)
+                }
+                downY = ev.y
+            }
+
+            MotionEvent.ACTION_MOVE -> {
+                val y = ev.y.toInt()
+                val yDiff: Float = y - downY
+                if (yDiff < -touchSlop && !canScrollForwardQs()) {
+                    // Intercept touches that are overscrolling.
+                    return true
+                }
+            }
+        }
+        return super.onInterceptTouchEvent(ev)
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/BounceableInfo.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/BounceableInfo.kt
new file mode 100644
index 0000000..b9994d7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/BounceableInfo.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2024 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.qs.panels.ui.compose
+
+import com.android.compose.animation.Bounceable
+import com.android.systemui.qs.panels.shared.model.SizedTile
+import com.android.systemui.qs.panels.ui.model.GridCell
+import com.android.systemui.qs.panels.ui.model.TileGridCell
+import com.android.systemui.qs.panels.ui.viewmodel.BounceableTileViewModel
+import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel
+
+data class BounceableInfo(
+    val bounceable: BounceableTileViewModel,
+    val previousTile: Bounceable?,
+    val nextTile: Bounceable?,
+    val bounceEnd: Boolean,
+)
+
+fun List<Pair<GridCell, BounceableTileViewModel>>.bounceableInfo(
+    index: Int,
+    columns: Int,
+): BounceableInfo {
+    val cell = this[index].first as TileGridCell
+    // Only look for neighbor bounceables if they are on the same row
+    val onLastColumn = cell.onLastColumn(cell.column, columns)
+    val previousTile = getOrNull(index - 1)?.takeIf { cell.column != 0 }
+    val nextTile = getOrNull(index + 1)?.takeIf { !onLastColumn }
+    return BounceableInfo(this[index].second, previousTile?.second, nextTile?.second, !onLastColumn)
+}
+
+fun List<BounceableTileViewModel>.bounceableInfo(
+    sizedTile: SizedTile<TileViewModel>,
+    index: Int,
+    column: Int,
+    columns: Int,
+): BounceableInfo {
+    // Only look for neighbor bounceables if they are on the same row
+    val onLastColumn = sizedTile.onLastColumn(column, columns)
+    val previousTile = getOrNull(index - 1)?.takeIf { column != 0 }
+    val nextTile = getOrNull(index + 1)?.takeIf { !onLastColumn }
+    return BounceableInfo(this[index], previousTile, nextTile, !onLastColumn)
+}
+
+private fun <T> SizedTile<T>.onLastColumn(column: Int, columns: Int): Boolean {
+    return column == columns - width
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditTileListState.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditTileListState.kt
index 770fd78..74fa0fe 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditTileListState.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditTileListState.kt
@@ -116,9 +116,9 @@
             regenerateGrid()
             _tiles.add(insertionIndex.coerceIn(0, _tiles.size), cell)
         } else {
-            // Add the tile with a temporary row which will get reassigned when
+            // Add the tile with a temporary row/col which will get reassigned when
             // regenerating spacers
-            _tiles.add(insertionIndex.coerceIn(0, _tiles.size), TileGridCell(draggedTile, 0))
+            _tiles.add(insertionIndex.coerceIn(0, _tiles.size), TileGridCell(draggedTile, 0, 0))
         }
 
         regenerateGrid()
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt
index e749475..d55763a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt
@@ -19,7 +19,7 @@
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.requiredHeight
 import androidx.compose.foundation.pager.HorizontalPager
 import androidx.compose.foundation.pager.rememberPagerState
 import androidx.compose.material.icons.Icons
@@ -97,7 +97,9 @@
                     TileGrid(tiles = page, modifier = Modifier, editModeStart = {})
                 }
             }
-            Box(modifier = Modifier.height(FooterHeight).fillMaxWidth()) {
+            // Use requiredHeight so it won't be squished if the view doesn't quite fit. As this is
+            // expected to be inside a scrollable container, this should not be an issue.
+            Box(modifier = Modifier.requiredHeight(FooterHeight).fillMaxWidth()) {
                 PagerDots(
                     pagerState = pagerState,
                     activeColor = MaterialTheme.colorScheme.primary,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
index a645b51..1c7a334 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
@@ -20,6 +20,8 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.res.dimensionResource
 import androidx.compose.ui.util.fastMap
@@ -29,6 +31,7 @@
 import com.android.systemui.grid.ui.compose.VerticalSpannedGrid
 import com.android.systemui.qs.composefragment.ui.GridAnchor
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.Tile
+import com.android.systemui.qs.panels.ui.viewmodel.BounceableTileViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.QuickQuickSettingsViewModel
 import com.android.systemui.qs.shared.ui.ElementKeys.toElementKey
 import com.android.systemui.res.R
@@ -38,10 +41,11 @@
     viewModel: QuickQuickSettingsViewModel,
     modifier: Modifier = Modifier,
 ) {
-    val sizedTiles by
-        viewModel.tileViewModels.collectAsStateWithLifecycle(initialValue = emptyList())
+    val sizedTiles by viewModel.tileViewModels.collectAsStateWithLifecycle()
     val tiles = sizedTiles.fastMap { it.tile }
+    val bounceables = remember(sizedTiles) { List(sizedTiles.size) { BounceableTileViewModel() } }
     val squishiness by viewModel.squishinessViewModel.squishiness.collectAsStateWithLifecycle()
+    val scope = rememberCoroutineScope()
 
     DisposableEffect(tiles) {
         val token = Any()
@@ -49,6 +53,7 @@
         onDispose { tiles.forEach { it.stopListening(token) } }
     }
     val columns by viewModel.columns.collectAsStateWithLifecycle()
+    var cellIndex = 0
     Box(modifier = modifier) {
         GridAnchor()
         VerticalSpannedGrid(
@@ -59,11 +64,15 @@
             modifier = Modifier.sysuiResTag("qqs_tile_layout"),
         ) { spanIndex ->
             val it = sizedTiles[spanIndex]
+            val column = cellIndex % columns
+            cellIndex += it.width
             Tile(
                 tile = it.tile,
                 iconOnly = it.isIcon,
                 modifier = Modifier.element(it.tile.spec.toElementKey(spanIndex)),
                 squishiness = { squishiness },
+                coroutineScope = scope,
+                bounceableInfo = bounceables.bounceableInfo(it, spanIndex, column, columns),
             )
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt
index 9ec5a82..71fa0ac 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt
@@ -31,6 +31,7 @@
 import androidx.compose.foundation.layout.fillMaxHeight
 import androidx.compose.foundation.layout.size
 import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
@@ -54,6 +55,7 @@
 import androidx.compose.ui.semantics.semantics
 import androidx.compose.ui.semantics.stateDescription
 import androidx.compose.ui.semantics.toggleableState
+import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.dp
 import com.android.compose.modifiers.background
 import com.android.compose.modifiers.thenIf
@@ -64,7 +66,6 @@
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.longPressLabel
 import com.android.systemui.qs.panels.ui.viewmodel.AccessibilityUiState
 import com.android.systemui.res.R
-import kotlinx.coroutines.delay
 
 private const val TEST_TAG_TOGGLE = "qs_tile_toggle_target"
 
@@ -138,13 +139,20 @@
     accessibilityUiState: AccessibilityUiState? = null,
 ) {
     Column(verticalArrangement = Arrangement.Center, modifier = modifier.fillMaxHeight()) {
-        Text(label, color = colors.label, modifier = Modifier.tileMarquee())
+        Text(
+            label,
+            style = MaterialTheme.typography.labelLarge,
+            color = colors.label,
+            maxLines = 1,
+            overflow = TextOverflow.Ellipsis,
+        )
         if (!TextUtils.isEmpty(secondaryLabel)) {
             Text(
                 secondaryLabel ?: "",
                 color = colors.secondaryLabel,
+                style = MaterialTheme.typography.bodyMedium,
                 modifier =
-                    Modifier.tileMarquee().thenIf(
+                    Modifier.thenIf(
                         accessibilityUiState?.stateDescription?.contains(secondaryLabel ?: "") ==
                             true
                     ) {
@@ -182,10 +190,7 @@
                     rememberAnimatedVectorPainter(animatedImageVector = image, atEnd = true)
                 } else {
                     var atEnd by remember(icon.res) { mutableStateOf(false) }
-                    LaunchedEffect(key1 = icon.res) {
-                        delay(350)
-                        atEnd = true
-                    }
+                    LaunchedEffect(key1 = icon.res) { atEnd = true }
                     rememberAnimatedVectorPainter(animatedImageVector = image, atEnd = atEnd)
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt
index 45c1e48..5c2a2bd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt
@@ -22,13 +22,13 @@
 import androidx.compose.animation.AnimatedVisibility
 import androidx.compose.animation.core.animateDpAsState
 import androidx.compose.animation.core.animateFloatAsState
-import androidx.compose.animation.core.animateIntAsState
 import androidx.compose.animation.fadeIn
 import androidx.compose.animation.fadeOut
 import androidx.compose.foundation.ExperimentalFoundationApi
 import androidx.compose.foundation.LocalOverscrollConfiguration
 import androidx.compose.foundation.background
 import androidx.compose.foundation.border
+import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.foundation.layout.Arrangement.spacedBy
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.BoxScope
@@ -46,7 +46,6 @@
 import androidx.compose.foundation.layout.wrapContentHeight
 import androidx.compose.foundation.layout.wrapContentSize
 import androidx.compose.foundation.lazy.grid.GridCells
-import androidx.compose.foundation.lazy.grid.LazyGridItemScope
 import androidx.compose.foundation.lazy.grid.LazyGridScope
 import androidx.compose.foundation.lazy.grid.rememberLazyGridState
 import androidx.compose.foundation.rememberScrollState
@@ -66,19 +65,17 @@
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.runtime.rememberUpdatedState
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.BiasAlignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.drawBehind
-import androidx.compose.ui.draw.drawWithContent
 import androidx.compose.ui.geometry.CornerRadius
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.SolidColor
-import androidx.compose.ui.graphics.drawscope.Stroke
-import androidx.compose.ui.layout.Layout
 import androidx.compose.ui.layout.onGloballyPositioned
 import androidx.compose.ui.layout.onSizeChanged
 import androidx.compose.ui.layout.positionInRoot
@@ -98,23 +95,26 @@
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
 import androidx.compose.ui.util.fastMap
-import androidx.compose.ui.zIndex
+import com.android.compose.animation.bounceable
 import com.android.compose.modifiers.background
 import com.android.compose.modifiers.height
 import com.android.systemui.common.ui.compose.load
 import com.android.systemui.qs.panels.shared.model.SizedTile
 import com.android.systemui.qs.panels.shared.model.SizedTileImpl
+import com.android.systemui.qs.panels.ui.compose.BounceableInfo
 import com.android.systemui.qs.panels.ui.compose.DragAndDropState
 import com.android.systemui.qs.panels.ui.compose.EditTileListState
+import com.android.systemui.qs.panels.ui.compose.bounceableInfo
 import com.android.systemui.qs.panels.ui.compose.dragAndDropRemoveZone
 import com.android.systemui.qs.panels.ui.compose.dragAndDropTileList
 import com.android.systemui.qs.panels.ui.compose.dragAndDropTileSource
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.InactiveCornerRadius
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.TileArrangementPadding
+import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.TileHeight
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.ToggleTargetSize
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.EditModeTileDefaults.CurrentTilesGridPadding
 import com.android.systemui.qs.panels.ui.compose.selection.MutableSelectionState
-import com.android.systemui.qs.panels.ui.compose.selection.ResizingHandle
+import com.android.systemui.qs.panels.ui.compose.selection.ResizableTileContainer
 import com.android.systemui.qs.panels.ui.compose.selection.TileWidths
 import com.android.systemui.qs.panels.ui.compose.selection.clearSelectionTile
 import com.android.systemui.qs.panels.ui.compose.selection.rememberSelectionState
@@ -122,11 +122,14 @@
 import com.android.systemui.qs.panels.ui.model.GridCell
 import com.android.systemui.qs.panels.ui.model.SpacerGridCell
 import com.android.systemui.qs.panels.ui.model.TileGridCell
+import com.android.systemui.qs.panels.ui.viewmodel.BounceableTileViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel
 import com.android.systemui.qs.pipeline.shared.TileSpec
 import com.android.systemui.qs.shared.model.groupAndSort
 import com.android.systemui.res.R
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
 
 object TileType
 
@@ -241,15 +244,20 @@
     onSetTiles: (List<TileSpec>) -> Unit,
 ) {
     val currentListState by rememberUpdatedState(listState)
-    val tileHeight = CommonTileDefaults.TileHeight
     val totalRows = listState.tiles.lastOrNull()?.row ?: 0
     val totalHeight by
         animateDpAsState(
-            gridHeight(totalRows + 1, tileHeight, TileArrangementPadding, CurrentTilesGridPadding),
+            gridHeight(totalRows + 1, TileHeight, TileArrangementPadding, CurrentTilesGridPadding),
             label = "QSEditCurrentTilesGridHeight",
         )
     val gridState = rememberLazyGridState()
     var gridContentOffset by remember { mutableStateOf(Offset(0f, 0f)) }
+    val coroutineScope = rememberCoroutineScope()
+
+    val cells =
+        remember(listState.tiles) {
+            listState.tiles.fastMap { Pair(it, BounceableTileViewModel()) }
+        }
 
     TileLazyGrid(
         state = gridState,
@@ -272,7 +280,7 @@
                 }
                 .testTag(CURRENT_TILES_GRID_TEST_TAG),
     ) {
-        EditTiles(listState.tiles, listState, selectionState) { spec ->
+        EditTiles(cells, columns, listState, selectionState, coroutineScope) { spec ->
             // Toggle the current size of the tile
             currentListState.isIcon(spec)?.let { onResize(spec, !it) }
         }
@@ -286,10 +294,10 @@
     columns: Int,
     dragAndDropState: DragAndDropState,
 ) {
-    // Available tiles aren't visible during drag and drop, so the row isn't needed
+    // Available tiles aren't visible during drag and drop, so the row/col isn't needed
     val groupedTiles =
         remember(tiles.fastMap { it.tile.category }, tiles.fastMap { it.tile.label }) {
-            groupAndSort(tiles.fastMap { TileGridCell(it, 0) })
+            groupAndSort(tiles.fastMap { TileGridCell(it, 0, 0) })
         }
     val labelColors = EditModeTileDefaults.editTileColors()
 
@@ -349,24 +357,26 @@
 /**
  * Adds a list of [GridCell] to the lazy grid
  *
- * @param cells the list of [GridCell]
+ * @param cells the pairs of [GridCell] to [BounceableTileViewModel]
  * @param dragAndDropState the [DragAndDropState] for this grid
  * @param selectionState the [MutableSelectionState] for this grid
  * @param onToggleSize the callback when a tile's size is toggled
  */
 fun LazyGridScope.EditTiles(
-    cells: List<GridCell>,
+    cells: List<Pair<GridCell, BounceableTileViewModel>>,
+    columns: Int,
     dragAndDropState: DragAndDropState,
     selectionState: MutableSelectionState,
+    coroutineScope: CoroutineScope,
     onToggleSize: (spec: TileSpec) -> Unit,
 ) {
     items(
         count = cells.size,
-        key = { cells[it].key(it, dragAndDropState) },
-        span = { cells[it].span },
+        key = { cells[it].first.key(it, dragAndDropState) },
+        span = { cells[it].first.span },
         contentType = { TileType },
     ) { index ->
-        when (val cell = cells[index]) {
+        when (val cell = cells[index].first) {
             is TileGridCell ->
                 if (dragAndDropState.isMoving(cell.tile.tileSpec)) {
                     // If the tile is being moved, replace it with a visible spacer
@@ -385,6 +395,9 @@
                         dragAndDropState = dragAndDropState,
                         selectionState = selectionState,
                         onToggleSize = onToggleSize,
+                        coroutineScope = coroutineScope,
+                        bounceableInfo = cells.bounceableInfo(index, columns),
+                        modifier = Modifier.animateItem(),
                     )
                 }
             is SpacerGridCell -> SpacerGridCell()
@@ -393,12 +406,15 @@
 }
 
 @Composable
-private fun LazyGridItemScope.TileGridCell(
+private fun TileGridCell(
     cell: TileGridCell,
     index: Int,
     dragAndDropState: DragAndDropState,
     selectionState: MutableSelectionState,
     onToggleSize: (spec: TileSpec) -> Unit,
+    coroutineScope: CoroutineScope,
+    bounceableInfo: BounceableInfo,
+    modifier: Modifier = Modifier,
 ) {
     val stateDescription = stringResource(id = R.string.accessibility_qs_edit_position, index + 1)
     var selected by remember { mutableStateOf(false) }
@@ -407,6 +423,9 @@
             targetValue = if (selected) 1f else 0f,
             label = "QSEditTileSelectionAlpha",
         )
+    val selectionColor = MaterialTheme.colorScheme.primary
+    val colors = EditModeTileDefaults.editTileColors()
+    val currentBounceableInfo by rememberUpdatedState(bounceableInfo)
 
     LaunchedEffect(selectionState.selection?.tileSpec) {
         selectionState.selection?.let {
@@ -420,152 +439,61 @@
         selected = selectionState.selection?.tileSpec == cell.tile.tileSpec
     }
 
-    val modifier =
-        Modifier.animateItem()
-            .semantics(mergeDescendants = true) {
-                this.stateDescription = stateDescription
-                contentDescription = cell.tile.label.text
-                customActions =
-                    listOf(
-                        // TODO(b/367748260): Add final accessibility actions
-                        CustomAccessibilityAction("Toggle size") {
-                            onToggleSize(cell.tile.tileSpec)
-                            true
-                        }
-                    )
-            }
-            .height(CommonTileDefaults.TileHeight)
-            .fillMaxWidth()
-
-    val content =
-        @Composable {
-            EditTile(
-                tileViewModel = cell.tile,
-                iconOnly = cell.isIcon,
-                selectionAlpha = { selectionAlpha },
-                modifier =
-                    Modifier.fillMaxSize()
-                        .selectableTile(cell.tile.tileSpec, selectionState)
-                        .dragAndDropTileSource(
-                            SizedTileImpl(cell.tile, cell.width),
-                            dragAndDropState,
-                            selectionState::unSelect,
-                        ),
-            )
-        }
-
-    if (selected) {
-        SelectedTile(
-            isIcon = cell.isIcon,
-            selectionAlpha = { selectionAlpha },
-            selectionState = selectionState,
-            modifier = modifier.zIndex(2f), // 2f to display this tile over neighbors when dragged
-            content = content,
-        )
-    } else {
-        UnselectedTile(
-            selectionAlpha = { selectionAlpha },
-            selectionState = selectionState,
-            modifier = modifier,
-            content = content,
-        )
-    }
-}
-
-@Composable
-private fun SelectedTile(
-    isIcon: Boolean,
-    selectionAlpha: () -> Float,
-    selectionState: MutableSelectionState,
-    modifier: Modifier = Modifier,
-    content: @Composable () -> Unit,
-) {
     // Current base, min and max width of this tile
     var tileWidths: TileWidths? by remember { mutableStateOf(null) }
-
-    // Animated diff between the current width and the resized width of the tile. We can't use
-    // animateContentSize here as the tile is sometimes unbounded.
-    val remainingOffset by
-        animateIntAsState(
-            selectionState.resizingState?.let { tileWidths?.base?.minus(it.width) ?: 0 } ?: 0,
-            label = "QSEditTileWidthOffset",
-        )
-
     val padding = with(LocalDensity.current) { TileArrangementPadding.roundToPx() }
-    Box(
-        modifier.onSizeChanged {
-            val min = if (isIcon) it.width else (it.width - padding) / 2
-            val max = if (isIcon) (it.width * 2) + padding else it.width
-            tileWidths = TileWidths(it.width, min, max)
-        }
+
+    ResizableTileContainer(
+        selected = selected,
+        selectionState = selectionState,
+        selectionAlpha = { selectionAlpha },
+        selectionColor = selectionColor,
+        tileWidths = { tileWidths },
+        modifier =
+            modifier
+                .height(TileHeight)
+                .fillMaxWidth()
+                .onSizeChanged {
+                    // Grab the size before the bounceable to get the idle width
+                    val min = if (cell.isIcon) it.width else (it.width - padding) / 2
+                    val max = if (cell.isIcon) (it.width * 2) + padding else it.width
+                    tileWidths = TileWidths(it.width, min, max)
+                }
+                .bounceable(
+                    bounceable = currentBounceableInfo.bounceable,
+                    previousBounceable = currentBounceableInfo.previousTile,
+                    nextBounceable = currentBounceableInfo.nextTile,
+                    orientation = Orientation.Horizontal,
+                    bounceEnd = currentBounceableInfo.bounceEnd,
+                ),
     ) {
-        val handle =
-            @Composable {
-                ResizingHandle(
-                    enabled = true,
-                    selectionState = selectionState,
-                    transition = selectionAlpha,
-                    tileWidths = { tileWidths },
+        Box(
+            modifier
+                .fillMaxSize()
+                .semantics(mergeDescendants = true) {
+                    this.stateDescription = stateDescription
+                    contentDescription = cell.tile.label.text
+                    customActions =
+                        listOf(
+                            // TODO(b/367748260): Add final accessibility actions
+                            CustomAccessibilityAction("Toggle size") {
+                                onToggleSize(cell.tile.tileSpec)
+                                true
+                            }
+                        )
+                }
+                .selectableTile(cell.tile.tileSpec, selectionState) {
+                    coroutineScope.launch { currentBounceableInfo.bounceable.animateBounce() }
+                }
+                .dragAndDropTileSource(
+                    SizedTileImpl(cell.tile, cell.width),
+                    dragAndDropState,
+                    selectionState::unSelect,
                 )
-            }
-
-        Layout(contents = listOf(content, handle)) {
-            (contentMeasurables, handleMeasurables),
-            constraints ->
-            // Grab the width from the resizing state if a resize is in progress, otherwise fill the
-            // max width
-            val width =
-                selectionState.resizingState?.width ?: (constraints.maxWidth - remainingOffset)
-            val contentPlaceable =
-                contentMeasurables.first().measure(constraints.copy(maxWidth = width))
-            val handlePlaceable = handleMeasurables.first().measure(constraints)
-
-            // Place the dot vertically centered on the right edge
-            val handleX = contentPlaceable.width - (handlePlaceable.width / 2)
-            val handleY = (contentPlaceable.height / 2) - (handlePlaceable.height / 2)
-
-            layout(constraints.maxWidth, constraints.maxHeight) {
-                contentPlaceable.place(0, 0)
-                handlePlaceable.place(handleX, handleY)
-            }
-        }
-    }
-}
-
-@Composable
-private fun UnselectedTile(
-    selectionAlpha: () -> Float,
-    selectionState: MutableSelectionState,
-    modifier: Modifier = Modifier,
-    content: @Composable () -> Unit,
-) {
-    val handle =
-        @Composable {
-            ResizingHandle(
-                enabled = false,
-                selectionState = selectionState,
-                transition = selectionAlpha,
-            )
-        }
-
-    Box(modifier) {
-        Layout(contents = listOf(content, handle)) {
-            (contentMeasurables, handleMeasurables),
-            constraints ->
-            val contentPlaceable =
-                contentMeasurables
-                    .first()
-                    .measure(constraints.copy(maxWidth = constraints.maxWidth))
-            val handlePlaceable = handleMeasurables.first().measure(constraints)
-
-            // Place the dot vertically centered on the right edge
-            val handleX = contentPlaceable.width - (handlePlaceable.width / 2)
-            val handleY = (contentPlaceable.height / 2) - (handlePlaceable.height / 2)
-
-            layout(constraints.maxWidth, constraints.maxHeight) {
-                contentPlaceable.place(0, 0)
-                handlePlaceable.place(handleX, handleY)
-            }
+                .tileBackground(colors.background)
+                .tilePadding()
+        ) {
+            EditTile(tile = cell.tile, iconOnly = cell.isIcon)
         }
     }
 }
@@ -588,19 +516,19 @@
         verticalArrangement = spacedBy(CommonTileDefaults.TilePadding, Alignment.Top),
         modifier = modifier,
     ) {
-        EditTileContainer(
-            colors = colors,
-            modifier =
-                Modifier.fillMaxWidth()
-                    .height(CommonTileDefaults.TileHeight)
-                    .clearSelectionTile(selectionState)
-                    .semantics(mergeDescendants = true) {
-                        onClick(onClickActionName) { false }
-                        this.stateDescription = stateDescription
-                    }
-                    .dragAndDropTileSource(SizedTileImpl(cell.tile, cell.width), dragAndDropState) {
-                        selectionState.unSelect()
-                    },
+        Box(
+            Modifier.fillMaxWidth()
+                .height(TileHeight)
+                .clearSelectionTile(selectionState)
+                .semantics(mergeDescendants = true) {
+                    onClick(onClickActionName) { false }
+                    this.stateDescription = stateDescription
+                }
+                .dragAndDropTileSource(SizedTileImpl(cell.tile, cell.width), dragAndDropState) {
+                    selectionState.unSelect()
+                }
+                .tileBackground(colors.background)
+                .tilePadding()
         ) {
             // Icon
             SmallTileContent(
@@ -626,16 +554,14 @@
 @Composable
 private fun SpacerGridCell(modifier: Modifier = Modifier) {
     // By default, spacers are invisible and exist purely to catch drag movements
-    Box(modifier.height(CommonTileDefaults.TileHeight).fillMaxWidth())
+    Box(modifier.height(TileHeight).fillMaxWidth())
 }
 
 @Composable
-fun EditTile(
-    tileViewModel: EditTileViewModel,
+fun BoxScope.EditTile(
+    tile: EditTileViewModel,
     iconOnly: Boolean,
-    modifier: Modifier = Modifier,
     colors: TileColors = EditModeTileDefaults.editTileColors(),
-    selectionAlpha: () -> Float = { 1f },
 ) {
     // Animated horizontal alignment from center (0f) to start (-1f)
     val alignmentValue by
@@ -646,68 +572,36 @@
     val alignment by remember {
         derivedStateOf { BiasAlignment(horizontalBias = alignmentValue, verticalBias = 0f) }
     }
+    // Icon
+    Box(Modifier.size(ToggleTargetSize).align(alignment)) {
+        SmallTileContent(
+            icon = tile.icon,
+            color = colors.icon,
+            animateToEnd = true,
+            modifier = Modifier.align(Alignment.Center),
+        )
+    }
 
-    EditTileContainer(colors = colors, selectionAlpha = selectionAlpha, modifier = modifier) {
-        // Icon
-        Box(Modifier.size(ToggleTargetSize).align(alignment)) {
-            SmallTileContent(
-                icon = tileViewModel.icon,
-                color = colors.icon,
-                animateToEnd = true,
-                modifier = Modifier.align(Alignment.Center),
-            )
-        }
-
-        // Labels, positioned after the icon
-        AnimatedVisibility(visible = !iconOnly, enter = fadeIn(), exit = fadeOut()) {
-            LargeTileLabels(
-                label = tileViewModel.label.text,
-                secondaryLabel = tileViewModel.appName?.text,
-                colors = colors,
-                modifier = Modifier.padding(start = ToggleTargetSize + TileArrangementPadding),
-            )
-        }
+    // Labels, positioned after the icon
+    AnimatedVisibility(visible = !iconOnly, enter = fadeIn(), exit = fadeOut()) {
+        LargeTileLabels(
+            label = tile.label.text,
+            secondaryLabel = tile.appName?.text,
+            colors = colors,
+            modifier = Modifier.padding(start = ToggleTargetSize + TileArrangementPadding),
+        )
     }
 }
 
-@Composable
-private fun EditTileContainer(
-    colors: TileColors,
-    modifier: Modifier = Modifier,
-    selectionAlpha: () -> Float = { 0f },
-    selectionColor: Color = MaterialTheme.colorScheme.primary,
-    content: @Composable BoxScope.() -> Unit = {},
-) {
-    Box(
-        Modifier.wrapContentSize().drawWithContent {
-            drawContent()
-            drawRoundRect(
-                SolidColor(selectionColor),
-                cornerRadius = CornerRadius(InactiveCornerRadius.toPx()),
-                style = Stroke(EditModeTileDefaults.SelectedBorderWidth.toPx()),
-                alpha = selectionAlpha(),
-            )
-        }
-    ) {
-        Box(
-            modifier =
-                modifier
-                    .drawBehind {
-                        drawRoundRect(
-                            SolidColor(colors.background),
-                            cornerRadius = CornerRadius(InactiveCornerRadius.toPx()),
-                        )
-                    }
-                    .tilePadding(),
-            content = content,
-        )
+private fun Modifier.tileBackground(color: Color): Modifier {
+    return drawBehind {
+        drawRoundRect(SolidColor(color), cornerRadius = CornerRadius(InactiveCornerRadius.toPx()))
     }
 }
 
 private object EditModeTileDefaults {
     const val PLACEHOLDER_ALPHA = .3f
     val EditGridHeaderHeight = 60.dp
-    val SelectedBorderWidth = 2.dp
     val CurrentTilesGridPadding = 8.dp
 
     @Composable
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
index 6920e49..e5c2135 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
@@ -20,6 +20,7 @@
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.res.dimensionResource
 import androidx.compose.ui.util.fastMap
@@ -29,7 +30,9 @@
 import com.android.systemui.grid.ui.compose.VerticalSpannedGrid
 import com.android.systemui.qs.panels.shared.model.SizedTileImpl
 import com.android.systemui.qs.panels.ui.compose.PaginatableGridLayout
+import com.android.systemui.qs.panels.ui.compose.bounceableInfo
 import com.android.systemui.qs.panels.ui.compose.rememberEditListState
+import com.android.systemui.qs.panels.ui.viewmodel.BounceableTileViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.IconTilesViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.QSColumnsViewModel
@@ -62,7 +65,11 @@
         }
         val columns by gridSizeViewModel.columns.collectAsStateWithLifecycle()
         val sizedTiles = tiles.map { SizedTileImpl(it, it.spec.width()) }
+        val bounceables =
+            remember(sizedTiles) { List(sizedTiles.size) { BounceableTileViewModel() } }
         val squishiness by squishinessViewModel.squishiness.collectAsStateWithLifecycle()
+        val scope = rememberCoroutineScope()
+        var cellIndex = 0
 
         VerticalSpannedGrid(
             columns = columns,
@@ -71,11 +78,15 @@
             spans = sizedTiles.fastMap { it.width },
         ) { spanIndex ->
             val it = sizedTiles[spanIndex]
+            val column = cellIndex % columns
+            cellIndex += it.width
             Tile(
                 tile = it.tile,
                 iconOnly = iconTilesViewModel.isIconTile(it.tile.spec),
                 modifier = Modifier.element(it.tile.spec.toElementKey(spanIndex)),
                 squishiness = { squishiness },
+                coroutineScope = scope,
+                bounceableInfo = bounceables.bounceableInfo(it, spanIndex, column, columns),
             )
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt
index 4bd5b2d..52d5261 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt
@@ -23,8 +23,8 @@
 import android.service.quicksettings.Tile.STATE_INACTIVE
 import androidx.compose.animation.core.animateDpAsState
 import androidx.compose.foundation.ExperimentalFoundationApi
-import androidx.compose.foundation.basicMarquee
 import androidx.compose.foundation.combinedClickable
+import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Arrangement.spacedBy
 import androidx.compose.foundation.layout.Box
@@ -44,6 +44,7 @@
 import androidx.compose.runtime.ReadOnlyComposable
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberUpdatedState
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.clip
@@ -61,11 +62,13 @@
 import androidx.compose.ui.unit.dp
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.compose.animation.Expandable
+import com.android.compose.animation.bounceable
 import com.android.compose.modifiers.thenIf
 import com.android.systemui.animation.Expandable
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.compose.modifiers.sysuiResTag
 import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.qs.panels.ui.compose.BounceableInfo
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.InactiveCornerRadius
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.longPressLabel
 import com.android.systemui.qs.panels.ui.viewmodel.TileUiState
@@ -74,6 +77,8 @@
 import com.android.systemui.qs.tileimpl.QSTileImpl
 import com.android.systemui.res.R
 import java.util.function.Supplier
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
 
 private const val TEST_TAG_SMALL = "qs_tile_small"
 private const val TEST_TAG_LARGE = "qs_tile_large"
@@ -102,9 +107,12 @@
     tile: TileViewModel,
     iconOnly: Boolean,
     squishiness: () -> Float,
+    coroutineScope: CoroutineScope,
+    bounceableInfo: BounceableInfo,
     modifier: Modifier = Modifier,
 ) {
     val state by tile.state.collectAsStateWithLifecycle(tile.currentState)
+    val currentBounceableInfo by rememberUpdatedState(bounceableInfo)
     val resources = resources()
     val uiState = remember(state, resources) { state.toUiState(resources) }
     val colors = TileDefaults.getColorForState(uiState)
@@ -112,7 +120,7 @@
     // TODO(b/361789146): Draw the shapes instead of clipping
     val tileShape = TileDefaults.animateTileShape(uiState.state)
 
-    TileContainer(
+    TileExpandable(
         color =
             if (iconOnly || !uiState.handlesSecondaryClick) {
                 colors.iconBackground
@@ -120,93 +128,101 @@
                 colors.background
             },
         shape = tileShape,
-        iconOnly = iconOnly,
-        onClick = tile::onClick,
-        onLongClick = tile::onLongClick,
-        uiState = uiState,
         squishiness = squishiness,
-        modifier = modifier,
+        modifier =
+            modifier
+                .fillMaxWidth()
+                .bounceable(
+                    bounceable = currentBounceableInfo.bounceable,
+                    previousBounceable = currentBounceableInfo.previousTile,
+                    nextBounceable = currentBounceableInfo.nextTile,
+                    orientation = Orientation.Horizontal,
+                    bounceEnd = currentBounceableInfo.bounceEnd,
+                ),
     ) { expandable ->
-        val icon = getTileIcon(icon = uiState.icon)
-        if (iconOnly) {
-            SmallTileContent(
-                icon = icon,
-                color = colors.icon,
-                modifier = Modifier.align(Alignment.Center),
-            )
-        } else {
-            val iconShape = TileDefaults.animateIconShape(uiState.state)
-            LargeTileContent(
-                label = uiState.label,
-                secondaryLabel = uiState.secondaryLabel,
-                icon = icon,
-                colors = colors,
-                iconShape = iconShape,
-                toggleClickSupported = state.handlesSecondaryClick,
-                onClick = {
-                    if (state.handlesSecondaryClick) {
-                        tile.onSecondaryClick()
-                    }
-                },
-                onLongClick = { tile.onLongClick(expandable) },
-                accessibilityUiState = uiState.accessibilityUiState,
-                squishiness = squishiness,
-            )
+        TileContainer(
+            onClick = {
+                tile.onClick(expandable)
+                if (uiState.accessibilityUiState.toggleableState != null) {
+                    coroutineScope.launch { currentBounceableInfo.bounceable.animateBounce() }
+                }
+            },
+            onLongClick = { tile.onLongClick(expandable) },
+            uiState = uiState,
+            iconOnly = iconOnly,
+        ) {
+            val icon = getTileIcon(icon = uiState.icon)
+            if (iconOnly) {
+                SmallTileContent(
+                    icon = icon,
+                    color = colors.icon,
+                    modifier = Modifier.align(Alignment.Center),
+                )
+            } else {
+                val iconShape = TileDefaults.animateIconShape(uiState.state)
+                LargeTileContent(
+                    label = uiState.label,
+                    secondaryLabel = uiState.secondaryLabel,
+                    icon = icon,
+                    colors = colors,
+                    iconShape = iconShape,
+                    toggleClickSupported = state.handlesSecondaryClick,
+                    onClick = {
+                        if (state.handlesSecondaryClick) {
+                            tile.onSecondaryClick()
+                        }
+                    },
+                    onLongClick = { tile.onLongClick(expandable) },
+                    accessibilityUiState = uiState.accessibilityUiState,
+                    squishiness = squishiness,
+                )
+            }
         }
     }
 }
 
 @Composable
-private fun TileContainer(
+private fun TileExpandable(
     color: Color,
     shape: Shape,
-    iconOnly: Boolean,
-    uiState: TileUiState,
     squishiness: () -> Float,
     modifier: Modifier = Modifier,
-    onClick: (Expandable) -> Unit = {},
-    onLongClick: (Expandable) -> Unit = {},
-    content: @Composable BoxScope.(Expandable) -> Unit,
+    content: @Composable (Expandable) -> Unit,
 ) {
     Expandable(
         color = color,
         shape = shape,
         modifier = modifier.clip(shape).verticalSquish(squishiness),
     ) {
-        val longPressLabel = longPressLabel()
-        Box(
-            modifier =
-                Modifier.height(CommonTileDefaults.TileHeight)
-                    .fillMaxWidth()
-                    .combinedClickable(
-                        onClick = { onClick(it) },
-                        onLongClick = { onLongClick(it) },
-                        onClickLabel = uiState.accessibilityUiState.clickLabel,
-                        onLongClickLabel = longPressLabel,
-                    )
-                    .semantics {
-                        role = uiState.accessibilityUiState.accessibilityRole
-                        if (uiState.accessibilityUiState.accessibilityRole == Role.Switch) {
-                            uiState.accessibilityUiState.toggleableState?.let {
-                                toggleableState = it
-                            }
-                        }
-                        stateDescription = uiState.accessibilityUiState.stateDescription
-                    }
-                    .sysuiResTag(if (iconOnly) TEST_TAG_SMALL else TEST_TAG_LARGE)
-                    .thenIf(iconOnly) {
-                        Modifier.semantics {
-                            contentDescription = uiState.accessibilityUiState.contentDescription
-                        }
-                    }
-                    .tilePadding()
-        ) {
-            content(it)
-        }
+        content(it)
     }
 }
 
 @Composable
+fun TileContainer(
+    onClick: () -> Unit,
+    onLongClick: () -> Unit,
+    uiState: TileUiState,
+    iconOnly: Boolean,
+    content: @Composable BoxScope.() -> Unit,
+) {
+    Box(
+        modifier =
+            Modifier.height(CommonTileDefaults.TileHeight)
+                .fillMaxWidth()
+                .tileCombinedClickable(
+                    onClick = onClick,
+                    onLongClick = onLongClick,
+                    uiState = uiState,
+                    iconOnly = iconOnly,
+                )
+                .sysuiResTag(if (iconOnly) TEST_TAG_SMALL else TEST_TAG_LARGE)
+                .tilePadding(),
+        content = content,
+    )
+}
+
+@Composable
 private fun getTileIcon(icon: Supplier<QSTile.Icon?>): Icon {
     val context = LocalContext.current
     return icon.get()?.let {
@@ -222,14 +238,38 @@
     return spacedBy(space = CommonTileDefaults.TileArrangementPadding, alignment = Alignment.Start)
 }
 
-fun Modifier.tileMarquee(): Modifier {
-    return basicMarquee(iterations = 1, initialDelayMillis = 200)
-}
-
 fun Modifier.tilePadding(): Modifier {
     return padding(CommonTileDefaults.TilePadding)
 }
 
+@Composable
+fun Modifier.tileCombinedClickable(
+    onClick: () -> Unit,
+    onLongClick: () -> Unit,
+    uiState: TileUiState,
+    iconOnly: Boolean,
+): Modifier {
+    val longPressLabel = longPressLabel()
+    return combinedClickable(
+            onClick = onClick,
+            onLongClick = onLongClick,
+            onClickLabel = uiState.accessibilityUiState.clickLabel,
+            onLongClickLabel = longPressLabel,
+        )
+        .semantics {
+            role = uiState.accessibilityUiState.accessibilityRole
+            if (uiState.accessibilityUiState.accessibilityRole == Role.Switch) {
+                uiState.accessibilityUiState.toggleableState?.let { toggleableState = it }
+            }
+            stateDescription = uiState.accessibilityUiState.stateDescription
+        }
+        .thenIf(iconOnly) {
+            Modifier.semantics {
+                contentDescription = uiState.accessibilityUiState.contentDescription
+            }
+        }
+}
+
 data class TileColors(
     val background: Color,
     val iconBackground: Color,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionState.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionState.kt
index 441d962..1d36aee 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionState.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionState.kt
@@ -89,8 +89,11 @@
  * Listens for click events to select/unselect the given [TileSpec]. Use this on current tiles as
  * they can be selected.
  */
-@Composable
-fun Modifier.selectableTile(tileSpec: TileSpec, selectionState: MutableSelectionState): Modifier {
+fun Modifier.selectableTile(
+    tileSpec: TileSpec,
+    selectionState: MutableSelectionState,
+    onClick: () -> Unit = {},
+): Modifier {
     return pointerInput(Unit) {
         detectTapGestures(
             onTap = {
@@ -99,6 +102,7 @@
                 } else {
                     selectionState.select(tileSpec, manual = true)
                 }
+                onClick()
             }
         )
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt
index e0f0b6a..9f13a37 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt
@@ -16,63 +16,117 @@
 
 package com.android.systemui.qs.panels.ui.compose.selection
 
+import androidx.compose.animation.core.animateIntAsState
 import androidx.compose.foundation.Canvas
 import androidx.compose.foundation.gestures.detectHorizontalDragGestures
 import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.BoxScope
 import androidx.compose.foundation.layout.size
 import androidx.compose.foundation.systemGestureExclusion
 import androidx.compose.material3.LocalMinimumInteractiveComponentSize
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.drawWithContent
+import androidx.compose.ui.geometry.CornerRadius
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.geometry.Rect
 import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.graphics.drawscope.Stroke
 import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.layout.layout
+import androidx.compose.ui.unit.Constraints
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.toSize
+import androidx.compose.ui.zIndex
+import com.android.compose.modifiers.thenIf
+import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.InactiveCornerRadius
 import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.ResizingDotSize
+import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.SelectedBorderWidth
 
 /**
- * Dot handling resizing drag events. Use this on the selected tile to resize it
+ * Places a dot to handle resizing drag events. Use this on tiles to resize.
  *
- * @param enabled whether resizing drag events should be handled
+ * The dot is placed vertically centered on the right border. The [content] will have a border when
+ * selected.
+ *
+ * @param selected whether resizing drag events should be handled
  * @param selectionState the [MutableSelectionState] on the grid
- * @param transition the animated value for the dot, used for its alpha and scale
+ * @param selectionAlpha the animated value for the dot and border alpha
+ * @param selectionColor the [Color] of the dot and border
  * @param tileWidths the [TileWidths] of the selected tile
- * @param onResize the callback when the drag passes the resizing threshold
  */
 @Composable
-fun ResizingHandle(
+fun ResizableTileContainer(
+    selected: Boolean,
+    selectionState: MutableSelectionState,
+    selectionAlpha: () -> Float,
+    selectionColor: Color,
+    tileWidths: () -> TileWidths?,
+    modifier: Modifier = Modifier,
+    content: @Composable BoxScope.() -> Unit = {},
+) {
+    Box(
+        modifier
+            .resizable(selected, selectionState, tileWidths)
+            .selectionBorder(selectionColor, selectionAlpha)
+    ) {
+        content()
+        ResizingHandle(
+            enabled = selected,
+            selectionState = selectionState,
+            transition = selectionAlpha,
+            tileWidths = tileWidths,
+            modifier =
+                // Higher zIndex to make sure the handle is drawn above the content
+                Modifier.zIndex(2f),
+        )
+    }
+}
+
+@Composable
+private fun ResizingHandle(
     enabled: Boolean,
     selectionState: MutableSelectionState,
     transition: () -> Float,
-    tileWidths: () -> TileWidths? = { null },
+    tileWidths: () -> TileWidths?,
+    modifier: Modifier = Modifier,
 ) {
-    if (enabled) {
-        // Manually creating the touch target around the resizing dot to ensure that the next tile
-        // does
-        // not receive the touch input accidentally.
-        val minTouchTargetSize = LocalMinimumInteractiveComponentSize.current
-        Box(
-            Modifier.size(minTouchTargetSize)
-                .systemGestureExclusion { Rect(Offset.Zero, it.size.toSize()) }
-                .pointerInput(Unit) {
-                    detectHorizontalDragGestures(
-                        onHorizontalDrag = { _, offset -> selectionState.onResizingDrag(offset) },
-                        onDragStart = {
-                            tileWidths()?.let { selectionState.onResizingDragStart(it) }
-                        },
-                        onDragEnd = selectionState::onResizingDragEnd,
-                        onDragCancel = selectionState::onResizingDragEnd,
+    // Manually creating the touch target around the resizing dot to ensure that the next tile
+    // does not receive the touch input accidentally.
+    val minTouchTargetSize = LocalMinimumInteractiveComponentSize.current
+    Box(
+        modifier
+            .layout { measurable, constraints ->
+                val size = minTouchTargetSize.roundToPx()
+                val placeable = measurable.measure(Constraints(size, size, size, size))
+                layout(placeable.width, placeable.height) {
+                    placeable.place(
+                        x = constraints.maxWidth - placeable.width / 2,
+                        y = constraints.maxHeight / 2 - placeable.height / 2,
                     )
                 }
-        ) {
-            ResizingDot(transition = transition, modifier = Modifier.align(Alignment.Center))
-        }
-    } else {
-        ResizingDot(transition = transition)
+            }
+            .thenIf(enabled) {
+                Modifier.systemGestureExclusion { Rect(Offset.Zero, it.size.toSize()) }
+                    .pointerInput(Unit) {
+                        detectHorizontalDragGestures(
+                            onHorizontalDrag = { _, offset ->
+                                selectionState.onResizingDrag(offset)
+                            },
+                            onDragStart = {
+                                tileWidths()?.let { selectionState.onResizingDragStart(it) }
+                            },
+                            onDragEnd = selectionState::onResizingDragEnd,
+                            onDragCancel = selectionState::onResizingDragEnd,
+                        )
+                    }
+            }
+    ) {
+        ResizingDot(transition = transition, modifier = Modifier.align(Alignment.Center))
     }
 }
 
@@ -88,6 +142,45 @@
     }
 }
 
+private fun Modifier.selectionBorder(
+    selectionColor: Color,
+    selectionAlpha: () -> Float = { 0f },
+): Modifier {
+    return drawWithContent {
+        drawContent()
+        drawRoundRect(
+            SolidColor(selectionColor),
+            cornerRadius = CornerRadius(InactiveCornerRadius.toPx()),
+            style = Stroke(SelectedBorderWidth.toPx()),
+            alpha = selectionAlpha(),
+        )
+    }
+}
+
+@Composable
+private fun Modifier.resizable(
+    selected: Boolean,
+    selectionState: MutableSelectionState,
+    tileWidths: () -> TileWidths?,
+): Modifier {
+    if (!selected) return zIndex(1f)
+
+    // Animated diff between the current width and the resized width of the tile. We can't use
+    // animateContentSize here as the tile is sometimes unbounded.
+    val remainingOffset by
+        animateIntAsState(
+            selectionState.resizingState?.let { tileWidths()?.base?.minus(it.width) ?: 0 } ?: 0,
+            label = "QSEditTileWidthOffset",
+        )
+    return zIndex(2f).layout { measurable, constraints ->
+        // Grab the width from the resizing state if a resize is in progress
+        val width = selectionState.resizingState?.width ?: (constraints.maxWidth - remainingOffset)
+        val placeable = measurable.measure(constraints.copy(minWidth = width, maxWidth = width))
+        layout(constraints.maxWidth, placeable.height) { placeable.place(0, 0) }
+    }
+}
+
 private object SelectionDefaults {
     val ResizingDotSize = 16.dp
+    val SelectedBorderWidth = 2.dp
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/model/TileGridCell.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/model/TileGridCell.kt
index b1841c4..c0441f8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/model/TileGridCell.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/model/TileGridCell.kt
@@ -31,8 +31,8 @@
 }
 
 /**
- * Represents a [EditTileViewModel] from a grid associated with a tile format and the row it's
- * positioned at
+ * Represents a [EditTileViewModel] from a grid associated with a tile format and the row and column
+ * it's positioned at
  */
 @Immutable
 data class TileGridCell(
@@ -41,13 +41,15 @@
     override val width: Int,
     override val span: GridItemSpan = GridItemSpan(width),
     override val s: String = "${tile.tileSpec.spec}-$row-$width",
+    val column: Int,
 ) : GridCell, SizedTile<EditTileViewModel>, CategoryAndName by tile {
     val key: String = "${tile.tileSpec.spec}-$row"
 
     constructor(
         sizedTile: SizedTile<EditTileViewModel>,
         row: Int,
-    ) : this(tile = sizedTile.tile, row = row, width = sizedTile.width)
+        column: Int,
+    ) : this(tile = sizedTile.tile, row = row, column = column, width = sizedTile.width)
 }
 
 /** Represents an empty space used to fill incomplete rows. Will always display as a 1x1 tile */
@@ -73,7 +75,13 @@
     return splitInRowsSequence(this, columns)
         .flatMapIndexed { rowIndex, sizedTiles ->
             val correctedRowIndex = rowIndex + startingRow
-            val row: List<GridCell> = sizedTiles.map { TileGridCell(it, correctedRowIndex) }
+            var column = 0
+            val row: List<GridCell> =
+                sizedTiles.map {
+                    TileGridCell(it, correctedRowIndex, column).also { cell ->
+                        column += cell.width
+                    }
+                }
 
             // Fill the incomplete rows with spacers
             val numSpacers = columns - sizedTiles.sumOf { it.width }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/BounceableTileViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/BounceableTileViewModel.kt
new file mode 100644
index 0000000..506b052
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/BounceableTileViewModel.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2024 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.qs.panels.ui.viewmodel
+
+import androidx.compose.animation.core.Animatable
+import androidx.compose.animation.core.VectorConverter
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import com.android.compose.animation.Bounceable
+
+class BounceableTileViewModel : Bounceable {
+    private val animatableBounce = Animatable(0.dp, Dp.VectorConverter)
+    override val bounce: Dp
+        get() = animatableBounce.value
+
+    suspend fun animateBounce() {
+        animatableBounce.animateTo(BounceSize)
+        animatableBounce.animateTo(0.dp)
+    }
+
+    private companion object {
+        val BounceSize = 8.dp
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditTileViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditTileViewModel.kt
index ee12736f..be6ce5c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditTileViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditTileViewModel.kt
@@ -43,13 +43,13 @@
 ) {
     fun load(context: Context): EditTileViewModel {
         return EditTileViewModel(
-            tileSpec,
-            icon,
-            label.toAnnotatedString(context) ?: AnnotatedString(tileSpec.spec),
-            appName?.toAnnotatedString(context),
-            isCurrent,
-            availableEditActions,
-            category,
+            tileSpec = tileSpec,
+            icon = icon,
+            label = label.toAnnotatedString(context) ?: AnnotatedString(tileSpec.spec),
+            appName = appName?.toAnnotatedString(context),
+            isCurrent = isCurrent,
+            availableEditActions = availableEditActions,
+            category = category,
         )
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileCoroutineScopeFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileCoroutineScopeFactory.kt
index b8f4ab4..dde3628 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileCoroutineScopeFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileCoroutineScopeFactory.kt
@@ -16,7 +16,7 @@
 
 package com.android.systemui.qs.tiles.base.viewmodel
 
-import com.android.app.tracing.coroutines.createCoroutineTracingContext
+import com.android.systemui.coroutines.newTracingContext
 import com.android.systemui.dagger.qualifiers.Application
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
@@ -28,5 +28,7 @@
 constructor(@Application private val applicationScope: CoroutineScope) {
 
     fun create(): CoroutineScope =
-        CoroutineScope(applicationScope.coroutineContext + SupervisorJob() + createCoroutineTracingContext("QSTileScope"))
+        CoroutineScope(
+            applicationScope.coroutineContext + SupervisorJob() + newTracingContext("QSTileScope")
+        )
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogManager.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogManager.kt
index ae56c2a..f674971 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogManager.kt
@@ -15,12 +15,12 @@
  */
 package com.android.systemui.qs.tiles.dialog
 
-import com.android.app.tracing.coroutines.createCoroutineTracingContext
 import android.util.Log
 import com.android.internal.jank.InteractionJankMonitor
 import com.android.systemui.animation.DialogCuj
 import com.android.systemui.animation.DialogTransitionAnimator
 import com.android.systemui.animation.Expandable
+import com.android.systemui.coroutines.newTracingContext
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.statusbar.phone.SystemUIDialog
@@ -63,7 +63,7 @@
             }
             return
         } else {
-            coroutineScope = CoroutineScope(bgDispatcher + createCoroutineTracingContext("InternetDialogScope"))
+            coroutineScope = CoroutineScope(bgDispatcher + newTracingContext("InternetDialogScope"))
             dialog =
                 dialogFactory
                     .create(aboveStatusBar, canConfigMobileData, canConfigWifi, coroutineScope)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/location/domain/interactor/LocationTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/location/domain/interactor/LocationTileUserActionInteractor.kt
index ac75932..1411544 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/location/domain/interactor/LocationTileUserActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/location/domain/interactor/LocationTileUserActionInteractor.kt
@@ -16,9 +16,9 @@
 
 package com.android.systemui.qs.tiles.impl.location.domain.interactor
 
-import com.android.app.tracing.coroutines.createCoroutineTracingContext
 import android.content.Intent
 import android.provider.Settings
+import com.android.systemui.coroutines.newTracingContext
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.plugins.ActivityStarter
@@ -53,9 +53,11 @@
                     val wasEnabled: Boolean = input.data.isEnabled
                     if (keyguardController.isMethodSecure() && keyguardController.isShowing()) {
                         activityStarter.postQSRunnableDismissingKeyguard {
-                            CoroutineScope(applicationScope.coroutineContext + createCoroutineTracingContext("LocationTileScope")).launch {
-                                locationController.setLocationEnabled(!wasEnabled)
-                            }
+                            CoroutineScope(
+                                    applicationScope.coroutineContext +
+                                        newTracingContext("LocationTileScope")
+                                )
+                                .launch { locationController.setLocationEnabled(!wasEnabled) }
                         }
                     } else {
                         withContext(coroutineContext) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt
index 40591bf..cc14e71 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/domain/interactor/ModesTileDataInteractor.kt
@@ -18,7 +18,7 @@
 
 import android.content.Context
 import android.os.UserHandle
-import com.android.app.tracing.coroutines.flow.map
+import com.android.app.tracing.coroutines.flow.flowName
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.common.shared.model.asIcon
 import com.android.systemui.dagger.qualifiers.Background
@@ -37,6 +37,7 @@
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
 
 class ModesTileDataInteractor
 @Inject
@@ -59,6 +60,7 @@
     fun tileData() =
         zenModeInteractor.activeModes
             .map { activeModes -> buildTileData(activeModes) }
+            .flowName("tileData")
             .flowOn(bgDispatcher)
             .distinctUntilChanged()
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegate.kt
index 468e180..f03c752 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegate.kt
@@ -16,12 +16,12 @@
 
 package com.android.systemui.qs.tiles.impl.saver.domain
 
-import com.android.app.tracing.coroutines.createCoroutineTracingContext
 import android.content.Context
 import android.content.DialogInterface
 import android.content.SharedPreferences
 import android.os.Bundle
 import com.android.internal.R
+import com.android.systemui.coroutines.newTracingContext
 import com.android.systemui.qs.tiles.impl.saver.domain.interactor.DataSaverTileUserActionInteractor
 import com.android.systemui.statusbar.phone.SystemUIDialog
 import com.android.systemui.statusbar.policy.DataSaverController
@@ -45,9 +45,8 @@
             setTitle(R.string.data_saver_enable_title)
             setMessage(R.string.data_saver_description)
             setPositiveButton(R.string.data_saver_enable_button) { _: DialogInterface?, _ ->
-                CoroutineScope(backgroundContext + createCoroutineTracingContext("DataSaverDialogScope")).launch {
-                    dataSaverController.setDataSaverEnabled(true)
-                }
+                CoroutineScope(backgroundContext + newTracingContext("DataSaverDialogScope"))
+                    .launch { dataSaverController.setDataSaverEnabled(true) }
 
                 sharedPreferences
                     .edit()
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
index ce942fe..47254775 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
@@ -19,7 +19,7 @@
 import android.view.MotionEvent
 import android.view.View
 import androidx.compose.runtime.getValue
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.compose.animation.scene.ContentKey
 import com.android.compose.animation.scene.DefaultEdgeDetector
 import com.android.compose.animation.scene.ObservableTransitionState
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionExecutor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ActionExecutor.kt
index 54e0319..17b1b6d 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionExecutor.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionExecutor.kt
@@ -26,7 +26,7 @@
 import android.util.Log
 import android.util.Pair
 import android.view.Window
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.internal.app.ChooserActivity
 import com.android.systemui.dagger.qualifiers.Application
 import dagger.assisted.Assisted
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
index 9e62280..7b01c36 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
@@ -31,7 +31,7 @@
 import android.view.RemoteAnimationTarget
 import android.view.WindowManager
 import android.view.WindowManagerGlobal
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.internal.infra.ServiceConnector
 import com.android.systemui.Flags
 import com.android.systemui.dagger.SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt
index c8067df..6df22f0 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt
@@ -21,7 +21,7 @@
 import android.util.Log
 import androidx.lifecycle.LifecycleService
 import androidx.lifecycle.lifecycleScope
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.shade.ShadeExpansionStateManager
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSoundController.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSoundController.kt
index d3a7fc4a..7aeec47 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSoundController.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSoundController.kt
@@ -18,7 +18,7 @@
 
 import android.media.MediaPlayer
 import android.util.Log
-import com.android.app.tracing.coroutines.async
+import com.android.app.tracing.coroutines.asyncTraced as async
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
 import javax.inject.Inject
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt
index 949d2aa..460bfbb 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.shade.domain.interactor
 
+import com.android.app.tracing.coroutines.flow.flowName
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyguard.data.repository.KeyguardRepository
@@ -62,17 +63,20 @@
     override val isShadeEnabled: StateFlow<Boolean> =
         disableFlagsRepository.disableFlags
             .map { it.isShadeEnabled() }
+            .flowName("isShadeEnabled")
             .stateIn(scope, SharingStarted.Eagerly, initialValue = false)
 
     override val isQsEnabled: StateFlow<Boolean> =
         disableFlagsRepository.disableFlags
             .map { it.isQuickSettingsEnabled() }
+            .flowName("isQsEnabled")
             .stateIn(scope, SharingStarted.Eagerly, initialValue = false)
 
     override val isAnyFullyExpanded: StateFlow<Boolean> =
         anyExpansion
             .map { it >= 1f }
             .distinctUntilChanged()
+            .flowName("isAnyFullyExpanded")
             .stateIn(scope, SharingStarted.Eagerly, initialValue = false)
 
     override val isShadeFullyExpanded: Flow<Boolean> =
@@ -81,6 +85,7 @@
     override val isShadeAnyExpanded: StateFlow<Boolean> =
         baseShadeInteractor.shadeExpansion
             .map { it > 0 }
+            .flowName("isShadeAnyExpanded")
             .stateIn(scope, SharingStarted.Eagerly, false)
 
     override val isShadeFullyCollapsed: Flow<Boolean> =
@@ -88,6 +93,7 @@
 
     override val isUserInteracting: StateFlow<Boolean> =
         combine(isUserInteractingWithShade, isUserInteractingWithQs) { shade, qs -> shade || qs }
+            .flowName("isUserInteracting")
             .stateIn(scope, SharingStarted.Eagerly, false)
 
     override val isShadeTouchable: Flow<Boolean> =
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeUserActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeUserActionsViewModel.kt
index 3113dc4..4bdd367 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeUserActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeUserActionsViewModel.kt
@@ -16,7 +16,6 @@
 
 package com.android.systemui.shade.ui.viewmodel
 
-import com.android.app.tracing.coroutines.flow.map
 import com.android.compose.animation.scene.Swipe
 import com.android.compose.animation.scene.SwipeDirection
 import com.android.compose.animation.scene.UserAction
@@ -33,6 +32,7 @@
 import dagger.assisted.AssistedInject
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.map
 
 /**
  * Models the UI state for the user actions that the user can perform to navigate to other scenes.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/emptyshade/ui/viewmodel/EmptyShadeViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/emptyshade/ui/viewmodel/EmptyShadeViewModel.kt
index 695e088..fbec640 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/emptyshade/ui/viewmodel/EmptyShadeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/emptyshade/ui/viewmodel/EmptyShadeViewModel.kt
@@ -18,7 +18,6 @@
 
 import android.content.Context
 import android.icu.text.MessageFormat
-import com.android.app.tracing.coroutines.flow.flowOn
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.modes.shared.ModesUi
@@ -40,6 +39,7 @@
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.map
 
 /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index 560028c..4c7d90c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -830,4 +830,13 @@
             });
         }
     }
+
+    protected void dumpAppearAnimationProperties(IndentingPrintWriter pw, String[] args) {
+        pw.print("AppearAnimation: ");
+        pw.print("mDrawingAppearAnimation", mDrawingAppearAnimation);
+        pw.print("mAppearAnimationFraction", mAppearAnimationFraction);
+        pw.print("mIsHeadsUpAnimation", mIsHeadsUpAnimation);
+        pw.print("mTargetPoint", mTargetPoint);
+        pw.println();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 49153d1..33dbbc2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -3883,6 +3883,7 @@
                 dumpHeights(pw);
             }
             showingLayout.dump(pw, args);
+            dumpAppearAnimationProperties(pw, args);
             dumpCustomOutline(pw, args);
             dumpClipping(pw, args);
             if (getViewState() != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewsFactoryContainer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewsFactoryContainer.kt
index b90aa10..71f9c07 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewsFactoryContainer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewsFactoryContainer.kt
@@ -19,6 +19,7 @@
 import android.widget.flags.Flags.notifLinearlayoutOptimized
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
+import com.android.systemui.statusbar.notification.row.icon.NotificationRowIconViewInflaterFactory
 import com.android.systemui.statusbar.notification.shared.NotificationViewFlipperPausing
 import javax.inject.Inject
 import javax.inject.Provider
@@ -35,6 +36,7 @@
     bigPictureLayoutInflaterFactory: BigPictureLayoutInflaterFactory,
     optimizedLinearLayoutFactory: NotificationOptimizedLinearLayoutFactory,
     notificationViewFlipperFactory: Provider<NotificationViewFlipperFactory>,
+    notificationRowIconViewInflaterFactory: NotificationRowIconViewInflaterFactory,
 ) : NotifRemoteViewsFactoryContainer {
     override val factories: Set<NotifRemoteViewsFactory> = buildSet {
         add(precomputedTextViewFactory)
@@ -47,5 +49,8 @@
         if (NotificationViewFlipperPausing.isEnabled) {
             add(notificationViewFlipperFactory.get())
         }
+        if (android.app.Flags.notificationsRedesignAppIcons()) {
+            add(notificationRowIconViewInflaterFactory)
+        }
     }
 }
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 e10fd8f..41abac1 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
@@ -342,7 +342,7 @@
      * Cancel any pending content view frees from {@link #freeNotificationView} for the provided
      * content views.
      *
-     * @param row top level notification row containing the content views
+     * @param row          top level notification row containing the content views
      * @param contentViews content views to cancel pending frees on
      */
     private void cancelContentViewFrees(
@@ -478,6 +478,13 @@
                 notifLayoutInflaterFactoryProvider.provide(row, FLAG_CONTENT_VIEW_HEADS_UP));
         setRemoteViewsInflaterFactory(result.newPublicView,
                 notifLayoutInflaterFactoryProvider.provide(row, FLAG_CONTENT_VIEW_PUBLIC));
+        if (android.app.Flags.notificationsRedesignAppIcons()) {
+            setRemoteViewsInflaterFactory(result.mNewGroupHeaderView,
+                    notifLayoutInflaterFactoryProvider.provide(row, FLAG_GROUP_SUMMARY_HEADER));
+            setRemoteViewsInflaterFactory(result.mNewMinimizedGroupHeaderView,
+                    notifLayoutInflaterFactoryProvider.provide(row,
+                            FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER));
+        }
     }
 
     private static void setRemoteViewsInflaterFactory(RemoteViews remoteViews,
@@ -516,6 +523,7 @@
                     logger.logAsyncTaskProgress(entry, "contracted view applied");
                     result.inflatedContentView = v;
                 }
+
                 @Override
                 public RemoteViews getRemoteView() {
                     return result.newContentView;
@@ -1406,6 +1414,7 @@
     @VisibleForTesting
     abstract static class ApplyCallback {
         public abstract void setResultView(View v);
+
         public abstract RemoteViews getRemoteView();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java
index 84f2f66..43ade5c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowModule.java
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.notification.row;
 
 import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.statusbar.notification.row.icon.AppIconProviderModule;
 import com.android.systemui.statusbar.notification.row.shared.NotificationRowContentBinderRefactor;
 
 import dagger.Binds;
@@ -28,7 +29,7 @@
 /**
  * Dagger Module containing notification row and view inflation implementations.
  */
-@Module
+@Module(includes = {AppIconProviderModule.class})
 public abstract class NotificationRowModule {
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/icon/AppIconProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/icon/AppIconProvider.kt
new file mode 100644
index 0000000..24b5cf1a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/icon/AppIconProvider.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2024 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.icon
+
+import android.app.ActivityManager
+import android.app.Flags
+import android.content.Context
+import android.content.pm.PackageManager.NameNotFoundException
+import android.graphics.Color
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.ColorDrawable
+import android.graphics.drawable.Drawable
+import android.util.Log
+import com.android.internal.R
+import com.android.launcher3.icons.BaseIconFactory
+import com.android.systemui.dagger.SysUISingleton
+import dagger.Module
+import dagger.Provides
+import javax.inject.Inject
+import javax.inject.Provider
+
+/** A provider used to cache and fetch app icons used by notifications. */
+interface AppIconProvider {
+    @Throws(NameNotFoundException::class)
+    fun getOrFetchAppIcon(packageName: String, context: Context): Drawable
+}
+
+@SysUISingleton
+class AppIconProviderImpl @Inject constructor(private val sysuiContext: Context) : AppIconProvider {
+    private val iconFactory: BaseIconFactory
+        get() {
+            val isLowRam = ActivityManager.isLowRamDeviceStatic()
+            val res = sysuiContext.resources
+            val iconSize: Int =
+                res.getDimensionPixelSize(
+                    if (isLowRam) R.dimen.notification_small_icon_size_low_ram
+                    else R.dimen.notification_small_icon_size
+                )
+            return BaseIconFactory(sysuiContext, res.configuration.densityDpi, iconSize)
+        }
+
+    override fun getOrFetchAppIcon(packageName: String, context: Context): Drawable {
+        val icon = context.packageManager.getApplicationIcon(packageName)
+        return BitmapDrawable(
+            context.resources,
+            iconFactory.createScaledBitmap(icon, BaseIconFactory.MODE_HARDWARE),
+        )
+    }
+}
+
+class NoOpIconProvider : AppIconProvider {
+    companion object {
+        const val TAG = "NoOpIconProvider"
+    }
+
+    override fun getOrFetchAppIcon(packageName: String, context: Context): Drawable {
+        Log.wtf(TAG, "NoOpIconProvider should not be used anywhere.")
+        return ColorDrawable(Color.WHITE)
+    }
+}
+
+@Module
+class AppIconProviderModule {
+    @Provides
+    @SysUISingleton
+    fun provideImpl(realImpl: Provider<AppIconProviderImpl>): AppIconProvider =
+        if (Flags.notificationsRedesignAppIcons()) {
+            realImpl.get()
+        } else {
+            NoOpIconProvider()
+        }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/icon/NotificationRowIconViewInflaterFactory.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/icon/NotificationRowIconViewInflaterFactory.kt
new file mode 100644
index 0000000..2522e58
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/icon/NotificationRowIconViewInflaterFactory.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2024 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.icon
+
+import android.content.Context
+import android.graphics.drawable.Drawable
+import android.util.AttributeSet
+import android.view.View
+import com.android.internal.widget.NotificationRowIconView
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.row.NotifRemoteViewsFactory
+import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder
+import javax.inject.Inject
+
+/**
+ * A factory which owns the construction of any NotificationRowIconView inside of Notifications in
+ * SystemUI. This allows overriding the small icon with the app icon in notifications.
+ */
+class NotificationRowIconViewInflaterFactory
+@Inject
+constructor(private val appIconProvider: AppIconProvider) : NotifRemoteViewsFactory {
+    override fun instantiate(
+        row: ExpandableNotificationRow,
+        @NotificationRowContentBinder.InflationFlag layoutType: Int,
+        parent: View?,
+        name: String,
+        context: Context,
+        attrs: AttributeSet,
+    ): View? {
+        return when (name) {
+            NotificationRowIconView::class.java.name ->
+                NotificationRowIconView(context, attrs).also { view ->
+                    val sbn = row.entry.sbn
+                    view.setIconProvider(
+                        object : NotificationRowIconView.NotificationIconProvider {
+                            override fun shouldShowAppIcon(): Boolean {
+                                // TODO(b/371174789): implement me
+                                return true
+                            }
+
+                            override fun getAppIcon(): Drawable {
+                                return appIconProvider.getOrFetchAppIcon(sbn.packageName, context)
+                            }
+                        }
+                    )
+                }
+            else -> null
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 00c5c40..f3437b5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -2098,8 +2098,13 @@
     }
 
     class TouchHandler implements Gefingerpoken {
+        private boolean mSwipeWantsIt = false;
+
         @Override
         public boolean onInterceptTouchEvent(MotionEvent ev) {
+            // Reset on each call to intercept, and share swipe state with onTouchEvent()
+            // below when this method returns true.
+            mSwipeWantsIt = false;
             mView.initDownStates(ev);
             mView.handleEmptySpaceClick(ev);
 
@@ -2126,17 +2131,16 @@
                     mView.startDraggingOnHun();
                 }
             }
-            boolean swipeWantsIt = false;
             if (mLongPressedView == null && !mView.isBeingDragged()
                     && !mView.isExpandingNotification()
                     && !mView.getExpandedInThisMotion()
                     && !mView.getOnlyScrollingInThisMotion()
                     && !mView.getDisallowDismissInThisMotion()) {
-                swipeWantsIt = mSwipeHelper.onInterceptTouchEvent(ev);
+                mSwipeWantsIt = mSwipeHelper.onInterceptTouchEvent(ev);
             }
             // Check if we need to clear any snooze leavebehinds
             boolean isUp = ev.getActionMasked() == MotionEvent.ACTION_UP;
-            if (!NotificationSwipeHelper.isTouchInView(ev, guts) && isUp && !swipeWantsIt &&
+            if (!NotificationSwipeHelper.isTouchInView(ev, guts) && isUp && !mSwipeWantsIt &&
                     !expandWantsIt && !scrollWantsIt) {
                 mView.setCheckForLeaveBehind(false);
                 mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */,
@@ -2155,7 +2159,8 @@
                     && ev.getActionMasked() != MotionEvent.ACTION_DOWN) {
                 mJankMonitor.begin(mView, CUJ_NOTIFICATION_SHADE_SCROLL_FLING);
             }
-            return swipeWantsIt || scrollWantsIt || expandWantsIt || longPressWantsIt || hunWantsIt;
+            return mSwipeWantsIt || scrollWantsIt || expandWantsIt || longPressWantsIt ||
+                    hunWantsIt;
         }
 
         @Override
@@ -2192,7 +2197,7 @@
                     }
                 }
             }
-            boolean horizontalSwipeWantsIt = false;
+            boolean horizontalSwipeWantsIt = mSwipeWantsIt;
             boolean scrollerWantsIt = false;
             // NOTE: the order of these is important. If reversed, onScrollTouch will reset on an
             // UP event, causing horizontalSwipeWantsIt to be set to true on vertical swipes.
@@ -2201,7 +2206,7 @@
                     && !mView.getExpandedInThisMotion()
                     && !onlyScrollingInThisMotion
                     && !mView.getDisallowDismissInThisMotion()) {
-                horizontalSwipeWantsIt = mSwipeHelper.onTouchEvent(ev);
+                mSwipeHelper.onTouchEvent(ev);
             }
             if (mLongPressedView == null && mView.isExpanded() && !mSwipeHelper.isSwiping()
                     && !expandingNotification && !mView.getDisallowScrollingInThisMotion()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
index 87d70ba..fb42ee7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt
@@ -17,7 +17,8 @@
 package com.android.systemui.statusbar.notification.stack.ui.viewbinder
 
 import android.util.Log
-import com.android.app.tracing.coroutines.flow.filter
+import com.android.app.tracing.coroutines.flow.collectTraced
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.common.ui.ConfigurationState
 import com.android.systemui.common.ui.view.onLayoutChanged
 import com.android.systemui.dagger.SysUISingleton
@@ -37,7 +38,6 @@
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.filter
-import kotlinx.coroutines.launch
 
 /** Binds the [NotificationScrollView]. */
 @SysUISingleton
@@ -79,39 +79,39 @@
             launch {
                 viewModel
                     .shadeScrimShape(cornerRadius = scrimRadius, viewLeftOffset = viewLeftOffset)
-                    .collect { view.setScrimClippingShape(it) }
+                    .collectTraced { view.setScrimClippingShape(it) }
             }
 
-            launch { viewModel.maxAlpha.collect { view.setMaxAlpha(it) } }
-            launch { viewModel.scrolledToTop.collect { view.setScrolledToTop(it) } }
+            launch { viewModel.maxAlpha.collectTraced { view.setMaxAlpha(it) } }
+            launch { viewModel.scrolledToTop.collectTraced { view.setScrolledToTop(it) } }
             launch {
-                viewModel.expandFraction.collect { view.setExpandFraction(it.coerceIn(0f, 1f)) }
+                viewModel.expandFraction.collectTraced { view.setExpandFraction(it.coerceIn(0f, 1f)) }
             }
-            launch { viewModel.qsExpandFraction.collect { view.setQsExpandFraction(it) } }
+            launch { viewModel.qsExpandFraction.collectTraced { view.setQsExpandFraction(it) } }
             launch {
-                viewModel.isShowingStackOnLockscreen.collect {
+                viewModel.isShowingStackOnLockscreen.collectTraced {
                     view.setShowingStackOnLockscreen(it)
                 }
             }
             launch {
-                viewModel.alphaForLockscreenFadeIn.collect { view.setAlphaForLockscreenFadeIn(it) }
+                viewModel.alphaForLockscreenFadeIn.collectTraced { view.setAlphaForLockscreenFadeIn(it) }
             }
-            launch { viewModel.isScrollable.collect { view.setScrollingEnabled(it) } }
-            launch { viewModel.isDozing.collect { isDozing -> view.setDozing(isDozing) } }
+            launch { viewModel.isScrollable.collectTraced { view.setScrollingEnabled(it) } }
+            launch { viewModel.isDozing.collectTraced { isDozing -> view.setDozing(isDozing) } }
             launch {
-                viewModel.isPulsing.collect { isPulsing ->
+                viewModel.isPulsing.collectTraced { isPulsing ->
                     view.setPulsing(isPulsing, viewModel.shouldAnimatePulse.value)
                 }
             }
             launch {
                 viewModel.shouldResetStackTop
                     .filter { it }
-                    .collect { view.setStackTop(-(view.getHeadsUpInset().toFloat())) }
+                    .collectTraced { view.setStackTop(-(view.getHeadsUpInset().toFloat())) }
             }
             launch {
-                viewModel.shouldCloseGuts.filter { it }.collect { view.closeGutsOnSceneTouch() }
+                viewModel.shouldCloseGuts.filter { it }.collectTraced { view.closeGutsOnSceneTouch() }
             }
-            launch { viewModel.suppressHeightUpdates.collect { view.suppressHeightUpdates(it) } }
+            launch { viewModel.suppressHeightUpdates.collectTraced { view.suppressHeightUpdates(it) } }
 
             launchAndDispose {
                 view.setSyntheticScrollConsumer(viewModel.syntheticScrollConsumer)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
index f39af18..878ae91 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
@@ -20,6 +20,7 @@
 package com.android.systemui.statusbar.notification.stack.ui.viewmodel
 
 import androidx.annotation.VisibleForTesting
+import com.android.app.tracing.coroutines.flow.flowName
 import com.android.systemui.common.shared.model.NotificationContainerBounds
 import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
 import com.android.systemui.dagger.SysUISingleton
@@ -158,6 +159,7 @@
             ) { shadeExpansion, qsExpansion ->
                 shadeExpansion || qsExpansion
             }
+            .flowName("isAnyExpanded")
             .stateIn(
                 scope = applicationScope,
                 started = SharingStarted.Eagerly,
@@ -175,6 +177,7 @@
                 isAnyExpanded ->
                 isShadeLocked && isAnyExpanded
             }
+            .flowName("isShadeLocked")
             .stateIn(
                 scope = applicationScope,
                 started = SharingStarted.Eagerly,
@@ -227,6 +230,7 @@
                 ),
                 keyguardTransitionInteractor.transitionValue(LOCKSCREEN).map { it > 0f },
             )
+            .flowName("isOnLockscreen")
             .stateIn(
                 scope = applicationScope,
                 started = SharingStarted.Eagerly,
@@ -239,6 +243,7 @@
         combine(isOnLockscreen, isAnyExpanded) { isKeyguard, isAnyExpanded ->
                 isKeyguard && !isAnyExpanded
             }
+            .flowName("isOnLockscreenWithoutShade")
             .stateIn(
                 scope = applicationScope,
                 started = SharingStarted.Eagerly,
@@ -274,6 +279,7 @@
         combine(isOnGlanceableHub, isAnyExpanded) { isGlanceableHub, isAnyExpanded ->
                 isGlanceableHub && !isAnyExpanded
             }
+            .flowName("isOnGlanceableHubWithoutShade")
             .stateIn(
                 scope = applicationScope,
                 started = SharingStarted.Eagerly,
@@ -288,6 +294,7 @@
                 isAnyExpanded ->
                 isDreaming && !isAnyExpanded
             }
+            .flowName("isDreamingWithoutShade")
             .stateIn(
                 scope = applicationScope,
                 started = SharingStarted.Eagerly,
@@ -345,6 +352,7 @@
                     }
                 }
             }
+            .flowName("shadeCollapseFadeIn")
             .stateIn(
                 scope = applicationScope,
                 started = SharingStarted.WhileSubscribed(),
@@ -382,6 +390,7 @@
                     bounds.copy(top = top, isAnimated = animate)
                 }
             }
+            .flowName("bounds")
             .stateIn(
                 scope = applicationScope,
                 started = SharingStarted.Lazily,
@@ -495,6 +504,7 @@
         // flatMapLatest below, the last value gets emitted, to avoid the randomness of `merge`.
         val alphaForTransitionsAndShade =
             merge(alphaForTransitions(viewState), alphaForShadeAndQsExpansion)
+                .flowName("alphaForTransitionsAndShade")
                 .stateIn(
                     // Use view-level scope instead of ApplicationScope, to prevent collection that
                     // never stops
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
index 316e1f1..a34ac2e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
@@ -22,7 +22,7 @@
 import android.hardware.biometrics.BiometricSourceType
 import android.provider.Settings
 import com.android.app.tracing.ListenersTracing.forEachTraced
-import com.android.app.tracing.coroutines.launch
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.Dumpable
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 069c624..40e5293 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -1715,26 +1715,6 @@
         updateScrims();
     }
 
-    public void setHasBackdrop(boolean hasBackdrop) {
-        for (ScrimState state : ScrimState.values()) {
-            state.setHasBackdrop(hasBackdrop);
-        }
-
-        // Backdrop event may arrive after state was already applied,
-        // in this case, back-scrim needs to be re-evaluated
-        if (mState == ScrimState.AOD || mState == ScrimState.PULSING) {
-            float newBehindAlpha = mState.getBehindAlpha();
-            if (isNaN(newBehindAlpha)) {
-                throw new IllegalStateException("Scrim opacity is NaN for state: " + mState
-                        + ", back: " + mBehindAlpha);
-            }
-            if (mBehindAlpha != newBehindAlpha) {
-                mBehindAlpha = newBehindAlpha;
-                updateScrims();
-            }
-        }
-    }
-
     private void setKeyguardFadingAway(boolean fadingAway, long duration) {
         for (ScrimState state : ScrimState.values()) {
             state.setKeyguardFadingAway(fadingAway, duration);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index fbba3dc..a0ab612 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -210,7 +210,7 @@
 
         @Override
         public float getMaxLightRevealScrimAlpha() {
-            return mWallpaperSupportsAmbientMode && !mHasBackdrop ? 0f : 1f;
+            return mWallpaperSupportsAmbientMode ? 0f : 1f;
         }
 
         @Override
@@ -369,7 +369,6 @@
     DockManager mDockManager;
     boolean mDisplayRequiresBlanking;
     boolean mWallpaperSupportsAmbientMode;
-    boolean mHasBackdrop;
     boolean mLaunchingAffordanceWithPreview;
     boolean mOccludeAnimationPlaying;
     boolean mWakeLockScreenSensorActive;
@@ -489,10 +488,6 @@
         return false;
     }
 
-    public void setHasBackdrop(boolean hasBackdrop) {
-        mHasBackdrop = hasBackdrop;
-    }
-
     public void setWakeLockScreenSensorActive(boolean active) {
         mWakeLockScreenSensorActive = active;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
index bad6f80..694a5e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
@@ -16,8 +16,8 @@
 
 package com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel
 
-import com.android.app.tracing.coroutines.createCoroutineTracingContext
 import androidx.annotation.VisibleForTesting
+import com.android.systemui.coroutines.newTracingContext
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.flags.FeatureFlagsClassic
@@ -29,8 +29,8 @@
 import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernStatusBarMobileView
 import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
 import javax.inject.Inject
-import kotlinx.coroutines.CoroutineScope
 import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.cancel
@@ -116,7 +116,7 @@
 
     private fun createViewModel(subId: Int): Pair<MobileIconViewModel, CoroutineScope> {
         // Create a child scope so we can cancel it
-        val vmScope = scope.createChildScope(createCoroutineTracingContext("MobileIconViewModel"))
+        val vmScope = scope.createChildScope(newTracingContext("MobileIconViewModel"))
         val vm =
             MobileIconViewModel(
                 subId,
diff --git a/packages/SystemUI/src/com/android/systemui/util/drawable/DrawableSize.kt b/packages/SystemUI/src/com/android/systemui/util/drawable/DrawableSize.kt
index de92318..d87607d 100644
--- a/packages/SystemUI/src/com/android/systemui/util/drawable/DrawableSize.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/drawable/DrawableSize.kt
@@ -11,6 +11,7 @@
 import android.graphics.drawable.AnimatedVectorDrawable
 import android.graphics.drawable.BitmapDrawable
 import android.graphics.drawable.Drawable
+import android.graphics.drawable.LayerDrawable
 import android.util.Log
 import androidx.annotation.Px
 import com.android.app.tracing.traceSection
@@ -22,36 +23,35 @@
         const val TAG = "SysUiDrawableSize"
 
         /**
-         * Downscales passed Drawable to set maximum width and height. This will only
-         * be done for Drawables that can be downscaled non-destructively - e.g. animated
-         * and stateful drawables will no be downscaled.
+         * Downscales passed Drawable to set maximum width and height. This will only be done for
+         * Drawables that can be downscaled non-destructively - e.g. animated drawables, stateful
+         * drawables, and drawables with mixed-type layers will not be downscaled.
          *
-         * Downscaling will keep the aspect ratio.
-         * This method will not touch drawables that already fit into size specification.
+         * Downscaling will keep the aspect ratio. This method will not touch drawables that already
+         * fit into size specification.
          *
          * @param resources Resources on which to base the density of resized drawable.
          * @param drawable Drawable to downscale.
          * @param maxWidth Maximum width of the downscaled drawable.
          * @param maxHeight Maximum height of the downscaled drawable.
-         *
          * @return returns downscaled drawable if it's possible to downscale it or original if it's
-         *         not.
+         *   not.
          */
         @JvmStatic
         fun downscaleToSize(
             res: Resources,
             drawable: Drawable,
             @Px maxWidth: Int,
-            @Px maxHeight: Int
+            @Px maxHeight: Int,
         ): Drawable {
             traceSection("DrawableSize#downscaleToSize") {
                 // Bitmap drawables can contain big bitmaps as their content while sneaking it past
                 // us using density scaling. Inspect inside the Bitmap drawables for actual bitmap
                 // size for those.
-                val originalWidth = (drawable as? BitmapDrawable)?.bitmap?.width
-                                    ?: drawable.intrinsicWidth
-                val originalHeight = (drawable as? BitmapDrawable)?.bitmap?.height
-                                    ?: drawable.intrinsicHeight
+                val originalWidth =
+                    (drawable as? BitmapDrawable)?.bitmap?.width ?: drawable.intrinsicWidth
+                val originalHeight =
+                    (drawable as? BitmapDrawable)?.bitmap?.height ?: drawable.intrinsicHeight
 
                 // Don't touch drawable if we can't resolve sizes for whatever reason.
                 if (originalWidth <= 0 || originalHeight <= 0) {
@@ -61,14 +61,18 @@
                 // Do not touch drawables that are already within bounds.
                 if (originalWidth < maxWidth && originalHeight < maxHeight) {
                     if (Log.isLoggable(TAG, Log.DEBUG)) {
-                        Log.d(TAG, "Not resizing $originalWidth x $originalHeight" + " " +
-                                "to $maxWidth x $maxHeight")
+                        Log.d(
+                            TAG,
+                            "Not resizing $originalWidth x $originalHeight" +
+                                " " +
+                                "to $maxWidth x $maxHeight",
+                        )
                     }
 
                     return drawable
                 }
 
-                if (!isSimpleBitmap(drawable)) {
+                if (isComplicatedBitmap(drawable)) {
                     return drawable
                 }
 
@@ -80,19 +84,25 @@
                 val height = (originalHeight * scale).toInt()
 
                 if (width <= 0 || height <= 0) {
-                    Log.w(TAG, "Attempted to resize ${drawable.javaClass.simpleName} " +
-                            "from $originalWidth x $originalHeight to invalid $width x $height.")
+                    Log.w(
+                        TAG,
+                        "Attempted to resize ${drawable.javaClass.simpleName} " +
+                            "from $originalWidth x $originalHeight to invalid $width x $height.",
+                    )
                     return drawable
                 }
 
                 if (Log.isLoggable(TAG, Log.DEBUG)) {
-                    Log.d(TAG, "Resizing large drawable (${drawable.javaClass.simpleName}) " +
-                            "from $originalWidth x $originalHeight to $width x $height")
+                    Log.d(
+                        TAG,
+                        "Resizing large drawable (${drawable.javaClass.simpleName}) " +
+                            "from $originalWidth x $originalHeight to $width x $height",
+                    )
                 }
 
                 // We want to keep existing config if it's more efficient than 32-bit RGB.
-                val config = (drawable as? BitmapDrawable)?.bitmap?.config
-                        ?: Bitmap.Config.ARGB_8888
+                val config =
+                    (drawable as? BitmapDrawable)?.bitmap?.config ?: Bitmap.Config.ARGB_8888
                 val scaledDrawableBitmap = Bitmap.createBitmap(width, height, config)
                 val canvas = Canvas(scaledDrawableBitmap)
 
@@ -105,8 +115,8 @@
             }
         }
 
-        private fun isSimpleBitmap(drawable: Drawable): Boolean {
-            return !(drawable.isStateful || isAnimated(drawable))
+        private fun isComplicatedBitmap(drawable: Drawable): Boolean {
+            return drawable.isStateful || isAnimated(drawable) || hasComplicatedLayers(drawable)
         }
 
         private fun isAnimated(drawable: Drawable): Boolean {
@@ -119,5 +129,30 @@
                 drawable is AnimatedStateListDrawable ||
                 drawable is AnimatedVectorDrawable
         }
+
+        private fun hasComplicatedLayers(drawable: Drawable): Boolean {
+            if (drawable !is LayerDrawable) {
+                return false
+            }
+            if (drawable.numberOfLayers == 1) {
+                return false
+            }
+
+            val firstLayerType = drawable.getDrawable(0).javaClass
+            for (i in 1..<drawable.numberOfLayers) {
+                val layer = drawable.getDrawable(i)
+                if (layer.javaClass != firstLayerType) {
+                    // If different layers have different drawable types, we shouldn't scale it down
+                    // because we may lose the level information if one of the layers is a bitmap
+                    // and another layer is a level-list. See b/244282477.
+                    return true
+                }
+                if (isComplicatedBitmap(layer)) {
+                    return true
+                }
+            }
+
+            return false
+        }
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/GlobalCoroutinesModule.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/GlobalCoroutinesModule.kt
index 2af84c7..579af73 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/GlobalCoroutinesModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/GlobalCoroutinesModule.kt
@@ -16,10 +16,9 @@
 
 package com.android.systemui.util.kotlin
 
-import com.android.app.tracing.coroutines.createCoroutineTracingContext
+import com.android.systemui.coroutines.newTracingContext
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.dagger.qualifiers.Tracing
 import dagger.Module
 import dagger.Provides
 import javax.inject.Singleton
@@ -27,7 +26,6 @@
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.ExperimentalCoroutinesApi
 
 /** Providers for various application-wide coroutines-related constructs. */
 @Module
@@ -35,16 +33,15 @@
     @Provides
     @Singleton
     @Application
-    fun applicationScope(
-        @Main dispatcherContext: CoroutineContext,
-    ): CoroutineScope = CoroutineScope(dispatcherContext + createCoroutineTracingContext("ApplicationScope"))
+    fun applicationScope(@Main dispatcherContext: CoroutineContext): CoroutineScope =
+        CoroutineScope(dispatcherContext + newTracingContext("ApplicationScope"))
 
     @Provides
     @Singleton
     @Main
     @Deprecated(
         "Use @Main CoroutineContext instead",
-        ReplaceWith("mainCoroutineContext()", "kotlin.coroutines.CoroutineContext")
+        ReplaceWith("mainCoroutineContext()", "kotlin.coroutines.CoroutineContext"),
     )
     fun mainDispatcher(): CoroutineDispatcher = Dispatchers.Main.immediate
 
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt
index 4d9aaa6..ea8709f 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt
@@ -15,7 +15,6 @@
  */
 package com.android.systemui.util.settings
 
-import com.android.app.tracing.coroutines.createCoroutineTracingContext
 import android.annotation.UserIdInt
 import android.content.ContentResolver
 import android.database.ContentObserver
@@ -24,6 +23,7 @@
 import androidx.annotation.AnyThread
 import androidx.annotation.WorkerThread
 import com.android.app.tracing.TraceUtils.trace
+import com.android.systemui.coroutines.newTracingContext
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.launch
@@ -94,7 +94,7 @@
      */
     @AnyThread
     fun registerContentObserverAsync(name: String, settingsObserver: ContentObserver) =
-        CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("SettingsProxy-A")).launch {
+        CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-A")).launch {
             registerContentObserverSync(getUriFor(name), settingsObserver)
         }
 
@@ -109,9 +109,9 @@
     fun registerContentObserverAsync(
         name: String,
         settingsObserver: ContentObserver,
-        @WorkerThread registered: Runnable
+        @WorkerThread registered: Runnable,
     ) =
-        CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("SettingsProxy-B")).launch {
+        CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-B")).launch {
             registerContentObserverSync(getUriFor(name), settingsObserver)
             registered.run()
         }
@@ -144,7 +144,7 @@
      */
     @AnyThread
     fun registerContentObserverAsync(uri: Uri, settingsObserver: ContentObserver) =
-        CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("SettingsProxy-C")).launch {
+        CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-C")).launch {
             registerContentObserverSync(uri, settingsObserver)
         }
 
@@ -159,9 +159,9 @@
     fun registerContentObserverAsync(
         uri: Uri,
         settingsObserver: ContentObserver,
-        @WorkerThread registered: Runnable
+        @WorkerThread registered: Runnable,
     ) =
-        CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("SettingsProxy-D")).launch {
+        CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-D")).launch {
             registerContentObserverSync(uri, settingsObserver)
             registered.run()
         }
@@ -175,7 +175,7 @@
     fun registerContentObserverSync(
         name: String,
         notifyForDescendants: Boolean,
-        settingsObserver: ContentObserver
+        settingsObserver: ContentObserver,
     ) = registerContentObserverSync(getUriFor(name), notifyForDescendants, settingsObserver)
 
     /**
@@ -204,9 +204,9 @@
     fun registerContentObserverAsync(
         name: String,
         notifyForDescendants: Boolean,
-        settingsObserver: ContentObserver
+        settingsObserver: ContentObserver,
     ) =
-        CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("SettingsProxy-E")).launch {
+        CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-E")).launch {
             registerContentObserverSync(getUriFor(name), notifyForDescendants, settingsObserver)
         }
 
@@ -222,9 +222,9 @@
         name: String,
         notifyForDescendants: Boolean,
         settingsObserver: ContentObserver,
-        @WorkerThread registered: Runnable
+        @WorkerThread registered: Runnable,
     ) =
-        CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("SettingsProxy-F")).launch {
+        CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-F")).launch {
             registerContentObserverSync(getUriFor(name), notifyForDescendants, settingsObserver)
             registered.run()
         }
@@ -273,9 +273,9 @@
     fun registerContentObserverAsync(
         uri: Uri,
         notifyForDescendants: Boolean,
-        settingsObserver: ContentObserver
+        settingsObserver: ContentObserver,
     ) =
-        CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("SettingsProxy-G")).launch {
+        CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-G")).launch {
             registerContentObserverSync(uri, notifyForDescendants, settingsObserver)
         }
 
@@ -291,9 +291,9 @@
         uri: Uri,
         notifyForDescendants: Boolean,
         settingsObserver: ContentObserver,
-        @WorkerThread registered: Runnable
+        @WorkerThread registered: Runnable,
     ) =
-        CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("SettingsProxy-H")).launch {
+        CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-H")).launch {
             registerContentObserverSync(uri, notifyForDescendants, settingsObserver)
             registered.run()
         }
@@ -330,7 +330,9 @@
      */
     @AnyThread
     fun unregisterContentObserverAsync(settingsObserver: ContentObserver) =
-        CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("SettingsProxy-I")).launch { unregisterContentObserver(settingsObserver) }
+        CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-I")).launch {
+            unregisterContentObserver(settingsObserver)
+        }
 
     /**
      * Look up a name in the database.
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt b/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt
index c820c07..c5deca2 100644
--- a/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt
@@ -15,7 +15,6 @@
  */
 package com.android.systemui.util.settings
 
-import com.android.app.tracing.coroutines.createCoroutineTracingContext
 import android.annotation.UserIdInt
 import android.annotation.WorkerThread
 import android.content.ContentResolver
@@ -24,6 +23,7 @@
 import android.os.UserHandle
 import android.provider.Settings.SettingNotFoundException
 import com.android.app.tracing.TraceUtils.trace
+import com.android.systemui.coroutines.newTracingContext
 import com.android.systemui.util.settings.SettingsProxy.Companion.parseFloat
 import com.android.systemui.util.settings.SettingsProxy.Companion.parseFloatOrThrow
 import com.android.systemui.util.settings.SettingsProxy.Companion.parseLongOrThrow
@@ -79,7 +79,7 @@
     }
 
     override fun registerContentObserverAsync(uri: Uri, settingsObserver: ContentObserver) =
-        CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("UserSettingsProxy-A")).launch {
+        CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-A")).launch {
             registerContentObserverForUserSync(uri, settingsObserver, userId)
         }
 
@@ -88,7 +88,7 @@
     override fun registerContentObserverSync(
         uri: Uri,
         notifyForDescendants: Boolean,
-        settingsObserver: ContentObserver
+        settingsObserver: ContentObserver,
     ) {
         registerContentObserverForUserSync(uri, notifyForDescendants, settingsObserver, userId)
     }
@@ -111,9 +111,9 @@
     override fun registerContentObserverAsync(
         uri: Uri,
         notifyForDescendants: Boolean,
-        settingsObserver: ContentObserver
+        settingsObserver: ContentObserver,
     ) =
-        CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("UserSettingsProxy-B")).launch {
+        CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-B")).launch {
             registerContentObserverForUserSync(uri, notifyForDescendants, settingsObserver, userId)
         }
 
@@ -156,9 +156,9 @@
     fun registerContentObserverForUserAsync(
         name: String,
         settingsObserver: ContentObserver,
-        userHandle: Int
+        userHandle: Int,
     ) =
-        CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("UserSettingsProxy-C")).launch {
+        CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-C")).launch {
             registerContentObserverForUserSync(getUriFor(name), settingsObserver, userHandle)
         }
 
@@ -197,9 +197,9 @@
     fun registerContentObserverForUserAsync(
         uri: Uri,
         settingsObserver: ContentObserver,
-        userHandle: Int
+        userHandle: Int,
     ) =
-        CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("UserSettingsProxy-D")).launch {
+        CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-D")).launch {
             registerContentObserverForUserSync(uri, settingsObserver, userHandle)
         }
 
@@ -214,9 +214,9 @@
         uri: Uri,
         settingsObserver: ContentObserver,
         userHandle: Int,
-        @WorkerThread registered: Runnable
+        @WorkerThread registered: Runnable,
     ) =
-        CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("UserSettingsProxy-E")).launch {
+        CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-E")).launch {
             registerContentObserverForUserSync(uri, settingsObserver, userHandle)
             registered.run()
         }
@@ -273,14 +273,14 @@
         name: String,
         notifyForDescendants: Boolean,
         settingsObserver: ContentObserver,
-        userHandle: Int
+        userHandle: Int,
     ) {
-        CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("UserSettingsProxy-F")).launch {
+        CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-F")).launch {
             registerContentObserverForUserSync(
                 getUriFor(name),
                 notifyForDescendants,
                 settingsObserver,
-                userHandle
+                userHandle,
             )
         }
     }
@@ -337,14 +337,14 @@
         uri: Uri,
         notifyForDescendants: Boolean,
         settingsObserver: ContentObserver,
-        userHandle: Int
+        userHandle: Int,
     ) =
-        CoroutineScope(backgroundDispatcher + createCoroutineTracingContext("UserSettingsProxy-G")).launch {
+        CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-G")).launch {
             registerContentObserverForUserSync(
                 uri,
                 notifyForDescendants,
                 settingsObserver,
-                userHandle
+                userHandle,
             )
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/domain/VolumeDialogSettingsButtonInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/domain/VolumeDialogSettingsButtonInteractor.kt
index 2dd0bda..5e0af63 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/domain/VolumeDialogSettingsButtonInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/domain/VolumeDialogSettingsButtonInteractor.kt
@@ -17,7 +17,7 @@
 package com.android.systemui.volume.dialog.settings.domain
 
 import android.app.ActivityManager
-import com.android.app.tracing.coroutines.flow.map
+import com.android.app.tracing.coroutines.flow.flowName
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
 import com.android.systemui.volume.Events
 import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog
@@ -30,6 +30,7 @@
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.filterIsInstance
+import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.stateIn
 
 @VolumeDialogScope
@@ -49,6 +50,7 @@
                 deviceProvisionedController.isCurrentUserSetup() &&
                     model.lockTaskModeState == ActivityManager.LOCK_TASK_MODE_NONE
             }
+            .flowName("VDSBI#isVisible")
             .stateIn(coroutineScope, SharingStarted.Eagerly, false)
 
     fun onButtonClicked() {
diff --git a/packages/SystemUI/tests/res/drawable/layer_drawable_all_same_type.xml b/packages/SystemUI/tests/res/drawable/layer_drawable_all_same_type.xml
new file mode 100644
index 0000000..d9ea0b9
--- /dev/null
+++ b/packages/SystemUI/tests/res/drawable/layer_drawable_all_same_type.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 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.
+  -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item android:drawable="@drawable/ic_brightness"/>
+    <item android:drawable="@drawable/ic_brightness"/>
+</layer-list>
diff --git a/packages/SystemUI/tests/res/drawable/layer_drawable_different_types.xml b/packages/SystemUI/tests/res/drawable/layer_drawable_different_types.xml
new file mode 100644
index 0000000..796de8f
--- /dev/null
+++ b/packages/SystemUI/tests/res/drawable/layer_drawable_different_types.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 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.
+  -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+    <!-- dessert_flan is a PNG while ic_brightness is a level-list. -->
+    <item android:drawable="@drawable/dessert_flan"/>
+    <item android:drawable="@drawable/ic_brightness"/>
+</layer-list>
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index e804b33..eecf36e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -309,8 +309,6 @@
         // Attach behind scrim so flows that are collecting on it start running.
         ViewUtils.attachView(mScrimBehind);
 
-        mScrimController.setHasBackdrop(false);
-
         mWallpaperRepository.getWallpaperSupportsAmbientMode().setValue(false);
         mTestScope.getTestScheduler().runCurrent();
 
@@ -483,47 +481,6 @@
     }
 
     @Test
-    public void transitionToAod_withAodWallpaperAndLockScreenWallpaper() {
-        mScrimController.setHasBackdrop(true);
-        mWallpaperRepository.getWallpaperSupportsAmbientMode().setValue(true);
-        mTestScope.getTestScheduler().runCurrent();
-
-        mScrimController.legacyTransitionTo(ScrimState.AOD);
-        finishAnimationsImmediately();
-
-        assertScrimAlpha(Map.of(
-                mScrimInFront, TRANSPARENT,
-                mScrimBehind, TRANSPARENT));
-        assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
-
-        assertScrimTinted(Map.of(
-                mScrimInFront, true,
-                mScrimBehind, true
-        ));
-    }
-
-    @Test
-    public void setHasBackdrop_withAodWallpaperAndAlbumArt() {
-        mWallpaperRepository.getWallpaperSupportsAmbientMode().setValue(true);
-        mTestScope.getTestScheduler().runCurrent();
-
-        mScrimController.legacyTransitionTo(ScrimState.AOD);
-        finishAnimationsImmediately();
-        mScrimController.setHasBackdrop(true);
-        finishAnimationsImmediately();
-
-        assertScrimAlpha(Map.of(
-                mScrimInFront, TRANSPARENT,
-                mScrimBehind, TRANSPARENT));
-        assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
-
-        assertScrimTinted(Map.of(
-                mScrimInFront, true,
-                mScrimBehind, true
-        ));
-    }
-
-    @Test
     public void transitionToAod_withFrontAlphaUpdates() {
         // Assert that setting the AOD front scrim alpha doesn't take effect in a non-AOD state.
         mScrimController.legacyTransitionTo(ScrimState.KEYGUARD);
@@ -1356,7 +1313,6 @@
         mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
         mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront);
         mScrimController.setAnimatorListener(mAnimatorListener);
-        mScrimController.setHasBackdrop(false);
         mWallpaperRepository.getWallpaperSupportsAmbientMode().setValue(false);
         mTestScope.getTestScheduler().runCurrent();
         mScrimController.legacyTransitionTo(ScrimState.KEYGUARD);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 5996ef1..1ceb20a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -198,6 +198,8 @@
 import com.android.wm.shell.taskview.TaskViewTransitions;
 import com.android.wm.shell.transition.Transitions;
 
+import kotlin.Lazy;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -216,7 +218,6 @@
 import java.util.Optional;
 import java.util.concurrent.Executor;
 
-import kotlin.Lazy;
 import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
 import platform.test.runner.parameterized.Parameters;
 
@@ -2481,7 +2482,7 @@
 
         mEntryListener.onEntryAdded(mRow);
 
-        verify(mBubbleLogger).log(argThat(b -> b.getKey().equals(mRow.getKey())),
+        verify(mBubbleLogger).log(eqBubbleWithKey(mRow.getKey()),
                 eq(BubbleLogger.Event.BUBBLE_BAR_BUBBLE_POSTED));
     }
 
@@ -2498,10 +2499,25 @@
         NotificationEntryHelper.modifyRanking(mRow).setTextChanged(true).build();
         mEntryListener.onEntryUpdated(mRow, /* fromSystem= */ true);
 
-        verify(mBubbleLogger).log(argThat(b -> b.getKey().equals(mRow.getKey())),
+        verify(mBubbleLogger).log(eqBubbleWithKey(mRow.getKey()),
                 eq(BubbleLogger.Event.BUBBLE_BAR_BUBBLE_UPDATED));
     }
 
+    @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
+    @Test
+    public void testEventLogging_bubbleBar_dragBubbleToDismiss() {
+        mBubbleProperties.mIsBubbleBarEnabled = true;
+        mPositioner.setIsLargeScreen(true);
+        FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
+        mBubbleController.registerBubbleStateListener(bubbleStateListener);
+
+        mEntryListener.onEntryAdded(mRow);
+        mBubbleController.dragBubbleToDismiss(mRow.getKey(), 1L);
+
+        verify(mBubbleLogger).log(eqBubbleWithKey(mRow.getKey()),
+                eq(BubbleLogger.Event.BUBBLE_BAR_BUBBLE_DISMISSED_DRAG_BUBBLE));
+    }
+
     /** Creates a bubble using the userId and package. */
     private Bubble createBubble(int userId, String pkg) {
         final UserHandle userHandle = new UserHandle(userId);
@@ -2687,6 +2703,10 @@
         assertThat(mSysUiStateBubblesManageMenuExpanded).isEqualTo(manageMenuExpanded);
     }
 
+    private Bubble eqBubbleWithKey(String key) {
+        return argThat(b -> b.getKey().equals(key));
+    }
+
     private static class FakeBubbleStateListener implements Bubbles.BubbleStateListener {
 
         int mStateChangeCalls = 0;
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt
index fc4f05d..a7a6195 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt
@@ -69,6 +69,8 @@
 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.InflationFlag
+import com.android.systemui.statusbar.notification.row.icon.AppIconProviderImpl
+import com.android.systemui.statusbar.notification.row.icon.NotificationRowIconViewInflaterFactory
 import com.android.systemui.statusbar.notification.row.shared.NotificationRowContentBinderRefactor
 import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainerLogger
 import com.android.systemui.statusbar.phone.KeyguardBypassController
@@ -99,7 +101,7 @@
 class ExpandableNotificationRowBuilder(
     private val context: Context,
     dependency: TestableDependency,
-    private val featureFlags: FakeFeatureFlagsClassic = FakeFeatureFlagsClassic()
+    private val featureFlags: FakeFeatureFlagsClassic = FakeFeatureFlagsClassic(),
 ) {
 
     private val mMockLogger: ExpandableNotificationRowLogger
@@ -161,21 +163,21 @@
                         DeviceConfig.NAMESPACE_SYSTEMUI,
                         SystemUiDeviceConfigFlags.SSIN_SHOW_IN_HEADS_UP,
                         "true",
-                        true
+                        true,
                     )
                     setProperty(
                         DeviceConfig.NAMESPACE_SYSTEMUI,
                         SystemUiDeviceConfigFlags.SSIN_ENABLED,
                         "true",
-                        true
+                        true,
                     )
                     setProperty(
                         DeviceConfig.NAMESPACE_SYSTEMUI,
                         SystemUiDeviceConfigFlags.SSIN_REQUIRES_TARGETING_P,
                         "false",
-                        true
+                        true,
                     )
-                }
+                },
             )
         val remoteViewsFactories = getNotifRemoteViewsFactoryContainer(featureFlags)
         val remoteInputManager = Mockito.mock(NotificationRemoteInputManager::class.java, STUB_ONLY)
@@ -192,21 +194,21 @@
                             Mockito.mock(KeyguardDismissUtil::class.java, STUB_ONLY),
                         remoteInputManager = remoteInputManager,
                         smartReplyController = mSmartReplyController,
-                        context = context
+                        context = context,
                     ),
                 smartActionsInflater =
                     SmartActionInflaterImpl(
                         constants = mSmartReplyConstants,
                         activityStarter = Mockito.mock(ActivityStarter::class.java, STUB_ONLY),
                         smartReplyController = mSmartReplyController,
-                        headsUpManager = mHeadsUpManager
-                    )
+                        headsUpManager = mHeadsUpManager,
+                    ),
             )
         val notifLayoutInflaterFactoryProvider =
             object : NotifLayoutInflaterFactory.Provider {
                 override fun provide(
                     row: ExpandableNotificationRow,
-                    layoutType: Int
+                    layoutType: Int,
                 ): NotifLayoutInflaterFactory =
                     NotifLayoutInflaterFactory(row, layoutType, remoteViewsFactories)
             }
@@ -270,14 +272,14 @@
         whenever(
                 mOnUserInteractionCallback.registerFutureDismissal(
                     ArgumentMatchers.any(),
-                    ArgumentMatchers.anyInt()
+                    ArgumentMatchers.anyInt(),
                 )
             )
             .thenReturn(mFutureDismissalRunnable)
     }
 
     private fun getNotifRemoteViewsFactoryContainer(
-        featureFlags: FeatureFlags,
+        featureFlags: FeatureFlags
     ): NotifRemoteViewsFactoryContainer {
         return NotifRemoteViewsFactoryContainerImpl(
             featureFlags,
@@ -285,6 +287,7 @@
             BigPictureLayoutInflaterFactory(),
             NotificationOptimizedLinearLayoutFactory(),
             { Mockito.mock(NotificationViewFlipperFactory::class.java) },
+            NotificationRowIconViewInflaterFactory(AppIconProviderImpl(context)),
         )
     }
 
@@ -293,7 +296,7 @@
             NotificationChannel(
                 notification.channelId,
                 notification.channelId,
-                NotificationManager.IMPORTANCE_DEFAULT
+                NotificationManager.IMPORTANCE_DEFAULT,
             )
         channel.isBlockable = true
         val entry =
@@ -321,7 +324,7 @@
 
     private fun generateRow(
         entry: NotificationEntry,
-        @InflationFlag extraInflationFlags: Int
+        @InflationFlag extraInflationFlags: Int,
     ): ExpandableNotificationRow {
         // NOTE: This flag is read when the ExpandableNotificationRow is inflated, so it needs to be
         //  set, but we do not want to override an existing value that is needed by a specific test.
@@ -329,7 +332,7 @@
         val rowInflaterTask =
             RowInflaterTask(
                 mFakeSystemClock,
-                Mockito.mock(RowInflaterTaskLogger::class.java, STUB_ONLY)
+                Mockito.mock(RowInflaterTaskLogger::class.java, STUB_ONLY),
             )
         val row = rowInflaterTask.inflateSynchronously(context, null, entry)
 
@@ -364,7 +367,7 @@
             mSmartReplyController,
             featureFlags,
             Mockito.mock(IStatusBarService::class.java, STUB_ONLY),
-            Mockito.mock(UiEventLogger::class.java, STUB_ONLY)
+            Mockito.mock(UiEventLogger::class.java, STUB_ONLY),
         )
         row.setAboveShelfChangedListener { aboveShelf: Boolean -> }
         mBindStage.getStageParams(entry).requireContentViews(extraInflationFlags)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/icon/AppIconProviderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/icon/AppIconProviderKosmos.kt
new file mode 100644
index 0000000..08c6bba
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/icon/AppIconProviderKosmos.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2024 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.icon
+
+import android.content.applicationContext
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.appIconProvider by Kosmos.Fixture { AppIconProviderImpl(applicationContext) }
diff --git a/services/autofill/bugfixes.aconfig b/services/autofill/bugfixes.aconfig
index ba84485..1803424 100644
--- a/services/autofill/bugfixes.aconfig
+++ b/services/autofill/bugfixes.aconfig
@@ -49,3 +49,10 @@
   description: "Include the session id into the FillEventHistory events as part of ClientState"
   bug: "333927465"
 }
+
+flag {
+  name: "highlight_autofill_single_field"
+  namespace: "autofill"
+  description: "Highlight single field after autofill selection"
+  bug: "41496744"
+}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 2fa0e0d..8f12b1d 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -39,6 +39,7 @@
 import static android.service.autofill.FillRequest.FLAG_VIEW_NOT_FOCUSED;
 import static android.service.autofill.FillRequest.FLAG_VIEW_REQUESTS_CREDMAN_SERVICE;
 import static android.service.autofill.FillRequest.INVALID_REQUEST_ID;
+import static android.service.autofill.Flags.highlightAutofillSingleField;
 import static android.view.autofill.AutofillManager.ACTION_RESPONSE_EXPIRED;
 import static android.view.autofill.AutofillManager.ACTION_START_SESSION;
 import static android.view.autofill.AutofillManager.ACTION_VALUE_CHANGED;
@@ -49,7 +50,6 @@
 import static android.view.autofill.AutofillManager.EXTRA_AUTOFILL_REQUEST_ID;
 import static android.view.autofill.AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM;
 import static android.view.autofill.AutofillManager.getSmartSuggestionModeToString;
-
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
 import static com.android.server.autofill.FillRequestEventLogger.TRIGGER_REASON_EXPLICITLY_REQUESTED;
 import static com.android.server.autofill.FillRequestEventLogger.TRIGGER_REASON_NORMAL_TRIGGER;
@@ -104,7 +104,6 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.app.Activity;
 import android.app.ActivityTaskManager;
 import android.app.IAssistDataReceiver;
 import android.app.PendingIntent;
@@ -143,7 +142,6 @@
 import android.service.assist.classification.FieldClassificationRequest;
 import android.service.assist.classification.FieldClassificationResponse;
 import android.service.autofill.AutofillFieldClassificationService.Scores;
-import android.service.autofill.AutofillService;
 import android.service.autofill.CompositeUserData;
 import android.service.autofill.ConvertCredentialResponse;
 import android.service.autofill.Dataset;
@@ -186,7 +184,6 @@
 import android.view.autofill.IAutofillWindowPresenter;
 import android.view.inputmethod.InlineSuggestionsRequest;
 import android.widget.RemoteViews;
-
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.logging.MetricsLogger;
@@ -198,7 +195,6 @@
 import com.android.server.autofill.ui.PendingUi;
 import com.android.server.inputmethod.InputMethodManagerInternal;
 import com.android.server.wm.ActivityTaskManagerInternal;
-
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -222,18 +218,21 @@
 /**
  * A session for a given activity.
  *
- * <p>This class manages the multiple {@link ViewState}s for each view it has, and keeps track
- * of the current {@link ViewState} to display the appropriate UI.
+ * <p>This class manages the multiple {@link ViewState}s for each view it has, and keeps track of
+ * the current {@link ViewState} to display the appropriate UI.
  *
- * <p>Although the autofill requests and callbacks are stateless from the service's point of
- * view, we need to keep state in the framework side for cases such as authentication. For
- * example, when service return a {@link FillResponse} that contains all the fields needed
- * to fill the activity but it requires authentication first, that response need to be held
- * until the user authenticates or it times out.
+ * <p>Although the autofill requests and callbacks are stateless from the service's point of view,
+ * we need to keep state in the framework side for cases such as authentication. For example, when
+ * service return a {@link FillResponse} that contains all the fields needed to fill the activity
+ * but it requires authentication first, that response need to be held until the user authenticates
+ * or it times out.
  */
-final class Session implements RemoteFillService.FillServiceCallbacks, ViewState.Listener,
-        AutoFillUI.AutoFillUiCallback, ValueFinder,
-        RemoteFieldClassificationService.FieldClassificationServiceCallbacks {
+final class Session
+        implements RemoteFillService.FillServiceCallbacks,
+                ViewState.Listener,
+                AutoFillUI.AutoFillUiCallback,
+                ValueFinder,
+                RemoteFieldClassificationService.FieldClassificationServiceCallbacks {
     private static final String TAG = "AutofillSession";
 
     // This should never be true in production. This is only for local debugging.
@@ -257,6 +256,7 @@
     private final AutofillManagerServiceImpl mService;
     private final Handler mHandler;
     private final AutoFillUI mUi;
+
     /**
      * Context associated with the session, it has the same {@link Context#getDisplayId() displayId}
      * of the activity being autofilled.
@@ -286,14 +286,11 @@
     /** Session is destroyed and removed from the manager service. */
     public static final int STATE_REMOVED = 3;
 
-    @IntDef(prefix = { "STATE_" }, value = {
-            STATE_UNKNOWN,
-            STATE_ACTIVE,
-            STATE_FINISHED,
-            STATE_REMOVED
-    })
+    @IntDef(
+            prefix = {"STATE_"},
+            value = {STATE_UNKNOWN, STATE_ACTIVE, STATE_FINISHED, STATE_REMOVED})
     @Retention(RetentionPolicy.SOURCE)
-    @interface SessionState{}
+    @interface SessionState {}
 
     @GuardedBy("mLock")
     private final SessionFlags mSessionFlags;
@@ -318,7 +315,8 @@
     public final int mFlags;
 
     @GuardedBy("mLock")
-    @NonNull private IBinder mActivityToken;
+    @NonNull
+    private IBinder mActivityToken;
 
     /** The app activity that's being autofilled */
     @NonNull private final ComponentName mComponentName;
@@ -341,11 +339,10 @@
      * autofill.
      */
     @GuardedBy("mLock")
-    @Nullable private Pair<Integer, InlineSuggestionsRequest> mLastInlineSuggestionsRequest;
+    @Nullable
+    private Pair<Integer, InlineSuggestionsRequest> mLastInlineSuggestionsRequest;
 
-    /**
-     * Id of the View currently being displayed.
-     */
+    /** Id of the View currently being displayed. */
     @GuardedBy("mLock")
     private @Nullable AutofillId mCurrentViewId;
 
@@ -363,8 +360,7 @@
      *
      * <p>Only {@code null} when the session is for augmented autofill only.
      */
-    @Nullable
-    private final RemoteFillService mRemoteFillService;
+    @Nullable private final RemoteFillService mRemoteFillService;
 
     /**
      * With the credman integration, Autofill Framework handles two types of autofill flows -
@@ -379,8 +375,7 @@
      * service the session was initially created with, the secondary provider handler will contain
      * the remaining autofill service.
      */
-    @Nullable
-    private final SecondaryProviderHandler mSecondaryProviderHandler;
+    @Nullable private final SecondaryProviderHandler mSecondaryProviderHandler;
 
     @GuardedBy("mLock")
     private SparseArray<FillResponse> mResponses;
@@ -395,9 +390,7 @@
     @GuardedBy("mLock")
     private ArrayList<FillContext> mContexts;
 
-    /**
-     * Whether the client has an {@link android.view.autofill.AutofillManager.AutofillCallback}.
-     */
+    /** Whether the client has an {@link android.view.autofill.AutofillManager.AutofillCallback}. */
     private boolean mHasCallback;
 
     /** Whether the session has credential manager provider as the primary provider. */
@@ -426,32 +419,24 @@
     @GuardedBy("mLock")
     private PendingUi mPendingSaveUi;
 
-    /**
-     * List of dataset ids selected by the user.
-     */
+    /** List of dataset ids selected by the user. */
     @GuardedBy("mLock")
     private ArrayList<String> mSelectedDatasetIds;
 
-    /**
-     * When the session started (using elapsed time since boot).
-     */
+    /** When the session started (using elapsed time since boot). */
     private final long mStartTime;
 
-    /**
-     * Count of FillRequests in the session.
-     */
+    /** Count of FillRequests in the session. */
     private int mRequestCount;
 
     /**
-     * Starting timestamp of latency logger.
-     * This is set when Session created or when the view is reset.
+     * Starting timestamp of latency logger. This is set when Session created or when the view is
+     * reset.
      */
     @GuardedBy("mLock")
     private long mLatencyBaseTime;
 
-    /**
-     * When the UI was shown for the first time (using elapsed time since boot).
-     */
+    /** When the UI was shown for the first time (using elapsed time since boot). */
     @GuardedBy("mLock")
     private long mUiShownTime;
 
@@ -475,15 +460,11 @@
     @GuardedBy("mLock")
     private final LocalLog mWtfHistory;
 
-    /**
-     * Map of {@link MetricsEvent#AUTOFILL_REQUEST} metrics, keyed by fill request id.
-     */
+    /** Map of {@link MetricsEvent#AUTOFILL_REQUEST} metrics, keyed by fill request id. */
     @GuardedBy("mLock")
     private final SparseArray<LogMaker> mRequestLogs = new SparseArray<>(1);
 
-    /**
-     * Destroys the augmented Autofill UI.
-     */
+    /** Destroys the augmented Autofill UI. */
     // TODO(b/123099468): this runnable is called when the Autofill session is destroyed, the
     // main reason being the cases where user tap HOME.
     // Right now it's completely destroying the UI, but we need to decide whether / how to
@@ -494,13 +475,10 @@
     @Nullable
     private Runnable mAugmentedAutofillDestroyer;
 
-    /**
-     * List of {@link MetricsEvent#AUTOFILL_AUGMENTED_REQUEST} metrics.
-     */
+    /** List of {@link MetricsEvent#AUTOFILL_AUGMENTED_REQUEST} metrics. */
     @GuardedBy("mLock")
     private ArrayList<LogMaker> mAugmentedRequestsLogs;
 
-
     /**
      * List of autofill ids of autofillable fields present in the AssistStructure that can be used
      * to trigger new augmented autofill requests (because the "standard" service was not interested
@@ -509,23 +487,17 @@
     @GuardedBy("mLock")
     private ArrayList<AutofillId> mAugmentedAutofillableIds;
 
-    @NonNull
-    final AutofillInlineSessionController mInlineSessionController;
+    @NonNull final AutofillInlineSessionController mInlineSessionController;
 
-    /**
-     * Receiver of assist data from the app's {@link Activity}.
-     */
+    /** Receiver of assist data from the app's {@link Activity}. */
     private final AssistDataReceiverImpl mAssistReceiver = new AssistDataReceiverImpl();
 
-    /**
-     * Receiver of assist data for pcc purpose
-     */
+    /** Receiver of assist data for pcc purpose */
     private final PccAssistDataReceiverImpl mPccAssistReceiver = new PccAssistDataReceiverImpl();
 
     private final ClassificationState mClassificationState = new ClassificationState();
 
-    @Nullable
-    private final ComponentName mCredentialAutofillService;
+    @Nullable private final ComponentName mCredentialAutofillService;
 
     // TODO(b/216576510): Share one BroadcastReceiver between all Sessions instead of creating a
     // new one per Session.
@@ -547,7 +519,10 @@
                     Slog.v(TAG, "mDelayedFillBroadcastReceiver delayed fill action received");
                     synchronized (mLock) {
                         int requestId = intent.getIntExtra(EXTRA_REQUEST_ID, 0);
-                        FillResponse response = intent.getParcelableExtra(EXTRA_FILL_RESPONSE, android.service.autofill.FillResponse.class);
+                        FillResponse response =
+                                intent.getParcelableExtra(
+                                        EXTRA_FILL_RESPONSE,
+                                        android.service.autofill.FillResponse.class);
                         mFillRequestEventLogger.maybeSetRequestTriggerReason(
                                 TRIGGER_REASON_RETRIGGER);
                         mAssistReceiver.processDelayedFillLocked(requestId, response);
@@ -575,28 +550,25 @@
     @GuardedBy("mLock")
     private SessionCommittedEventLogger mSessionCommittedEventLogger;
 
-    /**
-     * Fill dialog request would likely be sent slightly later.
-     */
+    /** Fill dialog request would likely be sent slightly later. */
     @NonNull
     @GuardedBy("mLock")
     private boolean mPreviouslyFillDialogPotentiallyStarted;
 
     /**
-     * Keeps track of if the user entered view, this is used to
-     * distinguish Fill Request that did not have user interaction
-     * with ones that did.
+     * Keeps track of if the user entered view, this is used to distinguish Fill Request that did
+     * not have user interaction with ones that did.
      *
-     * This is set to true when entering view - after FillDialog FillRequest
-     * or on plain user tap.
+     * <p>This is set to true when entering view - after FillDialog FillRequest or on plain user
+     * tap.
      */
     @NonNull
     @GuardedBy("mLock")
     private boolean mLogViewEntered;
 
     /**
-     * Keeps the fill dialog trigger ids of the last response. This invalidates
-     * the trigger ids of the previous response.
+     * Keeps the fill dialog trigger ids of the last response. This invalidates the trigger ids of
+     * the previous response.
      */
     @Nullable
     @GuardedBy("mLock")
@@ -662,9 +634,7 @@
         return false;
     }
 
-    /**
-     * Collection of flags/booleans that helps determine Session behaviors.
-     */
+    /** Collection of flags/booleans that helps determine Session behaviors. */
     private final class SessionFlags {
         /** Whether autofill is disabled by the service */
         private boolean mAutofillDisabled;
@@ -695,31 +665,35 @@
     final class AssistDataReceiverImpl extends IAssistDataReceiver.Stub {
         @GuardedBy("mLock")
         private boolean mWaitForInlineRequest;
+
         @GuardedBy("mLock")
         private InlineSuggestionsRequest mPendingInlineSuggestionsRequest;
+
         @GuardedBy("mLock")
         private FillRequest mPendingFillRequest;
+
         @GuardedBy("mLock")
         private FillRequest mLastFillRequest;
 
-        @Nullable Consumer<InlineSuggestionsRequest> newAutofillRequestLocked(ViewState viewState,
-                boolean isInlineRequest) {
+        @Nullable
+        Consumer<InlineSuggestionsRequest> newAutofillRequestLocked(
+                ViewState viewState, boolean isInlineRequest) {
             mPendingFillRequest = null;
             mWaitForInlineRequest = isInlineRequest;
             mPendingInlineSuggestionsRequest = null;
             if (isInlineRequest) {
                 WeakReference<AssistDataReceiverImpl> assistDataReceiverWeakReference =
-                    new WeakReference<AssistDataReceiverImpl>(this);
+                        new WeakReference<AssistDataReceiverImpl>(this);
                 WeakReference<ViewState> viewStateWeakReference =
-                    new WeakReference<ViewState>(viewState);
-                return new InlineSuggestionRequestConsumer(assistDataReceiverWeakReference,
-                    viewStateWeakReference);
+                        new WeakReference<ViewState>(viewState);
+                return new InlineSuggestionRequestConsumer(
+                        assistDataReceiverWeakReference, viewStateWeakReference);
             }
             return null;
         }
 
-        void handleInlineSuggestionRequest(InlineSuggestionsRequest inlineSuggestionsRequest,
-                ViewState viewState) {
+        void handleInlineSuggestionRequest(
+                InlineSuggestionsRequest inlineSuggestionsRequest, ViewState viewState) {
             if (sVerbose) {
                 Slog.v(TAG, "handleInlineSuggestionRequest(): inline suggestion request received");
             }
@@ -738,8 +712,10 @@
         void maybeRequestFillLocked() {
             if (mPendingFillRequest == null) {
                 if (sVerbose) {
-                        Slog.v(TAG, "maybeRequestFillLocked(): cancelling calling fill request "
-                            + "due to empty pending fill request");
+                    Slog.v(
+                            TAG,
+                            "maybeRequestFillLocked(): cancelling calling fill request "
+                                    + "due to empty pending fill request");
                 }
                 return;
             }
@@ -748,27 +724,35 @@
             if (mWaitForInlineRequest) {
                 if (mPendingInlineSuggestionsRequest == null) {
                     if (sVerbose) {
-                        Slog.v(TAG, "maybeRequestFillLocked(): cancelling calling fill request "
-                            + "due to waiting for inline request and pending inline request is "
-                            + "currently empty");
+                        Slog.v(
+                                TAG,
+                                "maybeRequestFillLocked(): cancelling calling fill request due to"
+                                    + " waiting for inline request and pending inline request is"
+                                    + " currently empty");
                     }
                     return;
                 }
                 if (sVerbose) {
-                    Slog.v(TAG, "maybeRequestFillLocked(): adding inline request to pending "
-                        + "fill request");
+                    Slog.v(
+                            TAG,
+                            "maybeRequestFillLocked(): adding inline request to pending "
+                                    + "fill request");
                 }
-                mPendingFillRequest = new FillRequest(mPendingFillRequest.getId(),
-                        mPendingFillRequest.getFillContexts(),
-                        mPendingFillRequest.getHints(),
-                        mPendingFillRequest.getClientState(),
-                        mPendingFillRequest.getFlags(),
-                        mPendingInlineSuggestionsRequest,
-                        mPendingFillRequest.getDelayedFillIntentSender());
+                mPendingFillRequest =
+                        new FillRequest(
+                                mPendingFillRequest.getId(),
+                                mPendingFillRequest.getFillContexts(),
+                                mPendingFillRequest.getHints(),
+                                mPendingFillRequest.getClientState(),
+                                mPendingFillRequest.getFlags(),
+                                mPendingInlineSuggestionsRequest,
+                                mPendingFillRequest.getDelayedFillIntentSender());
             } else {
                 if (sVerbose) {
-                    Slog.v(TAG, "maybeRequestFillLocked(): not adding inline request to pending "
-                        + "fill request");
+                    Slog.v(
+                            TAG,
+                            "maybeRequestFillLocked(): not adding inline request to pending "
+                                    + "fill request");
                 }
             }
 
@@ -780,19 +764,19 @@
                     && mSecondaryProviderHandler != null) {
                 Slog.v(TAG, "Requesting fill response to secondary provider.");
                 if (!mIsPrimaryCredential) {
-                    mPendingFillRequest = addCredentialManagerDataToClientState(
-                            mPendingFillRequest,
-                            mPendingInlineSuggestionsRequest, id);
+                    mPendingFillRequest =
+                            addCredentialManagerDataToClientState(
+                                    mPendingFillRequest, mPendingInlineSuggestionsRequest, id);
                 }
-                mSecondaryProviderHandler.onFillRequest(mPendingFillRequest,
-                        mPendingFillRequest.getFlags(), mClient.asBinder());
+                mSecondaryProviderHandler.onFillRequest(
+                        mPendingFillRequest, mPendingFillRequest.getFlags(), mClient.asBinder());
             } else if (mRemoteFillService != null) {
                 if (mIsPrimaryCredential) {
-                    mPendingFillRequest = addCredentialManagerDataToClientState(
-                            mPendingFillRequest,
-                            mPendingInlineSuggestionsRequest, id);
-                    mRemoteFillService.onFillCredentialRequest(mPendingFillRequest,
-                            mClient.asBinder());
+                    mPendingFillRequest =
+                            addCredentialManagerDataToClientState(
+                                    mPendingFillRequest, mPendingInlineSuggestionsRequest, id);
+                    mRemoteFillService.onFillCredentialRequest(
+                            mPendingFillRequest, mClient.asBinder());
                 } else {
                     mRemoteFillService.onFillRequest(mPendingFillRequest);
                 }
@@ -813,8 +797,11 @@
         @Override
         public void onHandleAssistData(Bundle resultData) throws RemoteException {
             if (mRemoteFillService == null) {
-                wtf(null, "onHandleAssistData() called without a remote service. "
-                        + "mForAugmentedAutofillOnly: %s", mSessionFlags.mAugmentedAutofillOnly);
+                wtf(
+                        null,
+                        "onHandleAssistData() called without a remote service. "
+                                + "mForAugmentedAutofillOnly: %s",
+                        mSessionFlags.mAugmentedAutofillOnly);
                 return;
             }
             // Keeps to prevent it is cleared on multiple threads.
@@ -824,7 +811,9 @@
                 return;
             }
 
-            final AssistStructure structure = resultData.getParcelable(ASSIST_KEY_STRUCTURE, android.app.assist.AssistStructure.class);
+            final AssistStructure structure =
+                    resultData.getParcelable(
+                            ASSIST_KEY_STRUCTURE, android.app.assist.AssistStructure.class);
             if (structure == null) {
                 Slog.e(TAG, "No assist structure - app might have crashed providing it");
                 return;
@@ -852,13 +841,16 @@
                 try {
                     structure.ensureDataForAutofill();
                 } catch (RuntimeException e) {
-                    wtf(e, "Exception lazy loading assist structure for %s: %s",
-                            structure.getActivityComponent(), e);
+                    wtf(
+                            e,
+                            "Exception lazy loading assist structure for %s: %s",
+                            structure.getActivityComponent(),
+                            e);
                     return;
                 }
 
-                final ArrayList<AutofillId> ids = Helper.getAutofillIds(structure,
-                        /* autofillableOnly= */false);
+                final ArrayList<AutofillId> ids =
+                        Helper.getAutofillIds(structure, /* autofillableOnly= */ false);
                 for (int i = 0; i < ids.size(); i++) {
                     ids.get(i).setSessionId(Session.this.id);
                 }
@@ -868,8 +860,9 @@
 
                 if (mCompatMode) {
                     // Sanitize URL bar, if needed
-                    final String[] urlBarIds = mService.getUrlBarResourceIdsForCompatMode(
-                            mComponentName.getPackageName());
+                    final String[] urlBarIds =
+                            mService.getUrlBarResourceIdsForCompatMode(
+                                    mComponentName.getPackageName());
                     if (sDebug) {
                         Slog.d(TAG, "url_bars in compat mode: " + Arrays.toString(urlBarIds));
                     }
@@ -878,11 +871,19 @@
                         if (mUrlBar != null) {
                             final AutofillId urlBarId = mUrlBar.getAutofillId();
                             if (sDebug) {
-                                Slog.d(TAG, "Setting urlBar as id=" + urlBarId + " and domain "
-                                        + mUrlBar.getWebDomain());
+                                Slog.d(
+                                        TAG,
+                                        "Setting urlBar as id="
+                                                + urlBarId
+                                                + " and domain "
+                                                + mUrlBar.getWebDomain());
                             }
-                            final ViewState viewState = new ViewState(urlBarId, Session.this,
-                                    ViewState.STATE_URL_BAR, mIsPrimaryCredential);
+                            final ViewState viewState =
+                                    new ViewState(
+                                            urlBarId,
+                                            Session.this,
+                                            ViewState.STATE_URL_BAR,
+                                            mIsPrimaryCredential);
                             mViewStates.put(urlBarId, viewState);
                         }
                     }
@@ -907,11 +908,17 @@
                 final List<String> hints = getTypeHintsForProvider();
 
                 mDelayedFillPendingIntent = createPendingIntent(requestId);
-                request = new FillRequest(requestId, contexts, hints, mClientState, flags,
-                        /*inlineSuggestionsRequest=*/ null,
-                        /*delayedFillIntentSender=*/ mDelayedFillPendingIntent == null
-                            ? null
-                            : mDelayedFillPendingIntent.getIntentSender());
+                request =
+                        new FillRequest(
+                                requestId,
+                                contexts,
+                                hints,
+                                mClientState,
+                                flags,
+                                /* inlineSuggestionsRequest= */ null,
+                                /* delayedFillIntentSender= */ mDelayedFillPendingIntent == null
+                                        ? null
+                                        : mDelayedFillPendingIntent.getIntentSender());
 
                 mPendingFillRequest = request;
                 maybeRequestFillLocked();
@@ -930,39 +937,49 @@
         @GuardedBy("mLock")
         void processDelayedFillLocked(int requestId, FillResponse response) {
             if (mLastFillRequest != null && requestId == mLastFillRequest.getId()) {
-                Slog.v(TAG, "processDelayedFillLocked: "
-                        + "calling onFillRequestSuccess with new response");
-                onFillRequestSuccess(requestId, response,
-                        mService.getServicePackageName(), mLastFillRequest.getFlags());
+                Slog.v(
+                        TAG,
+                        "processDelayedFillLocked: "
+                                + "calling onFillRequestSuccess with new response");
+                onFillRequestSuccess(
+                        requestId,
+                        response,
+                        mService.getServicePackageName(),
+                        mLastFillRequest.getFlags());
             }
         }
     }
 
-    private FillRequest addCredentialManagerDataToClientState(FillRequest pendingFillRequest,
-            InlineSuggestionsRequest pendingInlineSuggestionsRequest, int sessionId) {
+    private FillRequest addCredentialManagerDataToClientState(
+            FillRequest pendingFillRequest,
+            InlineSuggestionsRequest pendingInlineSuggestionsRequest,
+            int sessionId) {
 
         if (pendingFillRequest.getClientState() == null) {
-            pendingFillRequest = new FillRequest(pendingFillRequest.getId(),
-                    pendingFillRequest.getFillContexts(),
-                    pendingFillRequest.getHints(),
-                    new Bundle(),
-                    pendingFillRequest.getFlags(),
-                    pendingInlineSuggestionsRequest,
-                    pendingFillRequest.getDelayedFillIntentSender());
+            pendingFillRequest =
+                    new FillRequest(
+                            pendingFillRequest.getId(),
+                            pendingFillRequest.getFillContexts(),
+                            pendingFillRequest.getHints(),
+                            new Bundle(),
+                            pendingFillRequest.getFlags(),
+                            pendingInlineSuggestionsRequest,
+                            pendingFillRequest.getDelayedFillIntentSender());
         }
         pendingFillRequest.getClientState().putInt(SESSION_ID_KEY, sessionId);
         pendingFillRequest.getClientState().putInt(REQUEST_ID_KEY, pendingFillRequest.getId());
-        ResultReceiver resultReceiver = constructCredentialManagerCallback(
-                pendingFillRequest.getId());
-        pendingFillRequest.getClientState().putParcelable(
-                CredentialManager.EXTRA_AUTOFILL_RESULT_RECEIVER, resultReceiver);
+        ResultReceiver resultReceiver =
+                constructCredentialManagerCallback(pendingFillRequest.getId());
+        pendingFillRequest
+                .getClientState()
+                .putParcelable(CredentialManager.EXTRA_AUTOFILL_RESULT_RECEIVER, resultReceiver);
         return pendingFillRequest;
     }
 
     /**
-     * Get the list of valid autofill hint types from Device flags
-     * Returns empty list if PCC is off or no types available
-    */
+     * Get the list of valid autofill hint types from Device flags Returns empty list if PCC is off
+     * or no types available
+     */
     private List<String> getTypeHintsForProvider() {
         if (!mService.isPccClassificationEnabled()) {
             return Collections.EMPTY_LIST;
@@ -978,9 +995,7 @@
         return List.of(typeHints.split(PCC_HINTS_DELIMITER));
     }
 
-    /**
-     * Assist Data Receiver for PCC
-     */
+    /** Assist Data Receiver for PCC */
     private final class PccAssistDataReceiverImpl extends IAssistDataReceiver.Stub {
 
         @GuardedBy("mLock")
@@ -998,7 +1013,7 @@
                                 new WeakReference<>(Session.this);
                 remoteFieldClassificationService.onFieldClassificationRequest(
                         mClassificationState.mPendingFieldClassificationRequest,
-                                fieldClassificationServiceCallbacksWeakRef);
+                        fieldClassificationServiceCallbacksWeakRef);
             }
             mClassificationState.onFieldClassificationRequestSent();
         }
@@ -1006,26 +1021,35 @@
         @Override
         public void onHandleAssistData(Bundle resultData) throws RemoteException {
             // TODO: add a check if pcc field classification service is present
-            final AssistStructure structure = resultData.getParcelable(ASSIST_KEY_STRUCTURE,
-                android.app.assist.AssistStructure.class);
+            final AssistStructure structure =
+                    resultData.getParcelable(
+                            ASSIST_KEY_STRUCTURE, android.app.assist.AssistStructure.class);
             if (structure == null) {
-                Slog.e(TAG, "No assist structure for pcc detection - "
-                    + "app might have crashed providing it");
+                Slog.e(
+                        TAG,
+                        "No assist structure for pcc detection - "
+                                + "app might have crashed providing it");
                 return;
             }
 
             final Bundle receiverExtras = resultData.getBundle(ASSIST_KEY_RECEIVER_EXTRAS);
             if (receiverExtras == null) {
-                Slog.e(TAG, "No receiver extras for pcc detection - "
-                    + "app might have crashed providing it");
+                Slog.e(
+                        TAG,
+                        "No receiver extras for pcc detection - "
+                                + "app might have crashed providing it");
                 return;
             }
 
             final int requestId = receiverExtras.getInt(EXTRA_REQUEST_ID);
 
             if (sVerbose) {
-                Slog.v(TAG, "New structure for PCC Detection: requestId " + requestId + ": "
-                        + structure);
+                Slog.v(
+                        TAG,
+                        "New structure for PCC Detection: requestId "
+                                + requestId
+                                + ": "
+                                + structure);
             }
 
             synchronized (mLock) {
@@ -1037,13 +1061,16 @@
                 try {
                     structure.ensureDataForAutofill();
                 } catch (RuntimeException e) {
-                    wtf(e, "Exception lazy loading assist structure for %s: %s",
-                        structure.getActivityComponent(), e);
+                    wtf(
+                            e,
+                            "Exception lazy loading assist structure for %s: %s",
+                            structure.getActivityComponent(),
+                            e);
                     return;
                 }
 
-                final ArrayList<AutofillId> ids = Helper.getAutofillIds(structure,
-                    /* autofillableOnly= */false);
+                final ArrayList<AutofillId> ids =
+                        Helper.getAutofillIds(structure, /* autofillableOnly= */ false);
                 for (int i = 0; i < ids.size(); i++) {
                     ids.get(i).setSessionId(Session.this.id);
                 }
@@ -1066,13 +1093,18 @@
         PendingIntent pendingIntent;
         final long identity = Binder.clearCallingIdentity();
         try {
-            Intent intent = new Intent(ACTION_DELAYED_FILL).setPackage("android")
-                    .putExtra(EXTRA_REQUEST_ID, requestId);
-            pendingIntent = PendingIntent.getBroadcast(
-                    mContext, this.id, intent,
-                    PendingIntent.FLAG_MUTABLE
-                        | PendingIntent.FLAG_ONE_SHOT
-                        | PendingIntent.FLAG_CANCEL_CURRENT);
+            Intent intent =
+                    new Intent(ACTION_DELAYED_FILL)
+                            .setPackage("android")
+                            .putExtra(EXTRA_REQUEST_ID, requestId);
+            pendingIntent =
+                    PendingIntent.getBroadcast(
+                            mContext,
+                            this.id,
+                            intent,
+                            PendingIntent.FLAG_MUTABLE
+                                    | PendingIntent.FLAG_ONE_SHOT
+                                    | PendingIntent.FLAG_CANCEL_CURRENT);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -1113,9 +1145,7 @@
         }
     }
 
-    /**
-     * Returns the ids of all entries in {@link #mViewStates} in the same order.
-     */
+    /** Returns the ids of all entries in {@link #mViewStates} in the same order. */
     @GuardedBy("mLock")
     private AutofillId[] getIdsOfAllViewStatesLocked() {
         final int numViewState = mViewStates.size();
@@ -1164,8 +1194,8 @@
     }
 
     /**
-     * <p>Gets the value of a field, using either the {@code viewStates} or the {@code mContexts},
-     * or {@code null} when not found on either of them.
+     * Gets the value of a field, using either the {@code viewStates} or the {@code mContexts}, or
+     * {@code null} when not found on either of them.
      */
     @GuardedBy("mLock")
     @Nullable
@@ -1180,16 +1210,22 @@
         final ArrayList<Session> previousSessions = mService.getPreviousSessionsLocked(this);
         if (previousSessions != null) {
             if (sDebug) {
-                Slog.d(TAG, "findValueLocked(): looking on " + previousSessions.size()
-                        + " previous sessions for autofillId " + autofillId);
+                Slog.d(
+                        TAG,
+                        "findValueLocked(): looking on "
+                                + previousSessions.size()
+                                + " previous sessions for autofillId "
+                                + autofillId);
             }
             for (int i = 0; i < previousSessions.size(); i++) {
                 final Session previousSession = previousSessions.get(i);
-                final AutofillValue previousValue = previousSession
-                        .findValueFromThisSessionOnlyLocked(autofillId);
+                final AutofillValue previousValue =
+                        previousSession.findValueFromThisSessionOnlyLocked(autofillId);
                 if (previousValue != null) {
-                    return getSanitizedValue(createSanitizers(previousSession.getSaveInfoLocked()),
-                            autofillId, previousValue);
+                    return getSanitizedValue(
+                            createSanitizers(previousSession.getSaveInfoLocked()),
+                            autofillId,
+                            previousValue);
                 }
             }
         }
@@ -1212,16 +1248,22 @@
             AutofillValue candidateSaveValue = state.getCandidateSaveValue();
             if (candidateSaveValue != null && !candidateSaveValue.isEmpty()) {
                 if (sDebug) {
-                    Slog.d(TAG, "findValueLocked(): current value for " + autofillId
-                            + " is empty, using candidateSaveValue instead.");
+                    Slog.d(
+                            TAG,
+                            "findValueLocked(): current value for "
+                                    + autofillId
+                                    + " is empty, using candidateSaveValue instead.");
                 }
                 return candidateSaveValue;
             }
         }
         if (value == null) {
             if (sDebug) {
-                Slog.d(TAG, "findValueLocked(): no current value for " + autofillId
-                        + ", checking value from previous fill contexts");
+                Slog.d(
+                        TAG,
+                        "findValueLocked(): no current value for "
+                                + autofillId
+                                + ", checking value from previous fill contexts");
                 value = getValueFromContextsLocked(autofillId);
             }
         }
@@ -1231,17 +1273,16 @@
     /**
      * Updates values of the nodes in the context's structure so that:
      *
-     * - proper node is focused
-     * - autofillValue is sent back to service when it was previously autofilled
-     * - autofillValue is sent in the view used to force a request
+     * <p>- proper node is focused - autofillValue is sent back to service when it was previously
+     * autofilled - autofillValue is sent in the view used to force a request
      *
      * @param fillContext The context to be filled
      * @param flags The flags that started the session
      */
     @GuardedBy("mLock")
     private void fillContextWithAllowedValuesLocked(@NonNull FillContext fillContext, int flags) {
-        final ViewNode[] nodes = fillContext
-                .findViewNodesByAutofillIds(getIdsOfAllViewStatesLocked());
+        final ViewNode[] nodes =
+                fillContext.findViewNodesByAutofillIds(getIdsOfAllViewStatesLocked());
 
         final int numViewState = mViewStates.size();
         for (int i = 0; i < numViewState; i++) {
@@ -1250,7 +1291,8 @@
             final ViewNode node = nodes[i];
             if (node == null) {
                 if (sVerbose) {
-                    Slog.v(TAG,
+                    Slog.v(
+                            TAG,
                             "fillContextWithAllowedValuesLocked(): no node for " + viewState.id);
                 }
                 continue;
@@ -1277,14 +1319,15 @@
         }
     }
 
-    /**
-     * Cancels the last request sent to the {@link #mRemoteFillService}.
-     */
+    /** Cancels the last request sent to the {@link #mRemoteFillService}. */
     @GuardedBy("mLock")
     private void cancelCurrentRequestLocked() {
         if (mRemoteFillService == null) {
-            wtf(null, "cancelCurrentRequestLocked() called without a remote service. "
-                    + "mForAugmentedAutofillOnly: %s", mSessionFlags.mAugmentedAutofillOnly);
+            wtf(
+                    null,
+                    "cancelCurrentRequestLocked() called without a remote service. "
+                            + "mForAugmentedAutofillOnly: %s",
+                    mSessionFlags.mAugmentedAutofillOnly);
             return;
         }
         final int canceledRequest = mRemoteFillService.cancelCurrentRequest();
@@ -1318,21 +1361,20 @@
     private Optional<Integer> requestNewFillResponseLocked(
             @NonNull ViewState viewState, int newState, int flags) {
         boolean isSecondary = shouldRequestSecondaryProvider(flags);
-        final FillResponse existingResponse = isSecondary
-                ? viewState.getSecondaryResponse() : viewState.getResponse();
+        final FillResponse existingResponse =
+                isSecondary ? viewState.getSecondaryResponse() : viewState.getResponse();
         mFillRequestEventLogger.startLogForNewRequest();
         mRequestCount++;
         mFillRequestEventLogger.maybeSetAppPackageUid(uid);
         mFillRequestEventLogger.maybeSetFlags(mFlags);
-        if(mPreviouslyFillDialogPotentiallyStarted) {
+        if (mPreviouslyFillDialogPotentiallyStarted) {
             mFillRequestEventLogger.maybeSetRequestTriggerReason(TRIGGER_REASON_PRE_TRIGGER);
         } else {
             if ((flags & FLAG_MANUAL_REQUEST) != 0) {
                 mFillRequestEventLogger.maybeSetRequestTriggerReason(
                         TRIGGER_REASON_EXPLICITLY_REQUESTED);
             } else {
-                mFillRequestEventLogger.maybeSetRequestTriggerReason(
-                        TRIGGER_REASON_NORMAL_TRIGGER);
+                mFillRequestEventLogger.maybeSetRequestTriggerReason(TRIGGER_REASON_NORMAL_TRIGGER);
             }
         }
         if (existingResponse != null) {
@@ -1348,9 +1390,14 @@
         mSessionState = STATE_ACTIVE;
         if (mSessionFlags.mAugmentedAutofillOnly || mRemoteFillService == null) {
             if (sVerbose) {
-                Slog.v(TAG, "requestNewFillResponse(): triggering augmented autofill instead "
-                        + "(mForAugmentedAutofillOnly=" + mSessionFlags.mAugmentedAutofillOnly
-                        + ", flags=" + flags + ")");
+                Slog.v(
+                        TAG,
+                        "requestNewFillResponse(): triggering augmented autofill instead "
+                                + "(mForAugmentedAutofillOnly="
+                                + mSessionFlags.mAugmentedAutofillOnly
+                                + ", flags="
+                                + flags
+                                + ")");
             }
             mSessionFlags.mAugmentedAutofillOnly = true;
             mFillRequestEventLogger.maybeSetRequestId(AUGMENTED_AUTOFILL_REQUEST_ID);
@@ -1365,16 +1412,23 @@
 
         // Create a metrics log for the request
         final int ordinal = mRequestLogs.size() + 1;
-        final LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_REQUEST)
-                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_REQUEST_ORDINAL, ordinal);
+        final LogMaker log =
+                newLogMaker(MetricsEvent.AUTOFILL_REQUEST)
+                        .addTaggedData(MetricsEvent.FIELD_AUTOFILL_REQUEST_ORDINAL, ordinal);
         if (flags != 0) {
             log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_FLAGS, flags);
         }
         mRequestLogs.put(requestId, log);
 
         if (sVerbose) {
-            Slog.v(TAG, "Requesting structure for request #" + ordinal + " ,requestId=" + requestId
-                    + ", flags=" + flags);
+            Slog.v(
+                    TAG,
+                    "Requesting structure for request #"
+                            + ordinal
+                            + " ,requestId="
+                            + requestId
+                            + ", flags="
+                            + flags);
         }
         boolean isCredmanRequested = (flags & FLAG_VIEW_REQUESTS_CREDMAN_SERVICE) != 0;
         mFillRequestEventLogger.maybeSetRequestId(requestId);
@@ -1406,11 +1460,12 @@
         // is also not focused.
         final RemoteInlineSuggestionRenderService remoteRenderService =
                 mService.getRemoteInlineSuggestionRenderServiceLocked();
-        if (mSessionFlags.mInlineSupportedByService && remoteRenderService != null
-            && (isViewFocusedLocked(flags) || isRequestSupportFillDialog(flags))) {
+        if (mSessionFlags.mInlineSupportedByService
+                && remoteRenderService != null
+                && (isViewFocusedLocked(flags) || isRequestSupportFillDialog(flags))) {
             Consumer<InlineSuggestionsRequest> inlineSuggestionsRequestConsumer =
-                mAssistReceiver.newAutofillRequestLocked(viewState,
-                    /* isInlineRequest= */ true);
+                    mAssistReceiver.newAutofillRequestLocked(
+                            viewState, /* isInlineRequest= */ true);
             if (inlineSuggestionsRequestConsumer != null) {
                 final int requestIdCopy = requestId;
                 final AutofillId focusedId = mCurrentViewId;
@@ -1423,8 +1478,9 @@
                                         requestIdCopy,
                                         inlineSuggestionsRequestConsumer,
                                         focusedId);
-                RemoteCallback inlineSuggestionRendorInfoCallback = new RemoteCallback(
-                        inlineSuggestionRendorInfoCallbackOnResultListener, mHandler);
+                RemoteCallback inlineSuggestionRendorInfoCallback =
+                        new RemoteCallback(
+                                inlineSuggestionRendorInfoCallbackOnResultListener, mHandler);
 
                 remoteRenderService.getInlineSuggestionsRendererInfo(
                         inlineSuggestionRendorInfoCallback);
@@ -1465,8 +1521,9 @@
             receiverExtras.putInt(EXTRA_REQUEST_ID, requestId);
             final long identity = Binder.clearCallingIdentity();
             try {
-                if (!ActivityTaskManager.getService().requestAutofillData(mPccAssistReceiver,
-                        receiverExtras, mActivityToken, flags)) {
+                if (!ActivityTaskManager.getService()
+                        .requestAutofillData(
+                                mPccAssistReceiver, receiverExtras, mActivityToken, flags)) {
                     Slog.w(TAG, "failed to request autofill data for " + mActivityToken);
                 }
             } finally {
@@ -1483,8 +1540,9 @@
             receiverExtras.putInt(EXTRA_REQUEST_ID, requestId);
             final long identity = Binder.clearCallingIdentity();
             try {
-                if (!ActivityTaskManager.getService().requestAutofillData(mAssistReceiver,
-                        receiverExtras, mActivityToken, flags)) {
+                if (!ActivityTaskManager.getService()
+                        .requestAutofillData(
+                                mAssistReceiver, receiverExtras, mActivityToken, flags)) {
                     Slog.w(TAG, "failed to request autofill data for " + mActivityToken);
                 }
             } finally {
@@ -1495,13 +1553,27 @@
         }
     }
 
-    Session(@NonNull AutofillManagerServiceImpl service, @NonNull AutoFillUI ui,
-            @NonNull Context context, @NonNull Handler handler, int userId, @NonNull Object lock,
-            int sessionId, int taskId, int uid, @NonNull IBinder activityToken,
-            @NonNull IBinder client, boolean hasCallback, @NonNull LocalLog uiLatencyHistory,
-            @NonNull LocalLog wtfHistory, @Nullable ComponentName serviceComponentName,
-            @NonNull ComponentName componentName, boolean compatMode,
-            boolean bindInstantServiceAllowed, boolean forAugmentedAutofillOnly, int flags,
+    Session(
+            @NonNull AutofillManagerServiceImpl service,
+            @NonNull AutoFillUI ui,
+            @NonNull Context context,
+            @NonNull Handler handler,
+            int userId,
+            @NonNull Object lock,
+            int sessionId,
+            int taskId,
+            int uid,
+            @NonNull IBinder activityToken,
+            @NonNull IBinder client,
+            boolean hasCallback,
+            @NonNull LocalLog uiLatencyHistory,
+            @NonNull LocalLog wtfHistory,
+            @Nullable ComponentName serviceComponentName,
+            @NonNull ComponentName componentName,
+            boolean compatMode,
+            boolean bindInstantServiceAllowed,
+            boolean forAugmentedAutofillOnly,
+            int flags,
             @NonNull InputMethodManagerInternal inputMethodManagerInternal,
             boolean isPrimaryCredential) {
         if (sessionId < 0) {
@@ -1533,22 +1605,40 @@
             primaryServiceComponentName = serviceComponentName;
             secondaryServiceComponentName = mCredentialAutofillService;
         }
-        Slog.v(TAG, "Primary service component name: " + primaryServiceComponentName
-                + ", secondary service component name: " + secondaryServiceComponentName);
+        Slog.v(
+                TAG,
+                "Primary service component name: "
+                        + primaryServiceComponentName
+                        + ", secondary service component name: "
+                        + secondaryServiceComponentName);
 
-        mRemoteFillService = primaryServiceComponentName == null ? null
-                : new RemoteFillService(context, primaryServiceComponentName, userId, this,
-                        bindInstantServiceAllowed, mCredentialAutofillService);
-        mSecondaryProviderHandler = secondaryServiceComponentName == null ? null
-                : new SecondaryProviderHandler(context, userId, bindInstantServiceAllowed,
-                this::onSecondaryFillResponse, secondaryServiceComponentName,
-                        mCredentialAutofillService);
+        mRemoteFillService =
+                primaryServiceComponentName == null
+                        ? null
+                        : new RemoteFillService(
+                                context,
+                                primaryServiceComponentName,
+                                userId,
+                                this,
+                                bindInstantServiceAllowed,
+                                mCredentialAutofillService);
+        mSecondaryProviderHandler =
+                secondaryServiceComponentName == null
+                        ? null
+                        : new SecondaryProviderHandler(
+                                context,
+                                userId,
+                                bindInstantServiceAllowed,
+                                this::onSecondaryFillResponse,
+                                secondaryServiceComponentName,
+                                mCredentialAutofillService);
         mActivityToken = activityToken;
         mHasCallback = hasCallback;
         mUiLatencyHistory = uiLatencyHistory;
         mWtfHistory = wtfHistory;
-        int displayId = LocalServices.getService(ActivityTaskManagerInternal.class)
-                .getDisplayId(activityToken);
+        int displayId =
+                LocalServices.getService(ActivityTaskManagerInternal.class)
+                        .getDisplayId(activityToken);
         mContext = Helper.getDisplayContext(context, displayId);
         mComponentName = componentName;
         mCompatMode = compatMode;
@@ -1557,8 +1647,9 @@
         mStartTime = SystemClock.elapsedRealtime();
         mLatencyBaseTime = mStartTime;
         mRequestCount = 0;
-        mPresentationStatsEventLogger = PresentationStatsEventLogger.createPresentationLog(
-                sessionId, uid, mLatencyBaseTime);
+        mPresentationStatsEventLogger =
+                PresentationStatsEventLogger.createPresentationLog(
+                        sessionId, uid, mLatencyBaseTime);
         mFillRequestEventLogger = FillRequestEventLogger.forSessionId(sessionId);
         mFillResponseEventLogger = FillResponseEventLogger.forSessionId(sessionId);
         mSessionCommittedEventLogger = SessionCommittedEventLogger.forSessionId(sessionId);
@@ -1574,33 +1665,39 @@
             setClientLocked(client);
         }
 
-        mInlineSessionController = new AutofillInlineSessionController(inputMethodManagerInternal,
-                userId, componentName, handler, mLock,
-                new InlineFillUi.InlineUiEventCallback() {
-                    @Override
-                    public void notifyInlineUiShown(AutofillId autofillId) {
-                        notifyFillUiShown(autofillId);
-                    }
+        mInlineSessionController =
+                new AutofillInlineSessionController(
+                        inputMethodManagerInternal,
+                        userId,
+                        componentName,
+                        handler,
+                        mLock,
+                        new InlineFillUi.InlineUiEventCallback() {
+                            @Override
+                            public void notifyInlineUiShown(AutofillId autofillId) {
+                                notifyFillUiShown(autofillId);
+                            }
 
-                    @Override
-                    public void notifyInlineUiHidden(AutofillId autofillId) {
-                        notifyFillUiHidden(autofillId);
-                    }
-                });
+                            @Override
+                            public void notifyInlineUiHidden(AutofillId autofillId) {
+                                notifyFillUiHidden(autofillId);
+                            }
+                        });
 
-        mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_SESSION_STARTED)
-                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_FLAGS, flags));
+        mMetricsLogger.write(
+                newLogMaker(MetricsEvent.AUTOFILL_SESSION_STARTED)
+                        .addTaggedData(MetricsEvent.FIELD_AUTOFILL_FLAGS, flags));
         mLogViewEntered = false;
     }
 
     private ComponentName getCredentialAutofillService(Context context) {
         ComponentName componentName = null;
-        String credentialManagerAutofillCompName = context.getResources().getString(
-                R.string.config_defaultCredentialManagerAutofillService);
+        String credentialManagerAutofillCompName =
+                context.getResources()
+                        .getString(R.string.config_defaultCredentialManagerAutofillService);
         if (credentialManagerAutofillCompName != null
                 && !credentialManagerAutofillCompName.isEmpty()) {
-            componentName = ComponentName.unflattenFromString(
-                    credentialManagerAutofillCompName);
+            componentName = ComponentName.unflattenFromString(credentialManagerAutofillCompName);
         }
         if (componentName == null) {
             Slog.w(TAG, "Invalid CredentialAutofillService");
@@ -1614,7 +1711,8 @@
      * @return The activity token
      */
     @GuardedBy("mLock")
-    @NonNull IBinder getActivityTokenLocked() {
+    @NonNull
+    IBinder getActivityTokenLocked() {
         return mActivityToken;
     }
 
@@ -1627,8 +1725,11 @@
     void switchActivity(@NonNull IBinder newActivity, @NonNull IBinder newClient) {
         synchronized (mLock) {
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#switchActivity() rejected - session: "
-                        + id + " destroyed");
+                Slog.w(
+                        TAG,
+                        "Call to Session#switchActivity() rejected - session: "
+                                + id
+                                + " destroyed");
                 return;
             }
             mActivityToken = newActivity;
@@ -1643,17 +1744,22 @@
     private void setClientLocked(@NonNull IBinder client) {
         unlinkClientVultureLocked();
         mClient = IAutoFillManagerClient.Stub.asInterface(client);
-        mClientVulture = () -> {
-            synchronized (mLock) {
-                Slog.d(TAG, "handling death of " + mActivityToken + " when saving="
-                        + mSessionFlags.mShowingSaveUi);
-                if (mSessionFlags.mShowingSaveUi) {
-                    mUi.hideFillUi(this);
-                } else {
-                    mUi.destroyAll(mPendingSaveUi, this, false);
-                }
-            }
-        };
+        mClientVulture =
+                () -> {
+                    synchronized (mLock) {
+                        Slog.d(
+                                TAG,
+                                "handling death of "
+                                        + mActivityToken
+                                        + " when saving="
+                                        + mSessionFlags.mShowingSaveUi);
+                        if (mSessionFlags.mShowingSaveUi) {
+                            mUi.hideFillUi(this);
+                        } else {
+                            mUi.destroyAll(mPendingSaveUi, this, false);
+                        }
+                    }
+                };
         try {
             mClient.asBinder().linkToDeath(mClientVulture, 0);
         } catch (RemoteException e) {
@@ -1676,8 +1782,11 @@
     // FillServiceCallbacks
     @Override
     @SuppressWarnings("GuardedBy")
-    public void onFillRequestSuccess(int requestId, @Nullable FillResponse response,
-            @NonNull String servicePackageName, int requestFlags) {
+    public void onFillRequestSuccess(
+            int requestId,
+            @Nullable FillResponse response,
+            @NonNull String servicePackageName,
+            int requestFlags) {
         final AutofillId[] fieldClassificationIds;
 
         final LogMaker requestLog;
@@ -1701,8 +1810,11 @@
                     getDetectionPreferenceForLogging());
 
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#onFillRequestSuccess() rejected - session: "
-                        + id + " destroyed");
+                Slog.w(
+                        TAG,
+                        "Call to Session#onFillRequestSuccess() rejected - session: "
+                                + id
+                                + " destroyed");
                 mFillResponseEventLogger.maybeSetResponseStatus(RESPONSE_STATUS_SESSION_DESTROYED);
                 mFillResponseEventLogger.logAndEndEvent();
                 return;
@@ -1713,8 +1825,11 @@
                 // saveUi gets closed, the session will be destroyed and AutofillManager will reset
                 // its state. Processing the fill request will result in a great chance of corrupt
                 // state in Autofill.
-                Slog.w(TAG, "Call to Session#onFillRequestSuccess() rejected - session: "
-                        + id + " is showing saveUi");
+                Slog.w(
+                        TAG,
+                        "Call to Session#onFillRequestSuccess() rejected - session: "
+                                + id
+                                + " is showing saveUi");
                 mFillResponseEventLogger.maybeSetResponseStatus(RESPONSE_STATUS_SESSION_DESTROYED);
                 mFillResponseEventLogger.logAndEndEvent();
                 return;
@@ -1760,22 +1875,21 @@
             }
         }
 
-
         final long disableDuration = response.getDisableDuration();
         final boolean autofillDisabled = disableDuration > 0;
         if (autofillDisabled) {
             final int flags = response.getFlags();
             final boolean disableActivityOnly =
                     (flags & FillResponse.FLAG_DISABLE_ACTIVITY_ONLY) != 0;
-            notifyDisableAutofillToClient(disableDuration,
-                    disableActivityOnly ? mComponentName : null);
+            notifyDisableAutofillToClient(
+                    disableDuration, disableActivityOnly ? mComponentName : null);
 
             if (disableActivityOnly) {
-                mService.disableAutofillForActivity(mComponentName, disableDuration,
-                        id, mCompatMode);
+                mService.disableAutofillForActivity(
+                        mComponentName, disableDuration, id, mCompatMode);
             } else {
-                mService.disableAutofillForApp(mComponentName.getPackageName(), disableDuration,
-                        id, mCompatMode);
+                mService.disableAutofillForApp(
+                        mComponentName.getPackageName(), disableDuration, id, mCompatMode);
             }
 
             synchronized (mLock) {
@@ -1786,17 +1900,22 @@
                 if (triggerAugmentedAutofillLocked(requestFlags) != null) {
                     mSessionFlags.mAugmentedAutofillOnly = true;
                     if (sDebug) {
-                        Slog.d(TAG, "Service disabled autofill for " + mComponentName
-                                + ", but session is kept for augmented autofill only");
+                        Slog.d(
+                                TAG,
+                                "Service disabled autofill for "
+                                        + mComponentName
+                                        + ", but session is kept for augmented autofill only");
                     }
                     return;
                 }
             }
 
             if (sDebug) {
-                final StringBuilder message = new StringBuilder("Service disabled autofill for ")
+                final StringBuilder message =
+                        new StringBuilder("Service disabled autofill for ")
                                 .append(mComponentName)
-                                .append(": flags=").append(flags)
+                                .append(": flags=")
+                                .append(flags)
                                 .append(", duration=");
                 TimeUtils.formatDuration(disableDuration, message);
                 Slog.d(TAG, message.toString());
@@ -1816,8 +1935,9 @@
         }
 
         if (requestLog != null) {
-            requestLog.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS,
-                            response.getDatasets() == null ? 0 : response.getDatasets().size());
+            requestLog.addTaggedData(
+                    MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS,
+                    response.getDatasets() == null ? 0 : response.getDatasets().size());
             if (fieldClassificationIds != null) {
                 requestLog.addTaggedData(
                         MetricsEvent.FIELD_AUTOFILL_NUM_FIELD_CLASSIFICATION_IDS,
@@ -1840,10 +1960,9 @@
         }
     }
 
-
     @GuardedBy("mLock")
-    private void processResponseLockedForPcc(@NonNull FillResponse response,
-            @Nullable Bundle newClientState, int flags) {
+    private void processResponseLockedForPcc(
+            @NonNull FillResponse response, @Nullable Bundle newClientState, int flags) {
         if (DBG) {
             Slog.d(TAG, "DBG: Initial response: " + response);
         }
@@ -1851,9 +1970,7 @@
             response = getEffectiveFillResponse(response);
             if (isEmptyResponse(response)) {
                 // Treat it as a null response.
-                processNullResponseLocked(
-                        response != null ? response.getRequestId() : 0,
-                        flags);
+                processNullResponseLocked(response != null ? response.getRequestId() : 0, flags);
                 return;
             }
             if (DBG) {
@@ -1870,9 +1987,9 @@
             return ((response.getDatasets() == null || response.getDatasets().isEmpty())
                     && response.getAuthentication() == null
                     && (saveInfo == null
-                        || (ArrayUtils.isEmpty(saveInfo.getOptionalIds())
-                            && ArrayUtils.isEmpty(saveInfo.getRequiredIds())
-                            && ((saveInfo.getFlags() & SaveInfo.FLAG_DELAY_SAVE) == 0)))
+                            || (ArrayUtils.isEmpty(saveInfo.getOptionalIds())
+                                    && ArrayUtils.isEmpty(saveInfo.getRequiredIds())
+                                    && ((saveInfo.getFlags() & SaveInfo.FLAG_DELAY_SAVE) == 0)))
                     && (ArrayUtils.isEmpty(response.getFieldClassificationIds())));
         }
     }
@@ -1884,10 +2001,12 @@
         computeDatasetsForProviderAndUpdateContainer(response, autofillProviderContainer);
 
         if (DBG) {
-            Slog.d(TAG, "DBG: computeDatasetsForProviderAndUpdateContainer: "
-                    + autofillProviderContainer);
+            Slog.d(
+                    TAG,
+                    "DBG: computeDatasetsForProviderAndUpdateContainer: "
+                            + autofillProviderContainer);
         }
-        if (!mService.isPccClassificationEnabled())  {
+        if (!mService.isPccClassificationEnabled()) {
             if (sVerbose) {
                 Slog.v(TAG, "PCC classification is disabled");
             }
@@ -1897,10 +2016,14 @@
             if (mClassificationState.mState != ClassificationState.STATE_RESPONSE
                     || mClassificationState.mLastFieldClassificationResponse == null) {
                 if (sVerbose) {
-                    Slog.v(TAG, "PCC classification no last response:"
-                            + (mClassificationState.mLastFieldClassificationResponse == null)
-                            +   " ,ineligible state="
-                            + (mClassificationState.mState != ClassificationState.STATE_RESPONSE));
+                    Slog.v(
+                            TAG,
+                            "PCC classification no last response:"
+                                    + (mClassificationState.mLastFieldClassificationResponse
+                                            == null)
+                                    + " ,ineligible state="
+                                    + (mClassificationState.mState
+                                            != ClassificationState.STATE_RESPONSE));
                 }
                 return createShallowCopy(response, autofillProviderContainer);
             }
@@ -1966,8 +2089,11 @@
             mFillResponseEventLogger.maybeSetLatencyFillResponseReceivedMillis(
                     (int) (fillRequestReceivedRelativeTimestamp));
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#onSecondaryFillResponse() rejected - session: "
-                        + id + " destroyed");
+                Slog.w(
+                        TAG,
+                        "Call to Session#onSecondaryFillResponse() rejected - session: "
+                                + id
+                                + " destroyed");
                 mFillResponseEventLogger.maybeSetResponseStatus(RESPONSE_STATUS_SESSION_DESTROYED);
                 mFillResponseEventLogger.logAndEndEvent();
                 return;
@@ -1981,7 +2107,10 @@
                 mSecondaryResponses = new SparseArray<>(2);
             }
             mSecondaryResponses.put(fillResponse.getRequestId(), fillResponse);
-            setViewStatesLocked(fillResponse, ViewState.STATE_FILLABLE, /* clearResponse= */ false,
+            setViewStatesLocked(
+                    fillResponse,
+                    ViewState.STATE_FILLABLE,
+                    /* clearResponse= */ false,
                     /* isPrimary= */ false);
 
             // Updates the UI, if necessary.
@@ -1997,16 +2126,15 @@
     private FillResponse createShallowCopy(
             FillResponse response, DatasetComputationContainer container) {
         return FillResponse.shallowCopy(
-                response,
-                new ArrayList<>(container.mDatasets),
-                getEligibleSaveInfo(response));
+                response, new ArrayList<>(container.mDatasets), getEligibleSaveInfo(response));
     }
 
     private SaveInfo getEligibleSaveInfo(FillResponse response) {
         SaveInfo saveInfo = response.getSaveInfo();
-        if (saveInfo == null || (!ArrayUtils.isEmpty(saveInfo.getOptionalIds())
-                || !ArrayUtils.isEmpty(saveInfo.getRequiredIds())
-                || (saveInfo.getFlags() & SaveInfo.FLAG_DELAY_SAVE) != 0)) {
+        if (saveInfo == null
+                || (!ArrayUtils.isEmpty(saveInfo.getOptionalIds())
+                        || !ArrayUtils.isEmpty(saveInfo.getRequiredIds())
+                        || (saveInfo.getFlags() & SaveInfo.FLAG_DELAY_SAVE) != 0)) {
             return saveInfo;
         }
         synchronized (mLock) {
@@ -2019,12 +2147,12 @@
             ArraySet<AutofillId> ids = new ArraySet<>();
             int saveType = saveInfo.getType();
             if (saveType == SaveInfo.SAVE_DATA_TYPE_GENERIC) {
-                for (Set<AutofillId> autofillIds: hintsToAutofillIdMap.values()) {
+                for (Set<AutofillId> autofillIds : hintsToAutofillIdMap.values()) {
                     ids.addAll(autofillIds);
                 }
             } else {
                 Set<String> hints = HintsHelper.getHintsForSaveType(saveType);
-                for (Map.Entry<String, Set<AutofillId>> entry: hintsToAutofillIdMap.entrySet()) {
+                for (Map.Entry<String, Set<AutofillId>> entry : hintsToAutofillIdMap.entrySet()) {
                     String hint = entry.getKey();
                     if (hints.contains(hint)) {
                         ids.addAll(entry.getValue());
@@ -2039,9 +2167,7 @@
         }
     }
 
-    /**
-     * A private class to hold & compute datasets to be shown
-     */
+    /** A private class to hold & compute datasets to be shown */
     private static class DatasetComputationContainer {
         // List of all autofill ids that have a corresponding datasets
         Set<AutofillId> mAutofillIds = new LinkedHashSet<>();
@@ -2103,9 +2229,10 @@
     }
 
     /**
-     * Computes datasets that are eligible to be shown based on provider detections.
-     * Datasets are populated in the provided container for them to be later merged with the
-     * PCC eligible datasets based on preference strategy.
+     * Computes datasets that are eligible to be shown based on provider detections. Datasets are
+     * populated in the provided container for them to be later merged with the PCC eligible
+     * datasets based on preference strategy.
+     *
      * @param response
      * @param container
      */
@@ -2210,9 +2337,10 @@
     }
 
     /**
-     * Computes datasets that are eligible to be shown based on PCC detections.
-     * Datasets are populated in the provided container for them to be later merged with the
-     * provider eligible datasets based on preference strategy.
+     * Computes datasets that are eligible to be shown based on PCC detections. Datasets are
+     * populated in the provided container for them to be later merged with the provider eligible
+     * datasets based on preference strategy.
+     *
      * @param response
      * @param container
      */
@@ -2267,14 +2395,21 @@
                         // For that, there has to be a datatype detected by PCC, and the dataset
                         // for that datatype provided by the provider.
                         AutofillId autofillId = dataset.getFieldIds().get(j);
-                        if (!mClassificationState.mClassificationCombinedHintsMap
-                                .containsKey(autofillId)) {
+                        if (!mClassificationState.mClassificationCombinedHintsMap.containsKey(
+                                autofillId)) {
                             additionalEligibleAutofillIds.add(autofillId);
                             additionalDatasetAutofillIds.add(autofillId);
                             // For each of the field, copy over values.
-                            copyFieldsFromDataset(dataset, j, autofillId, fieldIds, fieldValues,
-                                    fieldPresentations, fieldDialogPresentations,
-                                    fieldInlinePresentations, fieldInlineTooltipPresentations,
+                            copyFieldsFromDataset(
+                                    dataset,
+                                    j,
+                                    autofillId,
+                                    fieldIds,
+                                    fieldValues,
+                                    fieldPresentations,
+                                    fieldDialogPresentations,
+                                    fieldInlinePresentations,
+                                    fieldInlineTooltipPresentations,
                                     fieldFilters);
                         }
                         continue;
@@ -2292,9 +2427,16 @@
                             eligibleAutofillIds.add(autofillId);
                             datasetAutofillIds.add(autofillId);
                             // For each of the field, copy over values.
-                            copyFieldsFromDataset(dataset, j, autofillId, fieldIds, fieldValues,
-                                    fieldPresentations, fieldDialogPresentations,
-                                    fieldInlinePresentations, fieldInlineTooltipPresentations,
+                            copyFieldsFromDataset(
+                                    dataset,
+                                    j,
+                                    autofillId,
+                                    fieldIds,
+                                    fieldValues,
+                                    fieldPresentations,
+                                    fieldDialogPresentations,
+                                    fieldInlinePresentations,
+                                    fieldInlineTooltipPresentations,
                                     fieldFilters);
                         }
                     }
@@ -2364,8 +2506,7 @@
         fieldPresentations.add(dataset.getFieldPresentation(index));
         fieldDialogPresentations.add(dataset.getFieldDialogPresentation(index));
         fieldInlinePresentations.add(dataset.getFieldInlinePresentation(index));
-        fieldInlineTooltipPresentations.add(
-                dataset.getFieldInlineTooltipPresentation(index));
+        fieldInlineTooltipPresentations.add(dataset.getFieldInlineTooltipPresentation(index));
         fieldFilters.add(dataset.getFilter(index));
     }
 
@@ -2395,16 +2536,22 @@
 
             unregisterDelayedFillBroadcastLocked();
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#onFillRequestFailureOrTimeout(req=" + requestId
-                        + ") rejected - session: " + id + " destroyed");
+                Slog.w(
+                        TAG,
+                        "Call to Session#onFillRequestFailureOrTimeout(req="
+                                + requestId
+                                + ") rejected - session: "
+                                + id
+                                + " destroyed");
                 mFillResponseEventLogger.maybeSetResponseStatus(RESPONSE_STATUS_SESSION_DESTROYED);
                 mFillResponseEventLogger.logAndEndEvent();
 
                 return;
             }
             if (sDebug) {
-                Slog.d(TAG, "finishing session due to service "
-                        + (timedOut ? "timeout" : "failure"));
+                Slog.d(
+                        TAG,
+                        "finishing session due to service " + (timedOut ? "timeout" : "failure"));
             }
             mService.resetLastResponse();
             mLastFillDialogTriggerIds = null;
@@ -2418,12 +2565,16 @@
                 final int targetSdk = mService.getTargedSdkLocked();
                 if (targetSdk >= Build.VERSION_CODES.Q) {
                     showMessage = false;
-                    Slog.w(TAG, "onFillRequestFailureOrTimeout(): not showing '" + message
-                            + "' because service's targetting API " + targetSdk);
+                    Slog.w(
+                            TAG,
+                            "onFillRequestFailureOrTimeout(): not showing '"
+                                    + message
+                                    + "' because service's targeting API "
+                                    + targetSdk);
                 }
                 if (message != null) {
-                    requestLog.addTaggedData(MetricsEvent.FIELD_AUTOFILL_TEXT_LEN,
-                            message.length());
+                    requestLog.addTaggedData(
+                            MetricsEvent.FIELD_AUTOFILL_TEXT_LEN, message.length());
                 }
             }
 
@@ -2445,8 +2596,8 @@
             mFillResponseEventLogger.maybeSetLatencyResponseProcessingMillis();
             mFillResponseEventLogger.logAndEndEvent();
         }
-        notifyUnavailableToClient(AutofillManager.STATE_UNKNOWN_FAILED,
-                /* autofillableIds= */ null);
+        notifyUnavailableToClient(
+                AutofillManager.STATE_UNKNOWN_FAILED, /* autofillableIds= */ null);
         if (showMessage) {
             getUiForShowing().showError(message, this);
         }
@@ -2455,8 +2606,8 @@
 
     // FillServiceCallbacks
     @Override
-    public void onSaveRequestSuccess(@NonNull String servicePackageName,
-            @Nullable IntentSender intentSender) {
+    public void onSaveRequestSuccess(
+            @NonNull String servicePackageName, @Nullable IntentSender intentSender) {
         synchronized (mLock) {
             mSessionFlags.mShowingSaveUi = false;
             // Log onSaveRequest result.
@@ -2464,16 +2615,22 @@
             mSaveEventLogger.maybeSetLatencySaveFinishMillis();
             mSaveEventLogger.logAndEndEvent();
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#onSaveRequestSuccess() rejected - session: "
-                        + id + " destroyed");
+                Slog.w(
+                        TAG,
+                        "Call to Session#onSaveRequestSuccess() rejected - session: "
+                                + id
+                                + " destroyed");
                 return;
             }
         }
-        LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_DATA_SAVE_REQUEST, servicePackageName)
-                .setType(intentSender == null ? MetricsEvent.TYPE_SUCCESS : MetricsEvent.TYPE_OPEN);
+        LogMaker log =
+                newLogMaker(MetricsEvent.AUTOFILL_DATA_SAVE_REQUEST, servicePackageName)
+                        .setType(
+                                intentSender == null
+                                        ? MetricsEvent.TYPE_SUCCESS
+                                        : MetricsEvent.TYPE_OPEN);
         mMetricsLogger.write(log);
 
-
         if (intentSender != null) {
             if (sDebug) Slog.d(TAG, "Starting intent sender on save()");
             startIntentSenderAndFinishSession(intentSender);
@@ -2485,8 +2642,8 @@
 
     // FillServiceCallbacks
     @Override
-    public void onSaveRequestFailure(@Nullable CharSequence message,
-            @NonNull String servicePackageName) {
+    public void onSaveRequestFailure(
+            @Nullable CharSequence message, @NonNull String servicePackageName) {
         boolean showMessage = !TextUtils.isEmpty(message);
 
         synchronized (mLock) {
@@ -2495,28 +2652,34 @@
             mSaveEventLogger.maybeSetLatencySaveFinishMillis();
             mSaveEventLogger.logAndEndEvent();
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#onSaveRequestFailure() rejected - session: "
-                        + id + " destroyed");
+                Slog.w(
+                        TAG,
+                        "Call to Session#onSaveRequestFailure() rejected - session: "
+                                + id
+                                + " destroyed");
                 return;
             }
             if (showMessage) {
                 final int targetSdk = mService.getTargedSdkLocked();
                 if (targetSdk >= Build.VERSION_CODES.Q) {
                     showMessage = false;
-                    Slog.w(TAG, "onSaveRequestFailure(): not showing '" + message
-                            + "' because service's targetting API " + targetSdk);
+                    Slog.w(
+                            TAG,
+                            "onSaveRequestFailure(): not showing '"
+                                    + message
+                                    + "' because service's targeting API "
+                                    + targetSdk);
                 }
             }
         }
         final LogMaker log =
                 newLogMaker(MetricsEvent.AUTOFILL_DATA_SAVE_REQUEST, servicePackageName)
-                .setType(MetricsEvent.TYPE_FAILURE);
+                        .setType(MetricsEvent.TYPE_FAILURE);
         if (message != null) {
             log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_TEXT_LEN, message.length());
         }
         mMetricsLogger.write(log);
 
-
         if (showMessage) {
             getUiForShowing().showError(message, this);
         }
@@ -2525,8 +2688,8 @@
 
     // FillServiceCallbacks
     @Override
-    public void onConvertCredentialRequestSuccess(@NonNull ConvertCredentialResponse
-            convertCredentialResponse) {
+    public void onConvertCredentialRequestSuccess(
+            @NonNull ConvertCredentialResponse convertCredentialResponse) {
         Dataset dataset = convertCredentialResponse.getDataset();
         Bundle clientState = convertCredentialResponse.getClientState();
         if (dataset != null) {
@@ -2534,15 +2697,18 @@
             if (clientState != null) {
                 requestId = clientState.getInt(EXTRA_AUTOFILL_REQUEST_ID);
             } else {
-                Slog.e(TAG, "onConvertCredentialRequestSuccess(): client state is null, this "
-                        + "would cause loss in logging.");
+                Slog.e(
+                        TAG,
+                        "onConvertCredentialRequestSuccess(): client state is null, this "
+                                + "would cause loss in logging.");
             }
             // TODO: Add autofill related logging; consider whether to log the index
-            fill(requestId, /* datasetIndex=*/ -1, dataset, UI_TYPE_CREDMAN_BOTTOM_SHEET);
+            fill(requestId, /* datasetIndex= */ -1, dataset, UI_TYPE_CREDMAN_BOTTOM_SHEET);
         } else {
             // TODO: Add logging to log this error case
-            Slog.e(TAG, "onConvertCredentialRequestSuccess(): dataset inside response is "
-                    + "null");
+            Slog.e(
+                    TAG,
+                    "onConvertCredentialRequestSuccess(): dataset inside response is " + "null");
         }
     }
 
@@ -2550,11 +2716,11 @@
      * Gets the {@link FillContext} for a request.
      *
      * @param requestId The id of the request
-     *
      * @return The context or {@code null} if there is no context
      */
     @GuardedBy("mLock")
-    @Nullable private FillContext getFillContextByRequestIdLocked(int requestId) {
+    @Nullable
+    private FillContext getFillContextByRequestIdLocked(int requestId) {
         if (mContexts == null) {
             return null;
         }
@@ -2582,19 +2748,26 @@
 
     // AutoFillUiCallback
     @Override
-    public void authenticate(int requestId, int datasetIndex, IntentSender intent, Bundle extras,
-            int uiType) {
+    public void authenticate(
+            int requestId, int datasetIndex, IntentSender intent, Bundle extras, int uiType) {
         if (sDebug) {
-            Slog.d(TAG, "authenticate(): requestId=" + requestId + "; datasetIdx=" + datasetIndex
-                    + "; intentSender=" + intent);
+            Slog.d(
+                    TAG,
+                    "authenticate(): requestId="
+                            + requestId
+                            + "; datasetIdx="
+                            + datasetIndex
+                            + "; intentSender="
+                            + intent);
         }
         final Intent fillInIntent;
         synchronized (mLock) {
             mPresentationStatsEventLogger.maybeSetAuthenticationType(
-                AUTHENTICATION_TYPE_FULL_AUTHENTICATION);
+                    AUTHENTICATION_TYPE_FULL_AUTHENTICATION);
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#authenticate() rejected - session: "
-                        + id + " destroyed");
+                Slog.w(
+                        TAG,
+                        "Call to Session#authenticate() rejected - session: " + id + " destroyed");
                 return;
             }
             fillInIntent = createAuthFillInIntentLocked(requestId, extras);
@@ -2607,10 +2780,14 @@
         mService.setAuthenticationSelected(id, mClientState, uiType);
 
         final int authenticationId = AutofillManager.makeAuthenticationId(requestId, datasetIndex);
-        mHandler.sendMessage(obtainMessage(
-                Session::startAuthentication,
-                this, authenticationId, intent, fillInIntent,
-                /* authenticateInline= */ uiType == UI_TYPE_INLINE));
+        mHandler.sendMessage(
+                obtainMessage(
+                        Session::startAuthentication,
+                        this,
+                        authenticationId,
+                        intent,
+                        fillInIntent,
+                        /* authenticateInline= */ uiType == UI_TYPE_INLINE));
     }
 
     // AutoFillUiCallback
@@ -2618,14 +2795,13 @@
     public void fill(int requestId, int datasetIndex, Dataset dataset, int uiType) {
         synchronized (mLock) {
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#fill() rejected - session: "
-                        + id + " destroyed");
+                Slog.w(TAG, "Call to Session#fill() rejected - session: " + id + " destroyed");
                 return;
             }
         }
-        mHandler.sendMessage(obtainMessage(
-                Session::autoFill,
-                this, requestId, datasetIndex, dataset, true, uiType));
+        mHandler.sendMessage(
+                obtainMessage(
+                        Session::autoFill, this, requestId, datasetIndex, dataset, true, uiType));
     }
 
     // AutoFillUiCallback
@@ -2633,15 +2809,13 @@
     public void save() {
         synchronized (mLock) {
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#save() rejected - session: "
-                        + id + " destroyed");
+                Slog.w(TAG, "Call to Session#save() rejected - session: " + id + " destroyed");
                 return;
             }
             mSaveEventLogger.maybeSetLatencySaveRequestMillis();
         }
-        mHandler.sendMessage(obtainMessage(
-                AutofillManagerServiceImpl::handleSessionSave,
-                mService, this));
+        mHandler.sendMessage(
+                obtainMessage(AutofillManagerServiceImpl::handleSessionSave, mService, this));
     }
 
     // AutoFillUiCallback
@@ -2650,13 +2824,13 @@
         synchronized (mLock) {
             mSessionFlags.mShowingSaveUi = false;
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#cancelSave() rejected - session: "
-                        + id + " destroyed");
+                Slog.w(
+                        TAG,
+                        "Call to Session#cancelSave() rejected - session: " + id + " destroyed");
                 return;
             }
         }
-        mHandler.sendMessage(obtainMessage(
-                Session::removeFromService, this));
+        mHandler.sendMessage(obtainMessage(Session::removeFromService, this));
     }
 
     // AutofillUiCallback
@@ -2692,26 +2866,34 @@
 
     // AutoFillUiCallback
     @Override
-    public void requestShowFillUi(AutofillId id, int width, int height,
-            IAutofillWindowPresenter presenter) {
+    public void requestShowFillUi(
+            AutofillId id, int width, int height, IAutofillWindowPresenter presenter) {
         synchronized (mLock) {
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#requestShowFillUi() rejected - session: "
-                        + id + " destroyed");
+                Slog.w(
+                        TAG,
+                        "Call to Session#requestShowFillUi() rejected - session: "
+                                + id
+                                + " destroyed");
                 return;
             }
             if (id.equals(mCurrentViewId)) {
                 try {
                     final ViewState view = mViewStates.get(id);
-                    mClient.requestShowFillUi(this.id, id, width, height, view.getVirtualBounds(),
-                            presenter);
+                    mClient.requestShowFillUi(
+                            this.id, id, width, height, view.getVirtualBounds(), presenter);
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Error requesting to show fill UI", e);
                 }
             } else {
                 if (sDebug) {
-                    Slog.d(TAG, "Do not show full UI on " + id + " as it is not the current view ("
-                            + mCurrentViewId + ") anymore");
+                    Slog.d(
+                            TAG,
+                            "Do not show full UI on "
+                                    + id
+                                    + " as it is not the current view ("
+                                    + mCurrentViewId
+                                    + ") anymore");
                 }
             }
         }
@@ -2722,8 +2904,11 @@
     public void dispatchUnhandledKey(AutofillId id, KeyEvent keyEvent) {
         synchronized (mLock) {
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#dispatchUnhandledKey() rejected - session: "
-                        + id + " destroyed");
+                Slog.w(
+                        TAG,
+                        "Call to Session#dispatchUnhandledKey() rejected - session: "
+                                + id
+                                + " destroyed");
                 return;
             }
             if (id.equals(mCurrentViewId)) {
@@ -2733,8 +2918,13 @@
                     Slog.e(TAG, "Error requesting to dispatch unhandled key", e);
                 }
             } else {
-                Slog.w(TAG, "Do not dispatch unhandled key on " + id
-                        + " as it is not the current view (" + mCurrentViewId + ") anymore");
+                Slog.w(
+                        TAG,
+                        "Do not dispatch unhandled key on "
+                                + id
+                                + " as it is not the current view ("
+                                + mCurrentViewId
+                                + ") anymore");
             }
         }
     }
@@ -2790,17 +2980,19 @@
     public void startIntentSender(IntentSender intentSender, Intent intent) {
         synchronized (mLock) {
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#startIntentSender() rejected - session: "
-                        + id + " destroyed");
+                Slog.w(
+                        TAG,
+                        "Call to Session#startIntentSender() rejected - session: "
+                                + id
+                                + " destroyed");
                 return;
             }
             if (intent == null) {
                 removeFromServiceLocked();
             }
         }
-        mHandler.sendMessage(obtainMessage(
-                Session::doStartIntentSender,
-                this, intentSender, intent));
+        mHandler.sendMessage(
+                obtainMessage(Session::doStartIntentSender, this, intentSender, intent));
     }
 
     // AutoFillUiCallback
@@ -2865,13 +3057,17 @@
     @GuardedBy("mLock")
     void setAuthenticationResultLocked(Bundle data, int authenticationId) {
         if (mDestroyed) {
-            Slog.w(TAG, "Call to Session#setAuthenticationResultLocked() rejected - session: "
-                    + id + " destroyed");
+            Slog.w(
+                    TAG,
+                    "Call to Session#setAuthenticationResultLocked() rejected - session: "
+                            + id
+                            + " destroyed");
             return;
         }
         if (sDebug) {
-            Slog.d(TAG, "setAuthenticationResultLocked(): id= " + authenticationId
-                    + ", data=" + data);
+            Slog.d(
+                    TAG,
+                    "setAuthenticationResultLocked(): id= " + authenticationId + ", data=" + data);
         }
         final int requestId = AutofillManager.getRequestIdFromAuthenticationId(authenticationId);
         if (requestId == AUGMENTED_AUTOFILL_REQUEST_ID) {
@@ -2890,9 +3086,10 @@
             removeFromService();
             return;
         }
-        final FillResponse authenticatedResponse = mRequestId.isSecondaryProvider(requestId)
-                ? mSecondaryResponses.get(requestId)
-                : mResponses.get(requestId);
+        final FillResponse authenticatedResponse =
+                mRequestId.isSecondaryProvider(requestId)
+                        ? mSecondaryResponses.get(requestId)
+                        : mResponses.get(requestId);
         if (authenticatedResponse == null || data == null) {
             Slog.w(TAG, "no authenticated response");
             mPresentationStatsEventLogger.maybeSetAuthenticationResult(
@@ -2902,8 +3099,7 @@
             return;
         }
 
-        final int datasetIdx = AutofillManager.getDatasetIdFromAuthenticationId(
-                authenticationId);
+        final int datasetIdx = AutofillManager.getDatasetIdFromAuthenticationId(authenticationId);
         Dataset dataset = null;
         // Authenticated a dataset - reset view state regardless if we got a response or a dataset
         if (datasetIdx != AutofillManager.AUTHENTICATION_ID_DATASET_ID_UNDEFINED) {
@@ -2922,33 +3118,45 @@
         mSessionFlags.mExpiredResponse = false;
 
         final Parcelable result = data.getParcelable(AutofillManager.EXTRA_AUTHENTICATION_RESULT);
-        final GetCredentialException exception = data.getSerializable(
-                CredentialProviderService.EXTRA_GET_CREDENTIAL_EXCEPTION,
-                GetCredentialException.class);
+        final GetCredentialException exception =
+                data.getSerializable(
+                        CredentialProviderService.EXTRA_GET_CREDENTIAL_EXCEPTION,
+                        GetCredentialException.class);
 
         final Bundle newClientState = data.getBundle(AutofillManager.EXTRA_CLIENT_STATE);
         if (sDebug) {
-            Slog.d(TAG, "setAuthenticationResultLocked(): result=" + result
-                    + ", clientState=" + newClientState + ", authenticationId=" + authenticationId);
+            Slog.d(
+                    TAG,
+                    "setAuthenticationResultLocked(): result="
+                            + result
+                            + ", clientState="
+                            + newClientState
+                            + ", authenticationId="
+                            + authenticationId);
         }
-        if (Flags.autofillCredmanDevIntegration() && exception != null
+        if (Flags.autofillCredmanDevIntegration()
+                && exception != null
                 && !exception.getType().equals(GetCredentialException.TYPE_USER_CANCELED)) {
             if (dataset != null && dataset.getFieldIds().size() == 1) {
                 if (sDebug) {
-                    Slog.d(TAG, "setAuthenticationResultLocked(): result returns with"
-                            + "Credential Manager Exception");
+                    Slog.d(
+                            TAG,
+                            "setAuthenticationResultLocked(): result returns with"
+                                    + "Credential Manager Exception");
                 }
                 AutofillId autofillId = dataset.getFieldIds().get(0);
-                sendCredentialManagerResponseToApp(/*response=*/ null,
-                        (GetCredentialException) exception, autofillId);
+                sendCredentialManagerResponseToApp(
+                        /* response= */ null, (GetCredentialException) exception, autofillId);
             }
             return;
         }
 
         if (result instanceof FillResponse) {
             if (sDebug) {
-                Slog.d(TAG, "setAuthenticationResultLocked(): received FillResponse from"
-                        + " authentication flow");
+                Slog.d(
+                        TAG,
+                        "setAuthenticationResultLocked(): received FillResponse from"
+                                + " authentication flow");
             }
             logAuthenticationStatusLocked(requestId, MetricsEvent.AUTOFILL_AUTHENTICATED);
             mPresentationStatsEventLogger.maybeSetAuthenticationResult(
@@ -2963,33 +3171,40 @@
                 if (dataset != null && dataset.getFieldIds().size() == 1) {
                     AutofillId autofillId = dataset.getFieldIds().get(0);
                     if (sDebug) {
-                        Slog.d(TAG, "Received GetCredentialResponse from authentication flow,"
-                                + "for autofillId: " + autofillId);
+                        Slog.d(
+                                TAG,
+                                "Received GetCredentialResponse from authentication flow,"
+                                        + "for autofillId: "
+                                        + autofillId);
                     }
-                    sendCredentialManagerResponseToApp(response,
-                            /*exception=*/ null, autofillId);
+                    sendCredentialManagerResponseToApp(response, /* exception= */ null, autofillId);
                 }
             } else if (Flags.autofillCredmanIntegration()) {
-                Dataset datasetFromCredentialResponse = getDatasetFromCredentialResponse(
-                        (GetCredentialResponse) result);
+                Dataset datasetFromCredentialResponse =
+                        getDatasetFromCredentialResponse((GetCredentialResponse) result);
                 if (datasetFromCredentialResponse != null) {
-                    autoFill(requestId, datasetIdx, datasetFromCredentialResponse,
-                            false, UI_TYPE_UNKNOWN);
+                    autoFill(
+                            requestId,
+                            datasetIdx,
+                            datasetFromCredentialResponse,
+                            false,
+                            UI_TYPE_UNKNOWN);
                 }
             }
         } else if (result instanceof Dataset) {
             if (sDebug) {
-                Slog.d(TAG, "setAuthenticationResultLocked(): received Dataset from"
-                        + " authentication flow");
+                Slog.d(
+                        TAG,
+                        "setAuthenticationResultLocked(): received Dataset from"
+                                + " authentication flow");
             }
             if (datasetIdx != AutofillManager.AUTHENTICATION_ID_DATASET_ID_UNDEFINED) {
-                logAuthenticationStatusLocked(requestId,
-                        MetricsEvent.AUTOFILL_DATASET_AUTHENTICATED);
+                logAuthenticationStatusLocked(
+                        requestId, MetricsEvent.AUTOFILL_DATASET_AUTHENTICATED);
                 mPresentationStatsEventLogger.maybeSetAuthenticationResult(
                         AUTHENTICATION_RESULT_SUCCESS);
                 if (newClientState != null) {
-                    if (sDebug)
-                        Slog.d(TAG, "Updating client state from auth dataset");
+                    if (sDebug) Slog.d(TAG, "Updating client state from auth dataset");
                     mClientState = newClientState;
                 }
                 Dataset datasetFromResult = getEffectiveDatasetForAuthentication((Dataset) result);
@@ -2999,10 +3214,14 @@
                 }
                 autoFill(requestId, datasetIdx, datasetFromResult, false, UI_TYPE_UNKNOWN);
             } else {
-                Slog.w(TAG, "invalid index (" + datasetIdx + ") for authentication id "
-                        + authenticationId);
-                logAuthenticationStatusLocked(requestId,
-                        MetricsEvent.AUTOFILL_INVALID_DATASET_AUTHENTICATION);
+                Slog.w(
+                        TAG,
+                        "invalid index ("
+                                + datasetIdx
+                                + ") for authentication id "
+                                + authenticationId);
+                logAuthenticationStatusLocked(
+                        requestId, MetricsEvent.AUTOFILL_INVALID_DATASET_AUTHENTICATION);
                 mPresentationStatsEventLogger.maybeSetAuthenticationResult(
                         AUTHENTICATION_RESULT_FAILURE);
             }
@@ -3010,8 +3229,7 @@
             if (result != null) {
                 Slog.w(TAG, "service returned invalid auth type: " + result);
             }
-            logAuthenticationStatusLocked(requestId,
-                    MetricsEvent.AUTOFILL_INVALID_AUTHENTICATION);
+            logAuthenticationStatusLocked(requestId, MetricsEvent.AUTOFILL_INVALID_AUTHENTICATION);
             mPresentationStatsEventLogger.maybeSetAuthenticationResult(
                     AUTHENTICATION_RESULT_FAILURE);
             processNullResponseLocked(requestId, 0);
@@ -3036,8 +3254,10 @@
             Slog.d(TAG, "DBG: authenticated effective response: " + response);
         }
         if (response == null || response.getDatasets().size() == 0) {
-            Log.wtf(TAG, "No datasets in fill response on authentication. response = "
-                    + (response == null ? "null" : response.toString()));
+            Log.wtf(
+                    TAG,
+                    "No datasets in fill response on authentication. response = "
+                            + (response == null ? "null" : response.toString()));
             return authenticatedDataset;
         }
         List<Dataset> datasets = response.getDatasets();
@@ -3047,8 +3267,10 @@
             for (Dataset dataset : datasets) {
                 if (!dataset.getFieldIds().isEmpty()) {
                     for (int i = 0; i < dataset.getFieldIds().size(); i++) {
-                        builder.setField(dataset.getFieldIds().get(i),
-                                new Field.Builder().setValue(dataset.getFieldValues().get(i))
+                        builder.setField(
+                                dataset.getFieldIds().get(i),
+                                new Field.Builder()
+                                        .setValue(dataset.getFieldValues().get(i))
                                         .build());
                     }
                 }
@@ -3063,12 +3285,11 @@
     }
 
     /**
-     * Returns whether the dataset returned from the authentication result is ephemeral or not.
-     * See {@link AutofillManager#EXTRA_AUTHENTICATION_RESULT_EPHEMERAL_DATASET} for more
-     * information.
+     * Returns whether the dataset returned from the authentication result is ephemeral or not. See
+     * {@link AutofillManager#EXTRA_AUTHENTICATION_RESULT_EPHEMERAL_DATASET} for more information.
      */
-    private static boolean isAuthResultDatasetEphemeral(@Nullable Dataset oldDataset,
-            @NonNull Bundle authResultData) {
+    private static boolean isAuthResultDatasetEphemeral(
+            @Nullable Dataset oldDataset, @NonNull Bundle authResultData) {
         if (authResultData.containsKey(
                 AutofillManager.EXTRA_AUTHENTICATION_RESULT_EPHEMERAL_DATASET)) {
             return authResultData.getBoolean(
@@ -3079,11 +3300,11 @@
 
     /**
      * A dataset can potentially have multiple fields, and it's possible that some of the fields'
-     * has inline presentation and some don't. It's also possible that some of the fields'
-     * inline presentation is pinned and some isn't. So the concept of whether a dataset is
-     * pinned or not is ill-defined. Here we say a dataset is pinned if any of the field has a
-     * pinned inline presentation in the dataset. It's not ideal but hopefully it is sufficient
-     * for most of the cases.
+     * has inline presentation and some don't. It's also possible that some of the fields' inline
+     * presentation is pinned and some isn't. So the concept of whether a dataset is pinned or not
+     * is ill-defined. Here we say a dataset is pinned if any of the field has a pinned inline
+     * presentation in the dataset. It's not ideal but hopefully it is sufficient for most of the
+     * cases.
      */
     private static boolean isPinnedDataset(@Nullable Dataset dataset) {
         if (dataset != null && dataset.getFieldIds() != null) {
@@ -3100,16 +3321,30 @@
 
     @GuardedBy("mLock")
     void setAuthenticationResultForAugmentedAutofillLocked(Bundle data, int authId) {
-        final Dataset dataset = (data == null) ? null :
-                data.getParcelable(AutofillManager.EXTRA_AUTHENTICATION_RESULT, android.service.autofill.Dataset.class);
+        final Dataset dataset =
+                (data == null)
+                        ? null
+                        : data.getParcelable(
+                                AutofillManager.EXTRA_AUTHENTICATION_RESULT,
+                                android.service.autofill.Dataset.class);
         if (sDebug) {
-            Slog.d(TAG, "Auth result for augmented autofill: sessionId=" + id
-                    + ", authId=" + authId + ", dataset=" + dataset);
+            Slog.d(
+                    TAG,
+                    "Auth result for augmented autofill: sessionId="
+                            + id
+                            + ", authId="
+                            + authId
+                            + ", dataset="
+                            + dataset);
         }
-        final AutofillId fieldId = (dataset != null && dataset.getFieldIds().size() == 1)
-                ? dataset.getFieldIds().get(0) : null;
-        final AutofillValue value = (dataset != null && dataset.getFieldValues().size() == 1)
-                ? dataset.getFieldValues().get(0) : null;
+        final AutofillId fieldId =
+                (dataset != null && dataset.getFieldIds().size() == 1)
+                        ? dataset.getFieldIds().get(0)
+                        : null;
+        final AutofillValue value =
+                (dataset != null && dataset.getFieldValues().size() == 1)
+                        ? dataset.getFieldValues().get(0)
+                        : null;
         final ClipData content = (dataset != null) ? dataset.getFieldContent() : null;
         if (fieldId == null || (value == null && content == null)) {
             if (sDebug) {
@@ -3154,8 +3389,14 @@
 
         // Fill the value into the field.
         if (sDebug) {
-            Slog.d(TAG, "Filling after auth: fieldId=" + fieldId + ", value=" + value
-                    + ", content=" + content);
+            Slog.d(
+                    TAG,
+                    "Filling after auth: fieldId="
+                            + fieldId
+                            + ", value="
+                            + value
+                            + ", content="
+                            + content);
         }
         try {
             if (content != null) {
@@ -3164,8 +3405,15 @@
                 mClient.autofill(id, dataset.getFieldIds(), dataset.getFieldValues(), true);
             }
         } catch (RemoteException e) {
-            Slog.w(TAG, "Error filling after auth: fieldId=" + fieldId + ", value=" + value
-                    + ", content=" + content, e);
+            Slog.w(
+                    TAG,
+                    "Error filling after auth: fieldId="
+                            + fieldId
+                            + ", value="
+                            + value
+                            + ", content="
+                            + content,
+                    e);
         }
 
         // Clear the suggestions since the user already accepted one of them.
@@ -3175,8 +3423,11 @@
     @GuardedBy("mLock")
     void setHasCallbackLocked(boolean hasIt) {
         if (mDestroyed) {
-            Slog.w(TAG, "Call to Session#setHasCallbackLocked() rejected - session: "
-                    + id + " destroyed");
+            Slog.w(
+                    TAG,
+                    "Call to Session#setHasCallbackLocked() rejected - session: "
+                            + id
+                            + " destroyed");
             return;
         }
         mHasCallback = hasIt;
@@ -3185,9 +3436,8 @@
     @GuardedBy("mLock")
     @Nullable
     private FillResponse getLastResponseLocked(@Nullable String logPrefixFmt) {
-        final String logPrefix = sDebug && logPrefixFmt != null
-                ? String.format(logPrefixFmt, this.id)
-                : null;
+        final String logPrefix =
+                sDebug && logPrefixFmt != null ? String.format(logPrefixFmt, this.id) : null;
         if (mContexts == null) {
             if (logPrefix != null) Slog.d(TAG, logPrefix + ": no contexts");
             return null;
@@ -3204,16 +3454,28 @@
         final int lastResponseIdx = getLastResponseIndexLocked();
         if (lastResponseIdx < 0) {
             if (logPrefix != null) {
-                Slog.w(TAG, logPrefix + ": did not get last response. mResponses=" + mResponses
-                        + ", mViewStates=" + mViewStates);
+                Slog.w(
+                        TAG,
+                        logPrefix
+                                + ": did not get last response. mResponses="
+                                + mResponses
+                                + ", mViewStates="
+                                + mViewStates);
             }
             return null;
         }
 
         final FillResponse response = mResponses.valueAt(lastResponseIdx);
         if (sVerbose && logPrefix != null) {
-            Slog.v(TAG, logPrefix + ": mResponses=" + mResponses + ", mContexts=" + mContexts
-                    + ", mViewStates=" + mViewStates);
+            Slog.v(
+                    TAG,
+                    logPrefix
+                            + ": mResponses="
+                            + mResponses
+                            + ", mContexts="
+                            + mContexts
+                            + ", mViewStates="
+                            + mViewStates);
         }
         return response;
     }
@@ -3232,9 +3494,8 @@
     }
 
     /**
-     * Get statistic information of save info in current session. Specifically
-     *   1. how many save info the current session has.
-     *   2. How many distinct save data types current session has.
+     * Get statistic information of save info in current session. Specifically 1. how many save info
+     * the current session has. 2. How many distinct save data types current session has.
      *
      * @return SaveInfoStats returns the above two number in a SaveInfoStats object
      */
@@ -3255,12 +3516,21 @@
      */
     public void logContextCommitted() {
         if (sVerbose) {
-            Slog.v(TAG, "logContextCommitted (" + id + "): commit_reason:" + COMMIT_REASON_UNKNOWN
-                    + " no_save_reason:" + Event.NO_SAVE_UI_REASON_NONE);
+            Slog.v(
+                    TAG,
+                    "logContextCommitted ("
+                            + id
+                            + "): commit_reason:"
+                            + COMMIT_REASON_UNKNOWN
+                            + " no_save_reason:"
+                            + Event.NO_SAVE_UI_REASON_NONE);
         }
-        mHandler.sendMessage(obtainMessage(Session::handleLogContextCommitted, this,
-                Event.NO_SAVE_UI_REASON_NONE,
-                COMMIT_REASON_UNKNOWN));
+        mHandler.sendMessage(
+                obtainMessage(
+                        Session::handleLogContextCommitted,
+                        this,
+                        Event.NO_SAVE_UI_REASON_NONE,
+                        COMMIT_REASON_UNKNOWN));
         synchronized (mLock) {
             logAllEventsLocked(COMMIT_REASON_UNKNOWN);
         }
@@ -3274,16 +3544,25 @@
      * @param saveDialogNotShowReason The reason why a save dialog was not shown.
      * @param commitReason The reason why context is committed.
      */
-
     @GuardedBy("mLock")
-    public void logContextCommittedLocked(@NoSaveReason int saveDialogNotShowReason,
-            @AutofillCommitReason int commitReason) {
+    public void logContextCommittedLocked(
+            @NoSaveReason int saveDialogNotShowReason, @AutofillCommitReason int commitReason) {
         if (sVerbose) {
-            Slog.v(TAG, "logContextCommittedLocked (" + id + "): commit_reason:" + commitReason
-                    + " no_save_reason:" + saveDialogNotShowReason);
+            Slog.v(
+                    TAG,
+                    "logContextCommittedLocked ("
+                            + id
+                            + "): commit_reason:"
+                            + commitReason
+                            + " no_save_reason:"
+                            + saveDialogNotShowReason);
         }
-        mHandler.sendMessage(obtainMessage(Session::handleLogContextCommitted, this,
-                saveDialogNotShowReason, commitReason));
+        mHandler.sendMessage(
+                obtainMessage(
+                        Session::handleLogContextCommitted,
+                        this,
+                        saveDialogNotShowReason,
+                        commitReason));
 
         mSessionCommittedEventLogger.maybeSetCommitReason(commitReason);
         mSessionCommittedEventLogger.maybeSetRequestCount(mRequestCount);
@@ -3295,8 +3574,8 @@
         mSaveEventLogger.maybeSetSaveUiNotShownReason(NO_SAVE_REASON_NONE);
     }
 
-    private void handleLogContextCommitted(@NoSaveReason int saveDialogNotShowReason,
-            @AutofillCommitReason int commitReason) {
+    private void handleLogContextCommitted(
+            @NoSaveReason int saveDialogNotShowReason, @AutofillCommitReason int commitReason) {
         final FillResponse lastResponse;
         synchronized (mLock) {
             lastResponse = getLastResponseLocked("logContextCommited(%s)");
@@ -3326,31 +3605,42 @@
 
         // Sets field classification scores
         if (userData != null && fcStrategy != null) {
-            logFieldClassificationScore(fcStrategy, userData, saveDialogNotShowReason,
-                    commitReason);
+            logFieldClassificationScore(
+                    fcStrategy, userData, saveDialogNotShowReason, commitReason);
         } else {
             logContextCommitted(null, null, saveDialogNotShowReason, commitReason);
         }
     }
 
-    private void logContextCommitted(@Nullable ArrayList<AutofillId> detectedFieldIds,
+    private void logContextCommitted(
+            @Nullable ArrayList<AutofillId> detectedFieldIds,
             @Nullable ArrayList<FieldClassification> detectedFieldClassifications,
             @NoSaveReason int saveDialogNotShowReason,
             @AutofillCommitReason int commitReason) {
         synchronized (mLock) {
-            logContextCommittedLocked(detectedFieldIds, detectedFieldClassifications,
-                    saveDialogNotShowReason, commitReason);
+            logContextCommittedLocked(
+                    detectedFieldIds,
+                    detectedFieldClassifications,
+                    saveDialogNotShowReason,
+                    commitReason);
         }
     }
 
     @GuardedBy("mLock")
-    private void logContextCommittedLocked(@Nullable ArrayList<AutofillId> detectedFieldIds,
+    private void logContextCommittedLocked(
+            @Nullable ArrayList<AutofillId> detectedFieldIds,
             @Nullable ArrayList<FieldClassification> detectedFieldClassifications,
             @NoSaveReason int saveDialogNotShowReason,
             @AutofillCommitReason int commitReason) {
         if (sVerbose) {
-            Slog.v(TAG, "logContextCommittedLocked (" + id + "): commit_reason:" + commitReason
-                    + " no_save_reason:" + saveDialogNotShowReason);
+            Slog.v(
+                    TAG,
+                    "logContextCommittedLocked ("
+                            + id
+                            + "): commit_reason:"
+                            + commitReason
+                            + " no_save_reason:"
+                            + saveDialogNotShowReason);
         }
         final FillResponse lastResponse = getLastResponseLocked("logContextCommited(%s)");
         if (lastResponse == null) return;
@@ -3423,8 +3713,11 @@
                     final AutofillValue currentValue = viewState.getCurrentValue();
                     if (autofilledValue != null && autofilledValue.equals(currentValue)) {
                         if (sDebug) {
-                            Slog.d(TAG, "logContextCommitted(): ignoring changed " + viewState
-                                    + " because it has same value that was autofilled");
+                            Slog.d(
+                                    TAG,
+                                    "logContextCommitted(): ignoring changed "
+                                            + viewState
+                                            + " because it has same value that was autofilled");
                         }
                         continue;
                     }
@@ -3442,8 +3735,12 @@
                     final AutofillValue currentValue = viewState.getCurrentValue();
                     if (currentValue == null) {
                         if (sDebug) {
-                            Slog.d(TAG, "logContextCommitted(): skipping view without current "
-                                    + "value ( " + viewState + ")");
+                            Slog.d(
+                                    TAG,
+                                    "logContextCommitted(): skipping view without current "
+                                            + "value ( "
+                                            + viewState
+                                            + ")");
                         }
                         continue;
                     }
@@ -3455,7 +3752,7 @@
                             final List<Dataset> datasets = response.getDatasets();
                             if (datasets == null || datasets.isEmpty()) {
                                 if (sVerbose) {
-                                    Slog.v(TAG,  "logContextCommitted() no datasets at " + j);
+                                    Slog.v(TAG, "logContextCommitted() no datasets at " + j);
                                 }
                             } else {
                                 for (int k = 0; k < datasets.size(); k++) {
@@ -3463,8 +3760,11 @@
                                     final String datasetId = dataset.getId();
                                     if (datasetId == null) {
                                         if (sVerbose) {
-                                            Slog.v(TAG, "logContextCommitted() skipping idless "
-                                                    + "dataset " + dataset);
+                                            Slog.v(
+                                                    TAG,
+                                                    "logContextCommitted() skipping idless "
+                                                            + "dataset "
+                                                            + dataset);
                                         }
                                     } else {
                                         final ArrayList<AutofillValue> values =
@@ -3473,9 +3773,13 @@
                                             final AutofillValue candidate = values.get(l);
                                             if (currentValue.equals(candidate)) {
                                                 if (sDebug) {
-                                                    Slog.d(TAG, "field " + viewState.id + " was "
-                                                            + "manually filled with value set by "
-                                                            + "dataset " + datasetId);
+                                                    Slog.d(
+                                                            TAG,
+                                                            "field "
+                                                                    + viewState.id
+                                                                    + " was manually filled with"
+                                                                    + " value set by dataset "
+                                                                    + datasetId);
                                                 }
                                                 if (manuallyFilledIds == null) {
                                                     manuallyFilledIds = new ArrayMap<>();
@@ -3524,10 +3828,20 @@
             }
         }
 
-        mService.logContextCommittedLocked(id, mClientState, mSelectedDatasetIds, ignoredDatasets,
-                changedFieldIds, changedDatasetIds, manuallyFilledFieldIds,
-                manuallyFilledDatasetIds, detectedFieldIds, detectedFieldClassifications,
-                mComponentName, mCompatMode, saveDialogNotShowReason);
+        mService.logContextCommittedLocked(
+                id,
+                mClientState,
+                mSelectedDatasetIds,
+                ignoredDatasets,
+                changedFieldIds,
+                changedDatasetIds,
+                manuallyFilledFieldIds,
+                manuallyFilledDatasetIds,
+                detectedFieldIds,
+                detectedFieldClassifications,
+                mComponentName,
+                mCompatMode,
+                saveDialogNotShowReason);
         mSessionCommittedEventLogger.maybeSetCommitReason(commitReason);
         mSessionCommittedEventLogger.maybeSetRequestCount(mRequestCount);
         mSaveEventLogger.maybeSetSaveUiNotShownReason(saveDialogNotShowReason);
@@ -3537,7 +3851,8 @@
      * Adds the matches to {@code detectedFieldsIds} and {@code detectedFieldClassifications} for
      * {@code fieldId} based on its {@code currentValue} and {@code userData}.
      */
-    private void logFieldClassificationScore(@NonNull FieldClassificationStrategy fcStrategy,
+    private void logFieldClassificationScore(
+            @NonNull FieldClassificationStrategy fcStrategy,
             @NonNull FieldClassificationUserData userData,
             @NoSaveReason int saveDialogNotShowReason,
             @AutofillCommitReason int commitReason) {
@@ -3555,16 +3870,20 @@
         if (userValues == null || categoryIds == null || userValues.length != categoryIds.length) {
             final int valuesLength = userValues == null ? -1 : userValues.length;
             final int idsLength = categoryIds == null ? -1 : categoryIds.length;
-            Slog.w(TAG, "setScores(): user data mismatch: values.length = "
-                    + valuesLength + ", ids.length = " + idsLength);
+            Slog.w(
+                    TAG,
+                    "setScores(): user data mismatch: values.length = "
+                            + valuesLength
+                            + ", ids.length = "
+                            + idsLength);
             return;
         }
 
         final int maxFieldsSize = UserData.getMaxFieldClassificationIdsSize();
 
         final ArrayList<AutofillId> detectedFieldIds = new ArrayList<>(maxFieldsSize);
-        final ArrayList<FieldClassification> detectedFieldClassifications = new ArrayList<>(
-                maxFieldsSize);
+        final ArrayList<FieldClassification> detectedFieldClassifications =
+                new ArrayList<>(maxFieldsSize);
 
         final Collection<ViewState> viewStates;
         synchronized (mLock) {
@@ -3583,33 +3902,49 @@
         }
 
         // Then use the results, asynchronously
-        final RemoteCallback callback = new RemoteCallback(
-                new LogFieldClassificationScoreOnResultListener(
-                        this,
-                        saveDialogNotShowReason,
-                        commitReason,
-                        viewsSize,
-                        autofillIds,
-                        userValues,
-                        categoryIds,
-                        detectedFieldIds,
-                        detectedFieldClassifications));
+        final RemoteCallback callback =
+                new RemoteCallback(
+                        new LogFieldClassificationScoreOnResultListener(
+                                this,
+                                saveDialogNotShowReason,
+                                commitReason,
+                                viewsSize,
+                                autofillIds,
+                                userValues,
+                                categoryIds,
+                                detectedFieldIds,
+                                detectedFieldClassifications));
 
-        fcStrategy.calculateScores(callback, currentValues, userValues, categoryIds,
-                defaultAlgorithm, defaultArgs, algorithms, args);
+        fcStrategy.calculateScores(
+                callback,
+                currentValues,
+                userValues,
+                categoryIds,
+                defaultAlgorithm,
+                defaultArgs,
+                algorithms,
+                args);
     }
 
-    void handleLogFieldClassificationScore(@Nullable Bundle result, int saveDialogNotShowReason,
-            int commitReason, int viewsSize, AutofillId[] autofillIds, String[] userValues,
-            String[] categoryIds, ArrayList<AutofillId> detectedFieldIds,
+    void handleLogFieldClassificationScore(
+            @Nullable Bundle result,
+            int saveDialogNotShowReason,
+            int commitReason,
+            int viewsSize,
+            AutofillId[] autofillIds,
+            String[] userValues,
+            String[] categoryIds,
+            ArrayList<AutofillId> detectedFieldIds,
             ArrayList<FieldClassification> detectedFieldClassifications) {
         if (result == null) {
             if (sDebug) Slog.d(TAG, "setFieldClassificationScore(): no results");
             logContextCommitted(null, null, saveDialogNotShowReason, commitReason);
             return;
         }
-        final Scores scores = result.getParcelable(EXTRA_SCORES,
-                android.service.autofill.AutofillFieldClassificationService.Scores.class);
+        final Scores scores =
+                result.getParcelable(
+                        EXTRA_SCORES,
+                        android.service.autofill.AutofillFieldClassificationService.Scores.class);
         if (scores == null) {
             Slog.w(TAG, "No field classification score on " + result);
             return;
@@ -3633,14 +3968,24 @@
                         final Float currentScore = scoresByField.get(categoryId);
                         if (currentScore != null && currentScore > score) {
                             if (sVerbose) {
-                                Slog.v(TAG, "skipping score " + score
-                                        + " because it's less than " + currentScore);
+                                Slog.v(
+                                        TAG,
+                                        "skipping score "
+                                                + score
+                                                + " because it's less than "
+                                                + currentScore);
                             }
                             continue;
                         }
                         if (sVerbose) {
-                            Slog.v(TAG, "adding score " + score + " at index " + j + " and id "
-                                    + autofillId);
+                            Slog.v(
+                                    TAG,
+                                    "adding score "
+                                            + score
+                                            + " at index "
+                                            + j
+                                            + " and id "
+                                            + autofillId);
                         }
                         scoresByField.put(categoryId, score);
                     } else if (sVerbose) {
@@ -3666,13 +4011,16 @@
             wtf(e, "Error accessing FC score at [%d, %d] (%s): %s", i, j, scores, e);
             return;
         }
-        logContextCommitted(detectedFieldIds, detectedFieldClassifications,
-                saveDialogNotShowReason, commitReason);
+        logContextCommitted(
+                detectedFieldIds,
+                detectedFieldClassifications,
+                saveDialogNotShowReason,
+                commitReason);
     }
 
     /**
-     * Generates a {@link android.service.autofill.FillEventHistory.Event#TYPE_SAVE_SHOWN}
-     * when necessary.
+     * Generates a {@link android.service.autofill.FillEventHistory.Event#TYPE_SAVE_SHOWN} when
+     * necessary.
      *
      * <p>Note: It is necessary to call logContextCommitted() first before calling this method.
      */
@@ -3689,11 +4037,14 @@
     @NonNull
     public SaveResult showSaveLocked() {
         if (mDestroyed) {
-            Slog.w(TAG, "Call to Session#showSaveLocked() rejected - session: "
-                    + id + " destroyed");
+            Slog.w(
+                    TAG,
+                    "Call to Session#showSaveLocked() rejected - session: " + id + " destroyed");
             mSaveEventLogger.maybeSetSaveUiNotShownReason(NO_SAVE_REASON_SESSION_DESTROYED);
             mSaveEventLogger.logAndEndEvent();
-            return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ false,
+            return new SaveResult(
+                    /* logSaveShown= */ false,
+                    /* removeSession= */ false,
                     Event.NO_SAVE_UI_REASON_NONE);
         }
         mSessionState = STATE_FINISHED;
@@ -3705,12 +4056,16 @@
          */
         if (mSessionFlags.mScreenHasCredmanField) {
             if (sVerbose) {
-                Slog.v(TAG, "Call to Session#showSaveLocked() rejected - "
-                        + "there is credman field in screen");
+                Slog.v(
+                        TAG,
+                        "Call to Session#showSaveLocked() rejected - "
+                                + "there is credman field in screen");
             }
             mSaveEventLogger.maybeSetSaveUiNotShownReason(NO_SAVE_REASON_SCREEN_HAS_CREDMAN_FIELD);
             mSaveEventLogger.logAndEndEvent();
-            return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ true,
+            return new SaveResult(
+                    /* logSaveShown= */ false,
+                    /* removeSession= */ true,
                     Event.NO_SAVE_UI_REASON_NONE);
         }
 
@@ -3728,7 +4083,9 @@
             if (sVerbose) Slog.v(TAG, "showSaveLocked(" + this.id + "): no saveInfo from service");
             mSaveEventLogger.maybeSetSaveUiNotShownReason(NO_SAVE_REASON_NO_SAVE_INFO);
             mSaveEventLogger.logAndEndEvent();
-            return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ true,
+            return new SaveResult(
+                    /* logSaveShown= */ false,
+                    /* removeSession= */ true,
                     Event.NO_SAVE_UI_REASON_NO_SAVE_INFO);
         }
 
@@ -3737,7 +4094,9 @@
             if (sDebug) Slog.v(TAG, "showSaveLocked(" + this.id + "): service asked to delay save");
             mSaveEventLogger.maybeSetSaveUiNotShownReason(NO_SAVE_REASON_WITH_DELAY_SAVE_FLAG);
             mSaveEventLogger.logAndEndEvent();
-            return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ false,
+            return new SaveResult(
+                    /* logSaveShown= */ false,
+                    /* removeSession= */ false,
                     Event.NO_SAVE_UI_REASON_WITH_DELAY_SAVE_FLAG);
         }
 
@@ -3774,12 +4133,13 @@
                     // Some apps clear the form before navigating to other activities.
                     // If current value is empty, consider fall back to last cached
                     // non-empty result first.
-                    final AutofillValue candidateSaveValue =
-                            viewState.getCandidateSaveValue();
+                    final AutofillValue candidateSaveValue = viewState.getCandidateSaveValue();
                     if (candidateSaveValue != null && !candidateSaveValue.isEmpty()) {
                         if (sVerbose) {
-                            Slog.v(TAG, "current value is empty, using cached last non-empty "
-                                    + "value instead");
+                            Slog.v(
+                                    TAG,
+                                    "current value is empty, using cached last non-empty "
+                                            + "value instead");
                         }
                         value = candidateSaveValue;
                     } else {
@@ -3788,8 +4148,14 @@
                         final AutofillValue initialValue = getValueFromContextsLocked(id);
                         if (initialValue != null) {
                             if (sDebug) {
-                                Slog.d(TAG, "Value of required field " + id + " didn't change; "
-                                        + "using initial value (" + initialValue + ") instead");
+                                Slog.d(
+                                        TAG,
+                                        "Value of required field "
+                                                + id
+                                                + " didn't change; "
+                                                + "using initial value ("
+                                                + initialValue
+                                                + ") instead");
                             }
                             value = initialValue;
                         } else {
@@ -3821,8 +4187,13 @@
                         final AutofillValue initialValue = getValueFromContextsLocked(id);
                         if (initialValue != null && initialValue.equals(value)) {
                             if (sDebug) {
-                                Slog.d(TAG, "id " + id + " is part of dataset but initial value "
-                                        + "didn't change: " + value);
+                                Slog.d(
+                                        TAG,
+                                        "id "
+                                                + id
+                                                + " is part of dataset but initial value "
+                                                + "didn't change: "
+                                                + value);
                             }
                             changed = false;
                         } else {
@@ -3833,8 +4204,14 @@
                     }
                     if (changed) {
                         if (sDebug) {
-                            Slog.d(TAG, "found a change on required " + id + ": " + filledValue
-                                    + " => " + value);
+                            Slog.d(
+                                    TAG,
+                                    "found a change on required "
+                                            + id
+                                            + ": "
+                                            + filledValue
+                                            + " => "
+                                            + value);
                         }
                         atLeastOneChanged = true;
                     }
@@ -3844,8 +4221,12 @@
 
         final AutofillId[] optionalIds = saveInfo.getOptionalIds();
         if (sVerbose) {
-            Slog.v(TAG, "allRequiredAreNotEmpty: " + allRequiredAreNotEmpty + " hasOptional: "
-                    + (optionalIds != null));
+            Slog.v(
+                    TAG,
+                    "allRequiredAreNotEmpty: "
+                            + allRequiredAreNotEmpty
+                            + " hasOptional: "
+                            + (optionalIds != null));
         }
         int saveDialogNotShowReason;
         if (!allRequiredAreNotEmpty) {
@@ -3859,7 +4240,7 @@
             // - if at least one required id changed but it was not part of a filled dataset, we
             //   need to check if an optional id is part of a filled datased (in which case we show
             //   Update instead of Save)
-            if (optionalIds!= null && (!atLeastOneChanged || !isUpdate)) {
+            if (optionalIds != null && (!atLeastOneChanged || !isUpdate)) {
                 // No change on required ids yet, look for changes on optional ids.
                 for (int i = 0; i < optionalIds.length; i++) {
                     final AutofillId id = optionalIds[i];
@@ -3879,8 +4260,10 @@
                                     viewState.getCandidateSaveValue();
                             if (candidateSaveValue != null && !candidateSaveValue.isEmpty()) {
                                 if (sVerbose) {
-                                    Slog.v(TAG, "current value is empty, using cached last "
-                                            + "non-empty value instead");
+                                    Slog.v(
+                                            TAG,
+                                            "current value is empty, using cached last "
+                                                    + "non-empty value instead");
                                 }
                                 currentValue = candidateSaveValue;
                             }
@@ -3897,8 +4280,14 @@
                         final AutofillValue filledValue = viewState.getAutofilledValue();
                         if (value != null && !value.equals(filledValue)) {
                             if (sDebug) {
-                                Slog.d(TAG, "found a change on optional " + id + ": " + filledValue
-                                        + " => " + value);
+                                Slog.d(
+                                        TAG,
+                                        "found a change on optional "
+                                                + id
+                                                + ": "
+                                                + filledValue
+                                                + " => "
+                                                + value);
                             }
                             if (filledValue != null) {
                                 isUpdate = true;
@@ -3907,12 +4296,16 @@
                             }
                             atLeastOneChanged = true;
                         }
-                    } else  {
+                    } else {
                         // Update current values cache based on initial value
                         final AutofillValue initialValue = getValueFromContextsLocked(id);
                         if (sDebug) {
-                            Slog.d(TAG, "no current value for " + id + "; initial value is "
-                                    + initialValue);
+                            Slog.d(
+                                    TAG,
+                                    "no current value for "
+                                            + id
+                                            + "; initial value is "
+                                            + initialValue);
                         }
                         if (initialValue != null) {
                             currentValues.put(id, initialValue);
@@ -3935,17 +4328,18 @@
                     try {
                         isValid = validator.isValid(this);
                         if (sDebug) Slog.d(TAG, validator + " returned " + isValid);
-                        log.setType(isValid
-                                ? MetricsEvent.TYPE_SUCCESS
-                                : MetricsEvent.TYPE_DISMISS);
+                        log.setType(
+                                isValid ? MetricsEvent.TYPE_SUCCESS : MetricsEvent.TYPE_DISMISS);
                     } catch (Exception e) {
                         Slog.e(TAG, "Not showing save UI because validation failed:", e);
                         log.setType(MetricsEvent.TYPE_FAILURE);
                         mMetricsLogger.write(log);
                         mSaveEventLogger.maybeSetSaveUiNotShownReason(
-                            NO_SAVE_REASON_FIELD_VALIDATION_FAILED);
+                                NO_SAVE_REASON_FIELD_VALIDATION_FAILED);
                         mSaveEventLogger.logAndEndEvent();
-                        return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ true,
+                        return new SaveResult(
+                                /* logSaveShown= */ false,
+                                /* removeSession= */ true,
                                 Event.NO_SAVE_UI_REASON_FIELD_VALIDATION_FAILED);
                     }
 
@@ -3953,9 +4347,11 @@
                     if (!isValid) {
                         Slog.i(TAG, "not showing save UI because fields failed validation");
                         mSaveEventLogger.maybeSetSaveUiNotShownReason(
-                            NO_SAVE_REASON_FIELD_VALIDATION_FAILED);
+                                NO_SAVE_REASON_FIELD_VALIDATION_FAILED);
                         mSaveEventLogger.logAndEndEvent();
-                        return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ true,
+                        return new SaveResult(
+                                /* logSaveShown= */ false,
+                                /* removeSession= */ true,
                                 Event.NO_SAVE_UI_REASON_FIELD_VALIDATION_FAILED);
                     }
                 }
@@ -3964,15 +4360,23 @@
                 // content.
                 final List<Dataset> datasets = response.getDatasets();
                 if (datasets != null) {
-                    datasets_loop: for (int i = 0; i < datasets.size(); i++) {
+                    datasets_loop:
+                    for (int i = 0; i < datasets.size(); i++) {
                         final Dataset dataset = datasets.get(i);
                         final ArrayMap<AutofillId, AutofillValue> datasetValues =
                                 Helper.getFields(dataset);
                         if (sVerbose) {
-                            Slog.v(TAG, "Checking if saved fields match contents of dataset #" + i
-                                    + ": " + dataset + "; savableIds=" + savableIds);
+                            Slog.v(
+                                    TAG,
+                                    "Checking if saved fields match contents of dataset #"
+                                            + i
+                                            + ": "
+                                            + dataset
+                                            + "; savableIds="
+                                            + savableIds);
                         }
-                        savable_ids_loop: for (int j = 0; j < savableIds.size(); j++) {
+                        savable_ids_loop:
+                        for (int j = 0; j < savableIds.size(); j++) {
                             final AutofillId id = savableIds.valueAt(j);
                             final AutofillValue currentValue = currentValues.get(id);
                             if (currentValue == null) {
@@ -3984,20 +4388,33 @@
                             final AutofillValue datasetValue = datasetValues.get(id);
                             if (!currentValue.equals(datasetValue)) {
                                 if (sDebug) {
-                                    Slog.d(TAG, "found a dataset change on id " + id + ": from "
-                                            + datasetValue + " to " + currentValue);
+                                    Slog.d(
+                                            TAG,
+                                            "found a dataset change on id "
+                                                    + id
+                                                    + ": from "
+                                                    + datasetValue
+                                                    + " to "
+                                                    + currentValue);
                                 }
                                 continue datasets_loop;
                             }
                             if (sVerbose) Slog.v(TAG, "no dataset changes for id " + id);
                         }
                         if (sDebug) {
-                            Slog.d(TAG, "ignoring Save UI because all fields match contents of "
-                                    + "dataset #" + i + ": " + dataset);
+                            Slog.d(
+                                    TAG,
+                                    "ignoring Save UI because all fields match contents of "
+                                            + "dataset #"
+                                            + i
+                                            + ": "
+                                            + dataset);
                         }
                         mSaveEventLogger.maybeSetSaveUiNotShownReason(NO_SAVE_REASON_DATASET_MATCH);
                         mSaveEventLogger.logAndEndEvent();
-                        return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ true,
+                        return new SaveResult(
+                                /* logSaveShown= */ false,
+                                /* removeSession= */ true,
                                 Event.NO_SAVE_UI_REASON_DATASET_MATCH);
                     }
                 }
@@ -4015,13 +4432,26 @@
                     wtf(null, "showSaveLocked(): no service label or icon");
                     mSaveEventLogger.maybeSetSaveUiNotShownReason(NO_SAVE_REASON_NONE);
                     mSaveEventLogger.logAndEndEvent();
-                    return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ true,
+                    return new SaveResult(
+                            /* logSaveShown= */ false,
+                            /* removeSession= */ true,
                             Event.NO_SAVE_UI_REASON_NONE);
                 }
-                getUiForShowing().showSaveUi(serviceLabel, serviceIcon,
-                        mService.getServicePackageName(), saveInfo, this,
-                        mComponentName, this, mContext,  mPendingSaveUi, isUpdate, mCompatMode,
-                        response.getShowSaveDialogIcon(), mSaveEventLogger);
+                getUiForShowing()
+                        .showSaveUi(
+                                serviceLabel,
+                                serviceIcon,
+                                mService.getServicePackageName(),
+                                saveInfo,
+                                this,
+                                mComponentName,
+                                this,
+                                mContext,
+                                mPendingSaveUi,
+                                isUpdate,
+                                mCompatMode,
+                                response.getShowSaveDialogIcon(),
+                                mSaveEventLogger);
                 if (client != null) {
                     try {
                         client.setSaveUiState(id, true);
@@ -4031,21 +4461,30 @@
                 }
                 mSessionFlags.mShowingSaveUi = true;
                 if (sDebug) {
-                    Slog.d(TAG, "Good news, everyone! All checks passed, show save UI for "
-                            + id + "!");
+                    Slog.d(
+                            TAG,
+                            "Good news, everyone! All checks passed, show save UI for " + id + "!");
                 }
-                return new SaveResult(/* logSaveShown= */ true, /* removeSession= */ false,
+                return new SaveResult(
+                        /* logSaveShown= */ true,
+                        /* removeSession= */ false,
                         Event.NO_SAVE_UI_REASON_NONE);
             }
         }
         // Nothing changed...
         if (sDebug) {
-            Slog.d(TAG, "showSaveLocked(" + id +"): with no changes, comes no responsibilities."
-                    + "allRequiredAreNotNull=" + allRequiredAreNotEmpty
-                    + ", atLeastOneChanged=" + atLeastOneChanged);
+            Slog.d(
+                    TAG,
+                    "showSaveLocked("
+                            + id
+                            + "): with no changes, comes no responsibilities."
+                            + "allRequiredAreNotNull="
+                            + allRequiredAreNotEmpty
+                            + ", atLeastOneChanged="
+                            + atLeastOneChanged);
         }
-        return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ true,
-                saveDialogNotShowReason);
+        return new SaveResult(
+                /* logSaveShown= */ false, /* removeSession= */ true, saveDialogNotShowReason);
     }
 
     private void logSaveShown() {
@@ -4078,25 +4517,21 @@
         return sanitized;
     }
 
-    /**
-     * Returns whether the session is currently showing the save UI
-     */
+    /** Returns whether the session is currently showing the save UI */
     @GuardedBy("mLock")
     boolean isSaveUiShowingLocked() {
         return mSessionFlags.mShowingSaveUi;
     }
 
-    /**
-     * Gets the latest non-empty value for the given id in the autofill contexts.
-     */
+    /** Gets the latest non-empty value for the given id in the autofill contexts. */
     @GuardedBy("mLock")
     @Nullable
     private ViewNode getViewNodeFromContextsLocked(@NonNull AutofillId autofillId) {
         final int numContexts = mContexts.size();
         for (int i = numContexts - 1; i >= 0; i--) {
             final FillContext context = mContexts.get(i);
-            final ViewNode node = Helper.findViewNodeByAutofillId(context.getStructure(),
-                    autofillId);
+            final ViewNode node =
+                    Helper.findViewNodeByAutofillId(context.getStructure(), autofillId);
             if (node != null) {
                 return node;
             }
@@ -4104,22 +4539,28 @@
         return null;
     }
 
-    /**
-     * Gets the latest non-empty value for the given id in the autofill contexts.
-     */
+    /** Gets the latest non-empty value for the given id in the autofill contexts. */
     @GuardedBy("mLock")
     @Nullable
     private AutofillValue getValueFromContextsLocked(@NonNull AutofillId autofillId) {
         final int numContexts = mContexts.size();
         for (int i = numContexts - 1; i >= 0; i--) {
             final FillContext context = mContexts.get(i);
-            final ViewNode node = Helper.findViewNodeByAutofillId(context.getStructure(),
-                    autofillId);
+            final ViewNode node =
+                    Helper.findViewNodeByAutofillId(context.getStructure(), autofillId);
             if (node != null) {
                 final AutofillValue value = node.getAutofillValue();
                 if (sDebug) {
-                    Slog.d(TAG, "getValueFromContexts(" + this.id + "/" + autofillId + ") at "
-                            + i + ": " + value);
+                    Slog.d(
+                            TAG,
+                            "getValueFromContexts("
+                                    + this.id
+                                    + "/"
+                                    + autofillId
+                                    + ") at "
+                                    + i
+                                    + ": "
+                                    + value);
                 }
                 if (value != null && !value.isEmpty()) {
                     return value;
@@ -4129,17 +4570,15 @@
         return null;
     }
 
-    /**
-     * Gets the latest autofill options for the given id in the autofill contexts.
-     */
+    /** Gets the latest autofill options for the given id in the autofill contexts. */
     @GuardedBy("mLock")
     @Nullable
     private CharSequence[] getAutofillOptionsFromContextsLocked(@NonNull AutofillId autofillId) {
         final int numContexts = mContexts.size();
         for (int i = numContexts - 1; i >= 0; i--) {
             final FillContext context = mContexts.get(i);
-            final ViewNode node = Helper.findViewNodeByAutofillId(context.getStructure(),
-                    autofillId);
+            final ViewNode node =
+                    Helper.findViewNodeByAutofillId(context.getStructure(), autofillId);
             if (node != null && node.getAutofillOptions() != null) {
                 return node.getAutofillOptions();
             }
@@ -4160,7 +4599,7 @@
             final FillContext context = mContexts.get(contextNum);
 
             final ViewNode[] nodes =
-                context.findViewNodesByAutofillIds(getIdsOfAllViewStatesLocked());
+                    context.findViewNodesByAutofillIds(getIdsOfAllViewStatesLocked());
 
             if (sVerbose) Slog.v(TAG, "updateValuesForSaveLocked(): updating " + context);
 
@@ -4191,8 +4630,11 @@
                 if (sanitizedValue != null) {
                     node.updateAutofillValue(sanitizedValue);
                 } else if (sDebug) {
-                    Slog.d(TAG, "updateValuesForSaveLocked(): not updating field " + id
-                            + " because it failed sanitization");
+                    Slog.d(
+                            TAG,
+                            "updateValuesForSaveLocked(): not updating field "
+                                    + id
+                                    + " because it failed sanitization");
                 }
             }
 
@@ -4200,28 +4642,33 @@
             context.getStructure().sanitizeForParceling(false);
 
             if (sVerbose) {
-                Slog.v(TAG, "updateValuesForSaveLocked(): dumping structure of " + context
-                        + " before calling service.save()");
+                Slog.v(
+                        TAG,
+                        "updateValuesForSaveLocked(): dumping structure of "
+                                + context
+                                + " before calling service.save()");
                 context.getStructure().dump(false);
             }
         }
     }
 
-    /**
-     * Calls service when user requested save.
-     */
+    /** Calls service when user requested save. */
     @GuardedBy("mLock")
     void callSaveLocked() {
         if (mDestroyed) {
-            Slog.w(TAG, "Call to Session#callSaveLocked() rejected - session: "
-                    + id + " destroyed");
+            Slog.w(
+                    TAG,
+                    "Call to Session#callSaveLocked() rejected - session: " + id + " destroyed");
             mSaveEventLogger.maybeSetIsSaved(false);
             mSaveEventLogger.logAndEndEvent();
             return;
         }
         if (mRemoteFillService == null) {
-            wtf(null, "callSaveLocked() called without a remote service. "
-                    + "mForAugmentedAutofillOnly: %s", mSessionFlags.mAugmentedAutofillOnly);
+            wtf(
+                    null,
+                    "callSaveLocked() called without a remote service. "
+                            + "mForAugmentedAutofillOnly: %s",
+                    mSessionFlags.mAugmentedAutofillOnly);
             mSaveEventLogger.maybeSetIsSaved(false);
             mSaveEventLogger.logAndEndEvent();
             return;
@@ -4241,7 +4688,7 @@
         // Remove pending fill requests as the session is finished.
         cancelCurrentRequestLocked();
 
-        final ArrayList<FillContext> contexts = mergePreviousSessionLocked( /* forSave= */ true);
+        final ArrayList<FillContext> contexts = mergePreviousSessionLocked(/* forSave= */ true);
 
         FieldClassificationResponse fieldClassificationResponse =
                 mClassificationState.mLastFieldClassificationResponse;
@@ -4251,8 +4698,9 @@
             if (mClientState == null) {
                 mClientState = new Bundle();
             }
-            mClientState.putParcelableArrayList(EXTRA_KEY_DETECTIONS, new ArrayList<>(
-                    fieldClassificationResponse.getClassifications()));
+            mClientState.putParcelableArrayList(
+                    EXTRA_KEY_DETECTIONS,
+                    new ArrayList<>(fieldClassificationResponse.getClassifications()));
         }
         final SaveRequest saveRequest =
                 new SaveRequest(contexts, mClientState, mSelectedDatasetIds);
@@ -4270,11 +4718,12 @@
      * from previous sessions that were asked by the service to be delayed (if any).
      *
      * <p>As a side-effect:
+     *
      * <ul>
-     *   <li>If the current {@link #mClientState} is {@code null}, sets it with the last non-
-     *   {@code null} client state from previous sessions.
+     *   <li>If the current {@link #mClientState} is {@code null}, sets it with the last non- {@code
+     *       null} client state from previous sessions.
      *   <li>When {@code forSave} is {@code true}, calls {@link #updateValuesForSaveLocked()} in the
-     *   previous sessions.
+     *       previous sessions.
      * </ul>
      */
     @NonNull
@@ -4283,30 +4732,51 @@
         final ArrayList<FillContext> contexts;
         if (previousSessions != null) {
             if (sDebug) {
-                Slog.d(TAG, "mergeSessions(" + this.id + "): Merging the content of "
-                        + previousSessions.size() + " sessions for task " + taskId);
+                Slog.d(
+                        TAG,
+                        "mergeSessions("
+                                + this.id
+                                + "): Merging the content of "
+                                + previousSessions.size()
+                                + " sessions for task "
+                                + taskId);
             }
             contexts = new ArrayList<>();
             for (int i = 0; i < previousSessions.size(); i++) {
                 final Session previousSession = previousSessions.get(i);
                 final ArrayList<FillContext> previousContexts = previousSession.mContexts;
                 if (previousContexts == null) {
-                    Slog.w(TAG, "mergeSessions(" + this.id + "): Not merging null contexts from "
-                            + previousSession.id);
+                    Slog.w(
+                            TAG,
+                            "mergeSessions("
+                                    + this.id
+                                    + "): Not merging null contexts from "
+                                    + previousSession.id);
                     continue;
                 }
                 if (forSave) {
                     previousSession.updateValuesForSaveLocked();
                 }
                 if (sDebug) {
-                    Slog.d(TAG, "mergeSessions(" + this.id + "): adding " + previousContexts.size()
-                            + " context from previous session #" + previousSession.id);
+                    Slog.d(
+                            TAG,
+                            "mergeSessions("
+                                    + this.id
+                                    + "): adding "
+                                    + previousContexts.size()
+                                    + " context from previous session #"
+                                    + previousSession.id);
                 }
                 contexts.addAll(previousContexts);
                 if (mClientState == null && previousSession.mClientState != null) {
                     if (sDebug) {
-                        Slog.d(TAG, "mergeSessions(" + this.id + "): setting client state from "
-                                + "previous session" + previousSession.id);
+                        Slog.d(
+                                TAG,
+                                "mergeSessions("
+                                        + this.id
+                                        + "): setting client state from "
+                                        + "previous session"
+                                        + previousSession.id);
                     }
                     mClientState = previousSession.mClientState;
                 }
@@ -4351,8 +4821,12 @@
         // If it's not, then check if it should start a partition.
         if (shouldStartNewPartitionLocked(id, flags)) {
             if (sDebug) {
-                Slog.d(TAG, "Starting partition or augmented request for view id " + id + ": "
-                        + viewState.getStateAsString());
+                Slog.d(
+                        TAG,
+                        "Starting partition or augmented request for view id "
+                                + id
+                                + ": "
+                                + viewState.getStateAsString());
             }
             // Fix to always let standard autofill start.
             // Sometimes activity contain IMPORTANT_FOR_AUTOFILL_NO fields which marks session as
@@ -4363,8 +4837,12 @@
         }
 
         if (sVerbose) {
-            Slog.v(TAG, "Not starting new partition for view " + id + ": "
-                    + viewState.getStateAsString());
+            Slog.v(
+                    TAG,
+                    "Not starting new partition for view "
+                            + id
+                            + ": "
+                            + viewState.getStateAsString());
         }
         return Optional.empty();
     }
@@ -4373,17 +4851,17 @@
      * Determines if a new partition should be started for an id.
      *
      * @param id The id of the view that is entered
-     *
      * @return {@code true} if a new partition should be started
      */
     @GuardedBy("mLock")
     private boolean shouldStartNewPartitionLocked(@NonNull AutofillId id, int flags) {
         final ViewState currentView = mViewStates.get(id);
-        SparseArray<FillResponse> responses = shouldRequestSecondaryProvider(flags)
-                ? mSecondaryResponses : mResponses;
+        SparseArray<FillResponse> responses =
+                shouldRequestSecondaryProvider(flags) ? mSecondaryResponses : mResponses;
         if (responses == null) {
-            return currentView != null && (currentView.getState()
-                    & ViewState.STATE_PENDING_CREATE_INLINE_REQUEST) == 0;
+            return currentView != null
+                    && (currentView.getState() & ViewState.STATE_PENDING_CREATE_INLINE_REQUEST)
+                            == 0;
         }
 
         if (mSessionFlags.mExpiredResponse) {
@@ -4395,8 +4873,14 @@
 
         final int numResponses = responses.size();
         if (numResponses >= AutofillManagerService.getPartitionMaxCount()) {
-            Slog.e(TAG, "Not starting a new partition on " + id + " because session " + this.id
-                    + " reached maximum of " + AutofillManagerService.getPartitionMaxCount());
+            Slog.e(
+                    TAG,
+                    "Not starting a new partition on "
+                            + id
+                            + " because session "
+                            + this.id
+                            + " reached maximum of "
+                            + AutofillManagerService.getPartitionMaxCount());
             return false;
         }
 
@@ -4437,8 +4921,7 @@
     }
 
     boolean shouldRequestSecondaryProvider(int flags) {
-        if (!mService.isAutofillCredmanIntegrationEnabled()
-                || mSecondaryProviderHandler == null) {
+        if (!mService.isAutofillCredmanIntegrationEnabled() || mSecondaryProviderHandler == null) {
             return false;
         }
         if (mIsPrimaryCredential) {
@@ -4452,8 +4935,8 @@
     // 'Session.this.mLock', which is the same as mLock.
     @SuppressWarnings("GuardedBy")
     @GuardedBy("mLock")
-    void updateLocked(AutofillId id, Rect virtualBounds, AutofillValue value, int action,
-            int flags) {
+    void updateLocked(
+            AutofillId id, Rect virtualBounds, AutofillValue value, int action, int flags) {
         if (mDestroyed) {
             Slog.w(TAG, "updateLocked(" + id + "):  rejected - session: destroyed");
             return;
@@ -4464,7 +4947,7 @@
                 Slog.d(TAG, "updateLocked(" + id + "): Set the response has expired.");
             }
             mPresentationStatsEventLogger.maybeSetNoPresentationEventReasonIfNoReasonExists(
-                        NOT_SHOWN_REASON_VIEW_CHANGED);
+                    NOT_SHOWN_REASON_VIEW_CHANGED);
             mPresentationStatsEventLogger.logAndEndEvent("ACTION_RESPONSE_EXPIRED");
             return;
         }
@@ -4474,23 +4957,35 @@
         if (sVerbose) {
             Slog.v(
                     TAG,
-                    "updateLocked(" + id + "): "
-                            + "id=" + this.id
-                            + ", action=" + actionAsString(action)
-                            + ", flags=" + flags
-                            + ", mCurrentViewId=" + mCurrentViewId
-                            + ", mExpiredResponse=" + mSessionFlags.mExpiredResponse
-                            + ", viewState=" + viewState);
+                    "updateLocked("
+                            + id
+                            + "): "
+                            + "id="
+                            + this.id
+                            + ", action="
+                            + actionAsString(action)
+                            + ", flags="
+                            + flags
+                            + ", mCurrentViewId="
+                            + mCurrentViewId
+                            + ", mExpiredResponse="
+                            + mSessionFlags.mExpiredResponse
+                            + ", viewState="
+                            + viewState);
         }
 
         if (viewState == null) {
-            if (action == ACTION_START_SESSION || action == ACTION_VALUE_CHANGED
+            if (action == ACTION_START_SESSION
+                    || action == ACTION_VALUE_CHANGED
                     || action == ACTION_VIEW_ENTERED) {
                 if (sVerbose) Slog.v(TAG, "Creating viewState for " + id);
                 boolean isIgnored = isIgnoredLocked(id);
-                viewState = new ViewState(id, this,
-                        isIgnored ? ViewState.STATE_IGNORED : ViewState.STATE_INITIAL,
-                        mIsPrimaryCredential);
+                viewState =
+                        new ViewState(
+                                id,
+                                this,
+                                isIgnored ? ViewState.STATE_IGNORED : ViewState.STATE_INITIAL,
+                                mIsPrimaryCredential);
                 mViewStates.put(id, viewState);
 
                 // TODO(b/73648631): for optimization purposes, should also ignore if change is
@@ -4521,7 +5016,7 @@
             mSessionFlags.mScreenHasCredmanField = true;
         }
 
-        switch(action) {
+        switch (action) {
             case ACTION_START_SESSION:
                 // View is triggering autofill.
                 mCurrentViewId = viewState.id;
@@ -4545,14 +5040,14 @@
             case ACTION_VALUE_CHANGED:
                 if (mCompatMode && (viewState.getState() & ViewState.STATE_URL_BAR) != 0) {
                     // Must cancel the session if the value of the URL bar changed
-                    final String currentUrl = mUrlBar == null ? null
-                            : mUrlBar.getText().toString().trim();
+                    final String currentUrl =
+                            mUrlBar == null ? null : mUrlBar.getText().toString().trim();
                     if (currentUrl == null) {
                         // Validation check - shouldn't happen.
                         wtf(null, "URL bar value changed, but current value is null");
                         return;
                     }
-                    if (value == null || ! value.isText()) {
+                    if (value == null || !value.isText()) {
                         // Validation check - shouldn't happen.
                         wtf(null, "URL bar value changed to null or non-text: %s", value);
                         return;
@@ -4567,8 +5062,10 @@
                         // are finished, as the URL bar changed callback is usually called before
                         // the virtual views become invisible.
                         if (sDebug) {
-                            Slog.d(TAG, "Ignoring change on URL because session will finish when "
-                                    + "views are gone");
+                            Slog.d(
+                                    TAG,
+                                    "Ignoring change on URL because session will finish when "
+                                            + "views are gone");
                         }
                         return;
                     }
@@ -4598,8 +5095,9 @@
                 // isSameViewEntered has some limitations, where it isn't considered same view when
                 // autofill suggestions pop up, user selects, and the focus lands back on the view.
                 // isSameViewAgain tries to overcome that situation.
-                final boolean isSameViewAgain = isSameViewEntered
-                        || Objects.equals(mCurrentViewId, mPreviousNonNullEnteredViewId);
+                final boolean isSameViewAgain =
+                        isSameViewEntered
+                                || Objects.equals(mCurrentViewId, mPreviousNonNullEnteredViewId);
                 if (mCurrentViewId != null) {
                     mPreviousNonNullEnteredViewId = mCurrentViewId;
                 }
@@ -4655,8 +5153,8 @@
                 // Trigger augmented autofill if applicable
                 if ((flags & FLAG_MANUAL_REQUEST) == 0) {
                     // Not a manual request
-                    if (mAugmentedAutofillableIds != null && mAugmentedAutofillableIds.contains(
-                            id)) {
+                    if (mAugmentedAutofillableIds != null
+                            && mAugmentedAutofillableIds.contains(id)) {
                         // Regular autofill handled the view and returned null response, but it
                         // triggered augmented autofill
                         if (!isSameViewEntered) {
@@ -4664,16 +5162,20 @@
                             triggerAugmentedAutofillLocked(flags);
                         } else {
                             if (sDebug) {
-                                Slog.d(TAG, "skip augmented autofill for same view: "
-                                        + "same view entered");
+                                Slog.d(
+                                        TAG,
+                                        "skip augmented autofill for same view: "
+                                                + "same view entered");
                             }
                         }
                         return;
                     } else if (mSessionFlags.mAugmentedAutofillOnly && isSameViewEntered) {
                         // Regular autofill is disabled.
                         if (sDebug) {
-                            Slog.d(TAG, "skip augmented autofill for same view: "
-                                    + "standard autofill disabled.");
+                            Slog.d(
+                                    TAG,
+                                    "skip augmented autofill for same view: "
+                                            + "standard autofill disabled.");
                         }
                         return;
                     }
@@ -4717,8 +5219,8 @@
                     // on the IME side if it arrives before the input view is finished on the IME.
                     mInlineSessionController.resetInlineFillUiLocked();
 
-                    if ((viewState.getState() &
-                            ViewState.STATE_PENDING_CREATE_INLINE_REQUEST) != 0) {
+                    if ((viewState.getState() & ViewState.STATE_PENDING_CREATE_INLINE_REQUEST)
+                            != 0) {
                         // View was exited before Inline Request sent back, do not set it to
                         // null yet to let onHandleAssistData finish processing
                     } else {
@@ -4728,7 +5230,7 @@
                     // It's not necessary that there's no more presentation for this view. It could
                     // be that the user chose some suggestion, in which case, view exits.
                     mPresentationStatsEventLogger.maybeSetNoPresentationEventReason(
-                                NOT_SHOWN_REASON_VIEW_FOCUS_CHANGED);
+                            NOT_SHOWN_REASON_VIEW_FOCUS_CHANGED);
                 }
                 break;
             default:
@@ -4737,8 +5239,8 @@
     }
 
     @GuardedBy("mLock")
-    private void logPresentationStatsOnViewEnteredLocked(FillResponse response,
-            boolean isCredmanRequested) {
+    private void logPresentationStatsOnViewEnteredLocked(
+            FillResponse response, boolean isCredmanRequested) {
         mPresentationStatsEventLogger.maybeSetIsCredentialRequest(isCredmanRequested);
         mPresentationStatsEventLogger.maybeSetFieldClassificationRequestId(
                 mFieldClassificationIdSnapshot);
@@ -4754,16 +5256,13 @@
 
     @GuardedBy("mLock")
     private void hideAugmentedAutofillLocked(@NonNull ViewState viewState) {
-        if ((viewState.getState()
-                & ViewState.STATE_TRIGGERED_AUGMENTED_AUTOFILL) != 0) {
+        if ((viewState.getState() & ViewState.STATE_TRIGGERED_AUGMENTED_AUTOFILL) != 0) {
             viewState.resetState(ViewState.STATE_TRIGGERED_AUGMENTED_AUTOFILL);
             cancelAugmentedAutofillLocked();
         }
     }
 
-    /**
-     * Checks whether a view should be ignored.
-     */
+    /** Checks whether a view should be ignored. */
     @GuardedBy("mLock")
     private boolean isIgnoredLocked(AutofillId id) {
         // Always check the latest response only
@@ -4782,22 +5281,30 @@
                 && getSaveInfoLocked() != null) {
             final int length = viewState.getCurrentValue().getTextValue().length();
             if (sDebug) {
-                Slog.d(TAG, "updateLocked(" + id + "): resetting value that was "
-                        + length + " chars long");
+                Slog.d(
+                        TAG,
+                        "updateLocked("
+                                + id
+                                + "): resetting value that was "
+                                + length
+                                + " chars long");
             }
-            final LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_VALUE_RESET)
-                    .addTaggedData(MetricsEvent.FIELD_AUTOFILL_PREVIOUS_LENGTH, length);
+            final LogMaker log =
+                    newLogMaker(MetricsEvent.AUTOFILL_VALUE_RESET)
+                            .addTaggedData(MetricsEvent.FIELD_AUTOFILL_PREVIOUS_LENGTH, length);
             mMetricsLogger.write(log);
         }
     }
 
     @GuardedBy("mLock")
-    private void updateViewStateAndUiOnValueChangedLocked(AutofillId id, AutofillValue value,
-            ViewState viewState, int flags) {
+    private void updateViewStateAndUiOnValueChangedLocked(
+            AutofillId id, AutofillValue value, ViewState viewState, int flags) {
         // Cache the last non-empty value for save purpose. Some apps clear the form before
         // navigating to other activities.
-        if (mIgnoreViewStateResetToEmpty && (value == null || value.isEmpty())
-                && viewState.getCurrentValue() != null && viewState.getCurrentValue().isText()
+        if (mIgnoreViewStateResetToEmpty
+                && (value == null || value.isEmpty())
+                && viewState.getCurrentValue() != null
+                && viewState.getCurrentValue().isText()
                 && viewState.getCurrentValue().getTextValue() != null
                 && viewState.getCurrentValue().getTextValue().length() > 1) {
             if (sVerbose) {
@@ -4875,8 +5382,8 @@
      * indicate the IME attempting to probe the potentially sensitive content of inline suggestions.
      */
     @GuardedBy("mLock")
-    private void updateFilteringStateOnValueChangedLocked(@Nullable String newTextValue,
-            ViewState viewState) {
+    private void updateFilteringStateOnValueChangedLocked(
+            @Nullable String newTextValue, ViewState viewState) {
         if (newTextValue == null) {
             // Don't just return here, otherwise the IME can circumvent this logic using non-text
             // values.
@@ -4901,18 +5408,22 @@
     }
 
     @Override
-    public void onFillReady(@NonNull FillResponse response, @NonNull AutofillId filledId,
-            @Nullable AutofillValue value, int flags) {
+    public void onFillReady(
+            @NonNull FillResponse response,
+            @NonNull AutofillId filledId,
+            @Nullable AutofillValue value,
+            int flags) {
         synchronized (mLock) {
             mPresentationStatsEventLogger.maybeSetFieldClassificationRequestId(
                     mFieldClassificationIdSnapshot);
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#onFillReady() rejected - session: "
-                        + id + " destroyed");
+                Slog.w(
+                        TAG,
+                        "Call to Session#onFillReady() rejected - session: " + id + " destroyed");
                 mSaveEventLogger.maybeSetSaveUiNotShownReason(NO_SAVE_REASON_SESSION_DESTROYED);
                 mSaveEventLogger.logAndEndEvent();
                 mPresentationStatsEventLogger.maybeSetNoPresentationEventReason(
-                    NOT_SHOWN_REASON_SESSION_COMMITTED_PREMATURELY);
+                        NOT_SHOWN_REASON_SESSION_COMMITTED_PREMATURELY);
                 mPresentationStatsEventLogger.logAndEndEvent("on fill ready");
                 return;
             }
@@ -4954,7 +5465,6 @@
             } else {
                 setFillDialogDisabled();
             }
-
         }
 
         if (response.supportsInlineSuggestions()) {
@@ -4971,10 +5481,20 @@
             }
         }
 
-        getUiForShowing().showFillUi(filledId, response, filterText,
-                mService.getServicePackageName(), mComponentName,
-                serviceLabel, serviceIcon, this, mContext, id, mCompatMode,
-                mService.getMaster().getMaxInputLengthForAutofill());
+        getUiForShowing()
+                .showFillUi(
+                        filledId,
+                        response,
+                        filterText,
+                        mService.getServicePackageName(),
+                        mComponentName,
+                        serviceLabel,
+                        serviceIcon,
+                        this,
+                        mContext,
+                        id,
+                        mCompatMode,
+                        mService.getMaster().getMaxInputLengthForAutofill());
 
         synchronized (mLock) {
             if (mUiShownTime == 0) {
@@ -4983,21 +5503,26 @@
                 final long duration = mUiShownTime - mStartTime;
 
                 if (sDebug) {
-                    final StringBuilder msg = new StringBuilder("1st UI for ")
-                            .append(mActivityToken)
-                            .append(" shown in ");
+                    final StringBuilder msg =
+                            new StringBuilder("1st UI for ")
+                                    .append(mActivityToken)
+                                    .append(" shown in ");
                     TimeUtils.formatDuration(duration, msg);
                     Slog.d(TAG, msg.toString());
                 }
-                final StringBuilder historyLog = new StringBuilder("id=").append(id)
-                        .append(" app=").append(mActivityToken)
-                        .append(" svc=").append(mService.getServicePackageName())
-                        .append(" latency=");
+                final StringBuilder historyLog =
+                        new StringBuilder("id=")
+                                .append(id)
+                                .append(" app=")
+                                .append(mActivityToken)
+                                .append(" svc=")
+                                .append(mService.getServicePackageName())
+                                .append(" latency=");
                 TimeUtils.formatDuration(duration, historyLog);
                 mUiLatencyHistory.log(historyLog.toString());
 
-                addTaggedDataToRequestLogLocked(response.getRequestId(),
-                        MetricsEvent.FIELD_AUTOFILL_DURATION, duration);
+                addTaggedDataToRequestLogLocked(
+                        response.getRequestId(), MetricsEvent.FIELD_AUTOFILL_DURATION, duration);
             }
         }
     }
@@ -5052,8 +5577,8 @@
         }
     }
 
-    private boolean requestShowFillDialog(FillResponse response,
-            AutofillId filledId, String filterText, int flags) {
+    private boolean requestShowFillDialog(
+            FillResponse response, AutofillId filledId, String filterText, int flags) {
         if (!isFillDialogUiEnabled()) {
             // Unsupported fill dialog UI
             if (sDebug) Log.w(TAG, "requestShowFillDialog: fill dialog is disabled");
@@ -5079,7 +5604,6 @@
                 if (sDebug) Log.w(TAG, "Last fill dialog triggered ids are changed.");
                 return false;
             }
-
         }
 
         Drawable serviceIcon = null;
@@ -5087,21 +5611,31 @@
             serviceIcon = getServiceIcon(response);
         }
 
-        getUiForShowing().showFillDialog(filledId, response, filterText,
-                mService.getServicePackageName(), mComponentName, serviceIcon, this,
-                id, mCompatMode, mPresentationStatsEventLogger, mLock);
+        getUiForShowing()
+                .showFillDialog(
+                        filledId,
+                        response,
+                        filterText,
+                        mService.getServicePackageName(),
+                        mComponentName,
+                        serviceIcon,
+                        this,
+                        id,
+                        mCompatMode,
+                        mPresentationStatsEventLogger,
+                        mLock);
         return true;
     }
 
     /**
-     * Get the custom icon that was passed through FillResponse. If the custom icon wasn't able
-     * to be fetched, use the default provider icon instead
+     * Get the custom icon that was passed through FillResponse. If the custom icon wasn't able to
+     * be fetched, use the default provider icon instead
      *
      * @return Drawable of the provider icon, if it was able to be fetched. Null otherwise
      */
     @SuppressWarnings("GuardedBy") // ErrorProne says we need to use mService.mLock, but it's
-                                   // actually the same object as mLock.
-                                   // TODO: Expose mService.mLock or redesign instead.
+    // actually the same object as mLock.
+    // TODO: Expose mService.mLock or redesign instead.
     @GuardedBy("mLock")
     private Drawable getServiceIcon(FillResponse response) {
         Drawable serviceIcon = null;
@@ -5130,14 +5664,14 @@
     }
 
     /**
-     * Get the custom label that was passed through FillResponse. If the custom label
-     * wasn't able to be fetched, use the default provider icon instead
+     * Get the custom label that was passed through FillResponse. If the custom label wasn't able to
+     * be fetched, use the default provider icon instead
      *
      * @return Drawable of the provider icon, if it was able to be fetched. Null otherwise
      */
     @SuppressWarnings("GuardedBy") // ErrorProne says we need to use mService.mLock, but it's
-                                   // actually the same object as mLock.
-                                   // TODO: Expose mService.mLock or redesign instead.
+    // actually the same object as mLock.
+    // TODO: Expose mService.mLock or redesign instead.
     @GuardedBy("mLock")
     private CharSequence getServiceLabel(FillResponse response) {
         CharSequence serviceLabel = null;
@@ -5167,11 +5701,9 @@
         return serviceLabel;
     }
 
-    /**
-     * Returns whether we made a request to show inline suggestions.
-     */
-    private boolean requestShowInlineSuggestionsLocked(@NonNull FillResponse response,
-            @Nullable String filterText) {
+    /** Returns whether we made a request to show inline suggestions. */
+    private boolean requestShowInlineSuggestionsLocked(
+            @NonNull FillResponse response, @Nullable String filterText) {
         if (mCurrentViewId == null) {
             Log.w(TAG, "requestShowInlineSuggestionsLocked(): no view currently focused");
             return false;
@@ -5199,89 +5731,122 @@
         }
 
         final InlineFillUi.InlineFillUiInfo inlineFillUiInfo =
-                new InlineFillUi.InlineFillUiInfo(inlineSuggestionsRequest.get(), focusedId,
-                        filterText, remoteRenderService, userId, id);
-        InlineFillUi inlineFillUi = InlineFillUi.forAutofill(inlineFillUiInfo, response,
-                new InlineFillUi.InlineSuggestionUiCallback() {
-                    @Override
-                    public void autofill(@NonNull Dataset dataset, int datasetIndex) {
-                        fill(response.getRequestId(), datasetIndex, dataset, UI_TYPE_INLINE);
-                    }
+                new InlineFillUi.InlineFillUiInfo(
+                        inlineSuggestionsRequest.get(),
+                        focusedId,
+                        filterText,
+                        remoteRenderService,
+                        userId,
+                        id);
+        InlineFillUi inlineFillUi =
+                InlineFillUi.forAutofill(
+                        inlineFillUiInfo,
+                        response,
+                        new InlineFillUi.InlineSuggestionUiCallback() {
+                            @Override
+                            public void autofill(@NonNull Dataset dataset, int datasetIndex) {
+                                fill(
+                                        response.getRequestId(),
+                                        datasetIndex,
+                                        dataset,
+                                        UI_TYPE_INLINE);
+                            }
 
-                    @Override
-                    public void authenticate(int requestId, int datasetIndex) {
-                        Session.this.authenticate(response.getRequestId(), datasetIndex,
-                                response.getAuthentication(), response.getClientState(),
-                                UI_TYPE_INLINE);
-                    }
+                            @Override
+                            public void authenticate(int requestId, int datasetIndex) {
+                                Session.this.authenticate(
+                                        response.getRequestId(),
+                                        datasetIndex,
+                                        response.getAuthentication(),
+                                        response.getClientState(),
+                                        UI_TYPE_INLINE);
+                            }
 
-                    @Override
-                    public void startIntentSender(@NonNull IntentSender intentSender) {
-                        Session.this.startIntentSender(intentSender, new Intent());
-                    }
+                            @Override
+                            public void startIntentSender(@NonNull IntentSender intentSender) {
+                                Session.this.startIntentSender(intentSender, new Intent());
+                            }
 
-                    @Override
-                    public void onError() {
-                        synchronized (mLock) {
-                            mInlineSessionController.setInlineFillUiLocked(
-                                    InlineFillUi.emptyUi(focusedId));
-                        }
-                    }
+                            @Override
+                            public void onError() {
+                                synchronized (mLock) {
+                                    mInlineSessionController.setInlineFillUiLocked(
+                                            InlineFillUi.emptyUi(focusedId));
+                                }
+                            }
 
-                    @Override
-                    public void onInflate() {
-                        Session.this.onShown(UI_TYPE_INLINE, 1);
-                    }
-                }, mService.getMaster().getMaxInputLengthForAutofill());
+                            @Override
+                            public void onInflate() {
+                                Session.this.onShown(UI_TYPE_INLINE, 1);
+                            }
+                        },
+                        mService.getMaster().getMaxInputLengthForAutofill());
         return mInlineSessionController.setInlineFillUiLocked(inlineFillUi);
     }
 
     private ResultReceiver constructCredentialManagerCallback(int requestId) {
-        final ResultReceiver resultReceiver = new ResultReceiver(mHandler) {
-            final AutofillId mAutofillId = mCurrentViewId;
-            @Override
-            protected void onReceiveResult(int resultCode, Bundle resultData) {
-                if (resultCode == SUCCESS_CREDMAN_SELECTOR) {
-                    Slog.d(TAG, "onReceiveResult from Credential Manager "
-                            + "bottom sheet with mCurrentViewId: " + mAutofillId);
-                    GetCredentialResponse getCredentialResponse =
-                            resultData.getParcelable(
-                                    CredentialProviderService.EXTRA_GET_CREDENTIAL_RESPONSE,
-                                    GetCredentialResponse.class);
+        final ResultReceiver resultReceiver =
+                new ResultReceiver(mHandler) {
+                    final AutofillId mAutofillId = mCurrentViewId;
 
-                    if (Flags.autofillCredmanDevIntegration()) {
-                        sendCredentialManagerResponseToApp(getCredentialResponse,
-                                /*exception=*/ null, mAutofillId);
-                    } else {
-                        Dataset datasetFromCredential = getDatasetFromCredentialResponse(
-                                getCredentialResponse);
-                        if (datasetFromCredential != null) {
-                            autoFill(requestId, /*datasetIndex=*/-1,
-                                    datasetFromCredential, false,
-                                    UI_TYPE_CREDMAN_BOTTOM_SHEET);
+                    @Override
+                    protected void onReceiveResult(int resultCode, Bundle resultData) {
+                        if (resultCode == SUCCESS_CREDMAN_SELECTOR) {
+                            Slog.d(
+                                    TAG,
+                                    "onReceiveResult from Credential Manager "
+                                            + "bottom sheet with mCurrentViewId: "
+                                            + mAutofillId);
+                            GetCredentialResponse getCredentialResponse =
+                                    resultData.getParcelable(
+                                            CredentialProviderService.EXTRA_GET_CREDENTIAL_RESPONSE,
+                                            GetCredentialResponse.class);
+
+                            if (Flags.autofillCredmanDevIntegration()) {
+                                sendCredentialManagerResponseToApp(
+                                        getCredentialResponse, /* exception= */ null, mAutofillId);
+                            } else {
+                                Dataset datasetFromCredential =
+                                        getDatasetFromCredentialResponse(getCredentialResponse);
+                                if (datasetFromCredential != null) {
+                                    autoFill(
+                                            requestId,
+                                            /* datasetIndex= */ -1,
+                                            datasetFromCredential,
+                                            false,
+                                            UI_TYPE_CREDMAN_BOTTOM_SHEET);
+                                }
+                            }
+                        } else if (resultCode == FAILURE_CREDMAN_SELECTOR) {
+                            String[] exception =
+                                    resultData.getStringArray(
+                                            CredentialProviderService
+                                                    .EXTRA_GET_CREDENTIAL_EXCEPTION);
+                            if (exception != null && exception.length >= 2) {
+                                String errType = exception[0];
+                                String errMsg = exception[1];
+                                Slog.w(
+                                        TAG,
+                                        "Credman bottom sheet from pinned "
+                                                + "entry failed with: + "
+                                                + errType
+                                                + " , "
+                                                + errMsg);
+                                sendCredentialManagerResponseToApp(
+                                        /* response= */ null,
+                                        new GetCredentialException(errType, errMsg),
+                                        mAutofillId);
+                            }
+                        } else {
+                            Slog.d(
+                                    TAG,
+                                    "Unknown resultCode from credential "
+                                            + "manager bottom sheet: "
+                                            + resultCode);
                         }
                     }
-                } else if (resultCode == FAILURE_CREDMAN_SELECTOR) {
-                    String[] exception =  resultData.getStringArray(
-                            CredentialProviderService.EXTRA_GET_CREDENTIAL_EXCEPTION);
-                    if (exception != null && exception.length >= 2) {
-                        String errType = exception[0];
-                        String errMsg = exception[1];
-                        Slog.w(TAG, "Credman bottom sheet from pinned "
-                                + "entry failed with: + " + errType + " , "
-                                + errMsg);
-                        sendCredentialManagerResponseToApp(/*response=*/ null,
-                                new GetCredentialException(errType, errMsg),
-                                mAutofillId);
-                    }
-                } else {
-                    Slog.d(TAG, "Unknown resultCode from credential "
-                            + "manager bottom sheet: " + resultCode);
-                }
-            }
-        };
-        ResultReceiver ipcFriendlyResultReceiver =
-                toIpcFriendlyResultReceiver(resultReceiver);
+                };
+        ResultReceiver ipcFriendlyResultReceiver = toIpcFriendlyResultReceiver(resultReceiver);
 
         return ipcFriendlyResultReceiver;
     }
@@ -5309,8 +5874,8 @@
         }
     }
 
-    private void notifyUnavailableToClient(int sessionFinishedState,
-            @Nullable ArrayList<AutofillId> autofillableIds) {
+    private void notifyUnavailableToClient(
+            int sessionFinishedState, @Nullable ArrayList<AutofillId> autofillableIds) {
         synchronized (mLock) {
             if (mCurrentViewId == null) return;
             try {
@@ -5374,27 +5939,25 @@
                 if (saveInfo.getRequiredIds() != null) {
                     Collections.addAll(trackedViews, saveInfo.getRequiredIds());
                     mSaveEventLogger.maybeSetSaveUiShownReason(
-                        SAVE_UI_SHOWN_REASON_REQUIRED_ID_CHANGE);
+                            SAVE_UI_SHOWN_REASON_REQUIRED_ID_CHANGE);
                 }
 
                 if (saveInfo.getOptionalIds() != null) {
                     Collections.addAll(trackedViews, saveInfo.getOptionalIds());
                     mSaveEventLogger.maybeSetSaveUiShownReason(
-                        SAVE_UI_SHOWN_REASON_OPTIONAL_ID_CHANGE);
+                            SAVE_UI_SHOWN_REASON_OPTIONAL_ID_CHANGE);
                 }
             }
             if ((flags & SaveInfo.FLAG_DONT_SAVE_ON_FINISH) != 0) {
-                mSaveEventLogger.maybeSetSaveUiShownReason(
-                    SAVE_UI_SHOWN_REASON_UNKNOWN);
+                mSaveEventLogger.maybeSetSaveUiShownReason(SAVE_UI_SHOWN_REASON_UNKNOWN);
                 mSaveEventLogger.maybeSetSaveUiNotShownReason(
-                    NO_SAVE_REASON_WITH_DONT_SAVE_ON_FINISH_FLAG);
+                        NO_SAVE_REASON_WITH_DONT_SAVE_ON_FINISH_FLAG);
                 saveOnFinish = false;
             }
 
         } else {
             flags = 0;
-            mSaveEventLogger.maybeSetSaveUiNotShownReason(
-                NO_SAVE_REASON_NO_SAVE_INFO);
+            mSaveEventLogger.maybeSetSaveUiNotShownReason(NO_SAVE_REASON_NO_SAVE_INFO);
             saveTriggerId = null;
         }
 
@@ -5427,21 +5990,35 @@
 
         try {
             if (sVerbose) {
-                Slog.v(TAG, "updateTrackedIdsLocked(): trackedViews: " + trackedViews
-                        + " fillableIds: " + fillableIds + " triggerId: " + saveTriggerId
-                        + " saveOnFinish:" + saveOnFinish + " flags: " + flags
-                        + " hasSaveInfo: " + (saveInfo != null));
+                Slog.v(
+                        TAG,
+                        "updateTrackedIdsLocked(): trackedViews: "
+                                + trackedViews
+                                + " fillableIds: "
+                                + fillableIds
+                                + " triggerId: "
+                                + saveTriggerId
+                                + " saveOnFinish:"
+                                + saveOnFinish
+                                + " flags: "
+                                + flags
+                                + " hasSaveInfo: "
+                                + (saveInfo != null));
             }
-            mClient.setTrackedViews(id, toArray(trackedViews), mSaveOnAllViewsInvisible,
-                    saveOnFinish, toArray(fillableIds), saveTriggerId, hasAuthentication);
+            mClient.setTrackedViews(
+                    id,
+                    toArray(trackedViews),
+                    mSaveOnAllViewsInvisible,
+                    saveOnFinish,
+                    toArray(fillableIds),
+                    saveTriggerId,
+                    hasAuthentication);
         } catch (RemoteException e) {
             Slog.w(TAG, "Cannot set tracked ids", e);
         }
     }
 
-    /**
-     * Sets the state of views that failed to autofill.
-     */
+    /** Sets the state of views that failed to autofill. */
     @GuardedBy("mLock")
     void setAutofillFailureLocked(@NonNull List<AutofillId> ids, boolean isRefill) {
         if (sVerbose && !ids.isEmpty()) {
@@ -5464,9 +6041,7 @@
         mPresentationStatsEventLogger.maybeSetViewFillFailureCounts(ids, isRefill);
     }
 
-    /**
-     * Sets the state of views that failed to autofill.
-     */
+    /** Sets the state of views that failed to autofill. */
     @GuardedBy("mLock")
     void setViewAutofilledLocked(@NonNull AutofillId id) {
         if (sVerbose) {
@@ -5478,17 +6053,14 @@
         mPresentationStatsEventLogger.maybeAddSuccessId(id);
     }
 
-    /**
-     * Sets the state of views that failed to autofill.
-     */
+    /** Sets the state of views that failed to autofill. */
     void setNotifyNotExpiringResponseDuringAuth() {
         synchronized (mLock) {
             mPresentationStatsEventLogger.maybeSetNotifyNotExpiringResponseDuringAuth();
         }
     }
-    /**
-     * Sets the state of views that failed to autofill.
-     */
+
+    /** Sets the state of views that failed to autofill. */
     void setLogViewEnteredIgnoredDuringAuth() {
         synchronized (mLock) {
             mPresentationStatsEventLogger.notifyViewEnteredIgnoredDuringAuthCount();
@@ -5496,10 +6068,15 @@
     }
 
     @GuardedBy("mLock")
-    private void replaceResponseLocked(@NonNull FillResponse oldResponse,
-            @NonNull FillResponse newResponse, @Nullable Bundle newClientState) {
+    private void replaceResponseLocked(
+            @NonNull FillResponse oldResponse,
+            @NonNull FillResponse newResponse,
+            @Nullable Bundle newClientState) {
         // Disassociate view states with the old response
-        setViewStatesLocked(oldResponse, ViewState.STATE_INITIAL, /* clearResponse= */ true,
+        setViewStatesLocked(
+                oldResponse,
+                ViewState.STATE_INITIAL,
+                /* clearResponse= */ true,
                 /* isPrimary= */ true);
         // Move over the id
         newResponse.setRequestId(oldResponse.getRequestId());
@@ -5519,7 +6096,7 @@
         final ArrayList<AutofillId> autofillableIds;
         if (context != null) {
             final AssistStructure structure = context.getStructure();
-            autofillableIds = Helper.getAutofillIds(structure, /* autofillableOnly= */true);
+            autofillableIds = Helper.getAutofillIds(structure, /* autofillableOnly= */ true);
         } else {
             Slog.w(TAG, "processNullResponseLocked(): no context for req " + requestId);
             autofillableIds = null;
@@ -5535,8 +6112,13 @@
         mAugmentedAutofillDestroyer = triggerAugmentedAutofillLocked(flags);
         if (mAugmentedAutofillDestroyer == null && ((flags & FLAG_PASSWORD_INPUT_TYPE) == 0)) {
             if (sVerbose) {
-                Slog.v(TAG, "canceling session " + id + " when service returned null and it cannot "
-                        + "be augmented. AutofillableIds: " + autofillableIds);
+                Slog.v(
+                        TAG,
+                        "canceling session "
+                                + id
+                                + " when service returned null and it cannot "
+                                + "be augmented. AutofillableIds: "
+                                + autofillableIds);
             }
             // Nothing to be done, but need to notify client.
             notifyUnavailableToClient(AutofillManager.STATE_FINISHED, autofillableIds);
@@ -5544,15 +6126,25 @@
         } else {
             if ((flags & FLAG_PASSWORD_INPUT_TYPE) != 0) {
                 if (sVerbose) {
-                    Slog.v(TAG, "keeping session " + id + " when service returned null and "
-                            + "augmented service is disabled for password fields. "
-                            + "AutofillableIds: " + autofillableIds);
+                    Slog.v(
+                            TAG,
+                            "keeping session "
+                                    + id
+                                    + " when service returned null and "
+                                    + "augmented service is disabled for password fields. "
+                                    + "AutofillableIds: "
+                                    + autofillableIds);
                 }
                 mInlineSessionController.hideInlineSuggestionsUiLocked(mCurrentViewId);
             } else {
                 if (sVerbose) {
-                    Slog.v(TAG, "keeping session " + id + " when service returned null but "
-                            + "it can be augmented. AutofillableIds: " + autofillableIds);
+                    Slog.v(
+                            TAG,
+                            "keeping session "
+                                    + id
+                                    + " when service returned null but "
+                                    + "it can be augmented. AutofillableIds: "
+                                    + autofillableIds);
                 }
             }
             mAugmentedAutofillableIds = autofillableIds;
@@ -5567,8 +6159,8 @@
     /**
      * Tries to trigger Augmented Autofill when the standard service could not fulfill a request.
      *
-     * <p> The request may not have been sent when this method returns as it may be waiting for
-     * the inline suggestion request asynchronously.
+     * <p>The request may not have been sent when this method returns as it may be waiting for the
+     * inline suggestion request asynchronously.
      *
      * @return callback to destroy the autofill UI, or {@code null} if not supported.
      */
@@ -5582,8 +6174,8 @@
         }
 
         // Check if Smart Suggestions is supported...
-        final @SmartSuggestionMode int supportedModes = mService
-                .getSupportedSmartSuggestionModesLocked();
+        final @SmartSuggestionMode int supportedModes =
+                mService.getSupportedSmartSuggestionModesLocked();
         if (supportedModes == 0) {
             if (sVerbose) Slog.v(TAG, "triggerAugmentedAutofillLocked(): no supported modes");
             return null;
@@ -5591,8 +6183,8 @@
 
         // ...then if the service is set for the user
 
-        final RemoteAugmentedAutofillService remoteService = mService
-                .getRemoteAugmentedAutofillServiceLocked();
+        final RemoteAugmentedAutofillService remoteService =
+                mService.getRemoteAugmentedAutofillServiceLocked();
         if (remoteService == null) {
             if (sVerbose) Slog.v(TAG, "triggerAugmentedAutofillLocked(): no service for user");
             return null;
@@ -5612,25 +6204,37 @@
             return null;
         }
 
-        final boolean isAllowlisted = mService
-                .isWhitelistedForAugmentedAutofillLocked(mComponentName);
+        final boolean isAllowlisted =
+                mService.isWhitelistedForAugmentedAutofillLocked(mComponentName);
 
         if (!isAllowlisted) {
             if (sVerbose) {
-                Slog.v(TAG, "triggerAugmentedAutofillLocked(): "
-                        + ComponentName.flattenToShortString(mComponentName) + " not whitelisted ");
+                Slog.v(
+                        TAG,
+                        "triggerAugmentedAutofillLocked(): "
+                                + ComponentName.flattenToShortString(mComponentName)
+                                + " not whitelisted ");
             }
-            logAugmentedAutofillRequestLocked(mode, remoteService.getComponentName(),
-                    mCurrentViewId, isAllowlisted, /* isInline= */ null);
+            logAugmentedAutofillRequestLocked(
+                    mode,
+                    remoteService.getComponentName(),
+                    mCurrentViewId,
+                    isAllowlisted,
+                    /* isInline= */ null);
             return null;
         }
 
         if (sVerbose) {
-            Slog.v(TAG, "calling Augmented Autofill Service ("
-                    + ComponentName.flattenToShortString(remoteService.getComponentName())
-                    + ") on view " + mCurrentViewId + " using suggestion mode "
-                    + getSmartSuggestionModeToString(mode)
-                    + " when server returned null for session " + this.id);
+            Slog.v(
+                    TAG,
+                    "calling Augmented Autofill Service ("
+                            + ComponentName.flattenToShortString(remoteService.getComponentName())
+                            + ") on view "
+                            + mCurrentViewId
+                            + " using suggestion mode "
+                            + getSmartSuggestionModeToString(mode)
+                            + " when server returned null for session "
+                            + this.id);
         }
         // Log FillRequest for Augmented Autofill.
         mFillRequestEventLogger.startLogForNewRequest();
@@ -5648,8 +6252,10 @@
         if (mAugmentedRequestsLogs == null) {
             mAugmentedRequestsLogs = new ArrayList<>();
         }
-        final LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_AUGMENTED_REQUEST,
-                remoteService.getComponentName().getPackageName());
+        final LogMaker log =
+                newLogMaker(
+                        MetricsEvent.AUTOFILL_AUGMENTED_REQUEST,
+                        remoteService.getComponentName().getPackageName());
         mAugmentedRequestsLogs.add(log);
 
         final AutofillId focusedId = mCurrentViewId;
@@ -5715,8 +6321,7 @@
             }
             synchronized (session.mLock) {
                 session.mInlineSessionController.onCreateInlineSuggestionsRequestLocked(
-                        mFocusedId, /*requestConsumer=*/ mRequestAugmentedAutofill,
-                        result);
+                        mFocusedId, /* requestConsumer= */ mRequestAugmentedAutofill, result);
             }
         }
     }
@@ -5741,19 +6346,17 @@
             mIsAllowlisted = isAllowlisted;
             mMode = mode;
             mCurrentValue = currentValue;
-
         }
+
         @Override
         public void accept(InlineSuggestionsRequest inlineSuggestionsRequest) {
             Session session = mSessionWeakRef.get();
 
-            if (logIfSessionNull(
-                    session, "AugmentedAutofillInlineSuggestionRequestConsumer:")) {
+            if (logIfSessionNull(session, "AugmentedAutofillInlineSuggestionRequestConsumer:")) {
                 return;
             }
             session.onAugmentedAutofillInlineSuggestionAccept(
                     inlineSuggestionsRequest, mFocusedId, mIsAllowlisted, mMode, mCurrentValue);
-
         }
     }
 
@@ -5770,8 +6373,7 @@
         public Boolean apply(InlineFillUi inlineFillUi) {
             Session session = mSessionWeakRef.get();
 
-            if (logIfSessionNull(
-                    session, "AugmentedAutofillInlineSuggestionsResponseCallback:")) {
+            if (logIfSessionNull(session, "AugmentedAutofillInlineSuggestionsResponseCallback:")) {
                 return false;
             }
 
@@ -5801,8 +6403,9 @@
     }
 
     /**
-     * If the session is null or has been destroyed, log the error msg, and return true.
-     * This is a helper function intended to be called when de-referencing from a weak reference.
+     * If the session is null or has been destroyed, log the error msg, and return true. This is a
+     * helper function intended to be called when de-referencing from a weak reference.
+     *
      * @param session
      * @param logPrefix
      * @return true if the session is null, false otherwise.
@@ -5830,15 +6433,25 @@
         synchronized (mLock) {
             final RemoteAugmentedAutofillService remoteService =
                     mService.getRemoteAugmentedAutofillServiceLocked();
-            logAugmentedAutofillRequestLocked(mode, remoteService.getComponentName(),
-                    focussedId, isAllowlisted, inlineSuggestionsRequest != null);
-            remoteService.onRequestAutofillLocked(id, mClient,
-                    taskId, mComponentName, mActivityToken,
-                    AutofillId.withoutSession(focussedId), currentValue,
+            logAugmentedAutofillRequestLocked(
+                    mode,
+                    remoteService.getComponentName(),
+                    focussedId,
+                    isAllowlisted,
+                    inlineSuggestionsRequest != null);
+            remoteService.onRequestAutofillLocked(
+                    id,
+                    mClient,
+                    taskId,
+                    mComponentName,
+                    mActivityToken,
+                    AutofillId.withoutSession(focussedId),
+                    currentValue,
                     inlineSuggestionsRequest,
                     new AugmentedAutofillInlineSuggestionsResponseCallback(this),
                     new AugmentedAutofillErrorCallback(this),
-                    mService.getRemoteInlineSuggestionRenderServiceLocked(), userId);
+                    mService.getRemoteInlineSuggestionRenderServiceLocked(),
+                    userId);
         }
     }
 
@@ -5847,15 +6460,14 @@
             cancelAugmentedAutofillLocked();
 
             // Also cancel augmented in IME
-            mInlineSessionController.setInlineFillUiLocked(
-                    InlineFillUi.emptyUi(mCurrentViewId));
+            mInlineSessionController.setInlineFillUiLocked(InlineFillUi.emptyUi(mCurrentViewId));
         }
     }
 
     @GuardedBy("mLock")
     private void cancelAugmentedAutofillLocked() {
-        final RemoteAugmentedAutofillService remoteService = mService
-                .getRemoteAugmentedAutofillServiceLocked();
+        final RemoteAugmentedAutofillService remoteService =
+                mService.getRemoteAugmentedAutofillServiceLocked();
         if (remoteService == null) {
             Slog.w(TAG, "cancelAugmentedAutofillLocked(): no service for user");
             return;
@@ -5865,8 +6477,8 @@
     }
 
     @GuardedBy("mLock")
-    private void processResponseLocked(@NonNull FillResponse newResponse,
-            @Nullable Bundle newClientState, int flags) {
+    private void processResponseLocked(
+            @NonNull FillResponse newResponse, @Nullable Bundle newClientState, int flags) {
         // Make sure we are hiding the UI which will be shown
         // only if handling the current response requires it.
         mUi.hideAll(this);
@@ -5878,9 +6490,18 @@
 
         final int requestId = newResponse.getRequestId();
         if (sVerbose) {
-            Slog.v(TAG, "processResponseLocked(): mCurrentViewId=" + mCurrentViewId
-                    + ",flags=" + flags + ", reqId=" + requestId + ", resp=" + newResponse
-                    + ",newClientState=" + newClientState);
+            Slog.v(
+                    TAG,
+                    "processResponseLocked(): mCurrentViewId="
+                            + mCurrentViewId
+                            + ",flags="
+                            + flags
+                            + ", reqId="
+                            + requestId
+                            + ", resp="
+                            + newResponse
+                            + ",newClientState="
+                            + newClientState);
         }
 
         if (mResponses == null) {
@@ -5892,8 +6513,9 @@
         mResponses.put(requestId, newResponse);
         mClientState = newClientState != null ? newClientState : newResponse.getClientState();
 
-        boolean webviewRequestedCredman = newClientState != null && newClientState.getBoolean(
-                WEBVIEW_REQUESTED_CREDENTIAL_KEY, false);
+        boolean webviewRequestedCredman =
+                newClientState != null
+                        && newClientState.getBoolean(WEBVIEW_REQUESTED_CREDENTIAL_KEY, false);
         List<Dataset> datasetList = newResponse.getDatasets();
 
         mPresentationStatsEventLogger.maybeSetWebviewRequestedCredential(webviewRequestedCredman);
@@ -5901,7 +6523,10 @@
         mPresentationStatsEventLogger.maybeSetAvailableCount(datasetList, mCurrentViewId);
         mFillResponseEventLogger.maybeSetDatasetsCountAfterPotentialPccFiltering(datasetList);
 
-        setViewStatesLocked(newResponse, ViewState.STATE_FILLABLE, /* clearResponse= */ false,
+        setViewStatesLocked(
+                newResponse,
+                ViewState.STATE_FILLABLE,
+                /* clearResponse= */ false,
                 /* isPrimary= */ true);
         updateFillDialogTriggerIdsLocked();
         updateTrackedIdsLocked();
@@ -5914,12 +6539,10 @@
         currentView.maybeCallOnFillReady(flags);
     }
 
-    /**
-     * Sets the state of all views in the given response.
-     */
+    /** Sets the state of all views in the given response. */
     @GuardedBy("mLock")
-    private void setViewStatesLocked(FillResponse response, int state, boolean clearResponse,
-                                     boolean isPrimary) {
+    private void setViewStatesLocked(
+            FillResponse response, int state, boolean clearResponse, boolean isPrimary) {
         final List<Dataset> datasets = response.getDatasets();
         if (datasets != null && !datasets.isEmpty()) {
             for (int i = 0; i < datasets.size(); i++) {
@@ -5964,12 +6587,14 @@
         }
     }
 
-    /**
-     * Sets the state and response of all views in the given dataset.
-     */
+    /** Sets the state and response of all views in the given dataset. */
     @GuardedBy("mLock")
-    private void setViewStatesLocked(@Nullable FillResponse response, @NonNull Dataset dataset,
-            int state, boolean clearResponse, boolean isPrimary) {
+    private void setViewStatesLocked(
+            @Nullable FillResponse response,
+            @NonNull Dataset dataset,
+            int state,
+            boolean clearResponse,
+            boolean isPrimary) {
         final ArrayList<AutofillId> ids = dataset.getFieldIds();
         final ArrayList<AutofillValue> values = dataset.getFieldValues();
         for (int j = 0; j < ids.size(); j++) {
@@ -5989,10 +6614,10 @@
     }
 
     @GuardedBy("mLock")
-    private ViewState createOrUpdateViewStateLocked(@NonNull AutofillId id, int state,
-            @Nullable AutofillValue value) {
+    private ViewState createOrUpdateViewStateLocked(
+            @NonNull AutofillId id, int state, @Nullable AutofillValue value) {
         ViewState viewState = mViewStates.get(id);
-        if (viewState != null)  {
+        if (viewState != null) {
             viewState.setState(state);
         } else {
             viewState = new ViewState(id, this, state, mIsPrimaryCredential);
@@ -6008,22 +6633,27 @@
         return viewState;
     }
 
-    void autoFill(int requestId, int datasetIndex, Dataset dataset, boolean generateEvent,
-            int uiType) {
+    void autoFill(
+            int requestId, int datasetIndex, Dataset dataset, boolean generateEvent, int uiType) {
         if (sDebug) {
-            Slog.d(TAG, "autoFill(): requestId=" + requestId  + "; datasetIdx=" + datasetIndex
-                    + "; dataset=" + dataset);
+            Slog.d(
+                    TAG,
+                    "autoFill(): requestId="
+                            + requestId
+                            + "; datasetIdx="
+                            + datasetIndex
+                            + "; dataset="
+                            + dataset);
         }
         synchronized (mLock) {
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#autoFill() rejected - session: "
-                        + id + " destroyed");
+                Slog.w(TAG, "Call to Session#autoFill() rejected - session: " + id + " destroyed");
                 return;
             }
             // Selected dataset id is logged regardless of authentication result.
             mPresentationStatsEventLogger.maybeSetSelectedDatasetId(datasetIndex);
             mPresentationStatsEventLogger.maybeSetSelectedDatasetPickReason(
-                dataset.getEligibleReason());
+                    dataset.getEligibleReason());
             // Autofill it directly...
             if (dataset.getAuthentication() == null) {
                 if (generateEvent) {
@@ -6039,10 +6669,14 @@
             // ...or handle authentication.
             mService.logDatasetAuthenticationSelected(dataset.getId(), id, mClientState, uiType);
             mPresentationStatsEventLogger.maybeSetAuthenticationType(
-                AUTHENTICATION_TYPE_DATASET_AUTHENTICATION);
+                    AUTHENTICATION_TYPE_DATASET_AUTHENTICATION);
             // does not matter the value of isPrimary because null response won't be overridden.
-            setViewStatesLocked(null, dataset, ViewState.STATE_WAITING_DATASET_AUTH,
-                    /* clearResponse= */ false, /* isPrimary= */ true);
+            setViewStatesLocked(
+                    null,
+                    dataset,
+                    ViewState.STATE_WAITING_DATASET_AUTH,
+                    /* clearResponse= */ false,
+                    /* isPrimary= */ true);
             final Intent fillInIntent;
             if (dataset.getCredentialFillInIntent() != null && Flags.autofillCredmanIntegration()) {
                 Slog.d(TAG, "Setting credential fill intent");
@@ -6055,11 +6689,13 @@
                 forceRemoveFromServiceLocked();
                 return;
             }
-            final int authenticationId = AutofillManager.makeAuthenticationId(requestId,
-                    datasetIndex);
-            startAuthentication(authenticationId, dataset.getAuthentication(), fillInIntent,
-                    /* authenticateInline= */false);
-
+            final int authenticationId =
+                    AutofillManager.makeAuthenticationId(requestId, datasetIndex);
+            startAuthentication(
+                    authenticationId,
+                    dataset.getAuthentication(),
+                    fillInIntent,
+                    /* authenticateInline= */ false);
         }
     }
 
@@ -6072,13 +6708,17 @@
         final FillContext context = getFillContextByRequestIdLocked(requestId);
 
         if (context == null) {
-            wtf(null, "createAuthFillInIntentLocked(): no FillContext. requestId=%d; mContexts=%s",
-                    requestId, mContexts);
+            wtf(
+                    null,
+                    "createAuthFillInIntentLocked(): no FillContext. requestId=%d; mContexts=%s",
+                    requestId,
+                    mContexts);
             return null;
         }
         if (mLastInlineSuggestionsRequest != null
                 && mLastInlineSuggestionsRequest.first == requestId) {
-            fillInIntent.putExtra(AutofillManager.EXTRA_INLINE_SUGGESTIONS_REQUEST,
+            fillInIntent.putExtra(
+                    AutofillManager.EXTRA_INLINE_SUGGESTIONS_REQUEST,
                     mLastInlineSuggestionsRequest.second);
         }
         fillInIntent.putExtra(AutofillManager.EXTRA_ASSIST_STRUCTURE, context.getStructure());
@@ -6121,12 +6761,15 @@
         }
     }
 
-    private void startAuthentication(int authenticationId, IntentSender intent,
-            Intent fillInIntent, boolean authenticateInline) {
+    private void startAuthentication(
+            int authenticationId,
+            IntentSender intent,
+            Intent fillInIntent,
+            boolean authenticateInline) {
         try {
             synchronized (mLock) {
-                mClient.authenticate(id, authenticationId, intent, fillInIntent,
-                        authenticateInline);
+                mClient.authenticate(
+                        id, authenticationId, intent, fillInIntent, authenticateInline);
             }
         } catch (RemoteException e) {
             Slog.e(TAG, "Error launching auth intent", e);
@@ -6139,22 +6782,18 @@
      * @hide
      */
     static final class SaveResult {
-        /**
-         * Whether to record the save dialog has been shown.
-         */
+        /** Whether to record the save dialog has been shown. */
         private boolean mLogSaveShown;
 
-        /**
-         * Whether to remove the session.
-         */
+        /** Whether to remove the session. */
         private boolean mRemoveSession;
 
-        /**
-         * The reason why a save dialog was not shown.
-         */
+        /** The reason why a save dialog was not shown. */
         @NoSaveReason private int mSaveDialogNotShowReason;
 
-        SaveResult(boolean logSaveShown, boolean removeSession,
+        SaveResult(
+                boolean logSaveShown,
+                boolean removeSession,
                 @NoSaveReason int saveDialogNotShowReason) {
             mLogSaveShown = logSaveShown;
             mRemoveSession = removeSession;
@@ -6218,15 +6857,19 @@
 
         @Override
         public String toString() {
-            return "SaveResult: [logSaveShown=" + mLogSaveShown
-                    + ", removeSession=" + mRemoveSession
-                    + ", saveDialogNotShowReason=" + mSaveDialogNotShowReason + "]";
+            return "SaveResult: [logSaveShown="
+                    + mLogSaveShown
+                    + ", removeSession="
+                    + mRemoveSession
+                    + ", saveDialogNotShowReason="
+                    + mSaveDialogNotShowReason
+                    + "]";
         }
     }
 
     /**
-     * Class maintaining the state of the requests to
-     * {@link android.service.assist.classification.FieldClassificationService}.
+     * Class maintaining the state of the requests to {@link
+     * android.service.assist.classification.FieldClassificationService}.
      */
     private static final class ClassificationState {
 
@@ -6234,18 +6877,16 @@
          * Initial state indicating that the request for classification hasn't been triggered yet.
          */
         private static final int STATE_INITIAL = 1;
-        /**
-         * Assist request has been triggered, but awaiting response.
-         */
+
+        /** Assist request has been triggered, but awaiting response. */
         private static final int STATE_PENDING_ASSIST_REQUEST = 2;
-        /**
-         * Classification request has been triggered, but awaiting response.
-         */
+
+        /** Classification request has been triggered, but awaiting response. */
         private static final int STATE_PENDING_REQUEST = 3;
-        /**
-         * Classification response has been received.
-         */
+
+        /** Classification response has been received. */
         private static final int STATE_RESPONSE = 4;
+
         /**
          * Classification state has been invalidated, and the last response may no longer be valid.
          * This could occur due to various reasons like views changing their layouts, becoming
@@ -6254,15 +6895,17 @@
          */
         private static final int STATE_INVALIDATED = 5;
 
-        @IntDef(prefix = { "STATE_" }, value = {
-                STATE_INITIAL,
-                STATE_PENDING_ASSIST_REQUEST,
-                STATE_PENDING_REQUEST,
-                STATE_RESPONSE,
-                STATE_INVALIDATED
-        })
+        @IntDef(
+                prefix = {"STATE_"},
+                value = {
+                    STATE_INITIAL,
+                    STATE_PENDING_ASSIST_REQUEST,
+                    STATE_PENDING_REQUEST,
+                    STATE_RESPONSE,
+                    STATE_INVALIDATED
+                })
         @Retention(RetentionPolicy.SOURCE)
-        @interface ClassificationRequestState{}
+        @interface ClassificationRequestState {}
 
         @GuardedBy("mLock")
         private @ClassificationRequestState int mState = STATE_INITIAL;
@@ -6284,8 +6927,8 @@
 
         /**
          * Typically, there would be a 1:1 mapping. However, in certain cases, we may have a hint
-         * being applicable to many types. An example of this being new/change password forms,
-         * where you need to confirm the passward twice.
+         * being applicable to many types. An example of this being new/change password forms, where
+         * you need to confirm the passward twice.
          */
         @GuardedBy("mLock")
         private ArrayMap<String, Set<AutofillId>> mHintsToAutofillIdMap;
@@ -6317,8 +6960,9 @@
 
         /**
          * Process the response received.
+         *
          * @return true if the response was processed, false otherwise. If there wasn't any
-         * response, yet this function was called, it would return false.
+         *     response, yet this function was called, it would return false.
          */
         @GuardedBy("mLock")
         private boolean processResponse() {
@@ -6358,7 +7002,9 @@
         }
 
         @GuardedBy("mLock")
-        private static void processDetections(Set<String> detections, AutofillId id,
+        private static void processDetections(
+                Set<String> detections,
+                AutofillId id,
                 ArrayMap<String, Set<AutofillId>> currentMap) {
             for (String detection : detections) {
                 Set<AutofillId> autofillIds;
@@ -6416,37 +7062,67 @@
         @Override
         public String toString() {
             return "ClassificationState: ["
-                    + "state=" + stateToString()
-                    + ", mPendingFieldClassificationRequest=" + mPendingFieldClassificationRequest
-                    + ", mLastFieldClassificationResponse=" + mLastFieldClassificationResponse
-                    + ", mClassificationHintsMap=" + mClassificationHintsMap
-                    + ", mClassificationGroupHintsMap=" + mClassificationGroupHintsMap
-                    + ", mHintsToAutofillIdMap=" + mHintsToAutofillIdMap
-                    + ", mGroupHintsToAutofillIdMap=" + mGroupHintsToAutofillIdMap
+                    + "state="
+                    + stateToString()
+                    + ", mPendingFieldClassificationRequest="
+                    + mPendingFieldClassificationRequest
+                    + ", mLastFieldClassificationResponse="
+                    + mLastFieldClassificationResponse
+                    + ", mClassificationHintsMap="
+                    + mClassificationHintsMap
+                    + ", mClassificationGroupHintsMap="
+                    + mClassificationGroupHintsMap
+                    + ", mHintsToAutofillIdMap="
+                    + mHintsToAutofillIdMap
+                    + ", mGroupHintsToAutofillIdMap="
+                    + mGroupHintsToAutofillIdMap
                     + "]";
         }
-
     }
 
     @Override
     public String toString() {
-        return "Session: [id=" + id + ", component=" + mComponentName
-                + ", state=" + sessionStateAsString(mSessionState) + "]";
+        return "Session: [id="
+                + id
+                + ", component="
+                + mComponentName
+                + ", state="
+                + sessionStateAsString(mSessionState)
+                + "]";
     }
 
     @GuardedBy("mLock")
     void dumpLocked(String prefix, PrintWriter pw) {
         final String prefix2 = prefix + "  ";
-        pw.print(prefix); pw.print("id: "); pw.println(id);
-        pw.print(prefix); pw.print("uid: "); pw.println(uid);
-        pw.print(prefix); pw.print("taskId: "); pw.println(taskId);
-        pw.print(prefix); pw.print("flags: "); pw.println(mFlags);
-        pw.print(prefix); pw.print("displayId: "); pw.println(mContext.getDisplayId());
-        pw.print(prefix); pw.print("state: "); pw.println(sessionStateAsString(mSessionState));
-        pw.print(prefix); pw.print("mComponentName: "); pw.println(mComponentName);
-        pw.print(prefix); pw.print("mActivityToken: "); pw.println(mActivityToken);
-        pw.print(prefix); pw.print("mStartTime: "); pw.println(mStartTime);
-        pw.print(prefix); pw.print("Time to show UI: ");
+        pw.print(prefix);
+        pw.print("id: ");
+        pw.println(id);
+        pw.print(prefix);
+        pw.print("uid: ");
+        pw.println(uid);
+        pw.print(prefix);
+        pw.print("taskId: ");
+        pw.println(taskId);
+        pw.print(prefix);
+        pw.print("flags: ");
+        pw.println(mFlags);
+        pw.print(prefix);
+        pw.print("displayId: ");
+        pw.println(mContext.getDisplayId());
+        pw.print(prefix);
+        pw.print("state: ");
+        pw.println(sessionStateAsString(mSessionState));
+        pw.print(prefix);
+        pw.print("mComponentName: ");
+        pw.println(mComponentName);
+        pw.print(prefix);
+        pw.print("mActivityToken: ");
+        pw.println(mActivityToken);
+        pw.print(prefix);
+        pw.print("mStartTime: ");
+        pw.println(mStartTime);
+        pw.print(prefix);
+        pw.print("Time to show UI: ");
         if (mUiShownTime == 0) {
             pw.println("N/A");
         } else {
@@ -6454,41 +7130,67 @@
             pw.println();
         }
         final int requestLogsSizes = mRequestLogs.size();
-        pw.print(prefix); pw.print("mSessionLogs: "); pw.println(requestLogsSizes);
+        pw.print(prefix);
+        pw.print("mSessionLogs: ");
+        pw.println(requestLogsSizes);
         for (int i = 0; i < requestLogsSizes; i++) {
             final int requestId = mRequestLogs.keyAt(i);
             final LogMaker log = mRequestLogs.valueAt(i);
-            pw.print(prefix2); pw.print('#'); pw.print(i); pw.print(": req=");
-            pw.print(requestId); pw.print(", log=" ); dumpRequestLog(pw, log); pw.println();
+            pw.print(prefix2);
+            pw.print('#');
+            pw.print(i);
+            pw.print(": req=");
+            pw.print(requestId);
+            pw.print(", log=");
+            dumpRequestLog(pw, log);
+            pw.println();
         }
-        pw.print(prefix); pw.print("mResponses: ");
+        pw.print(prefix);
+        pw.print("mResponses: ");
         if (mResponses == null) {
             pw.println("null");
         } else {
             pw.println(mResponses.size());
             for (int i = 0; i < mResponses.size(); i++) {
-                pw.print(prefix2); pw.print('#'); pw.print(i);
-                pw.print(' '); pw.println(mResponses.valueAt(i));
+                pw.print(prefix2);
+                pw.print('#');
+                pw.print(i);
+                pw.print(' ');
+                pw.println(mResponses.valueAt(i));
             }
         }
-        pw.print(prefix); pw.print("mCurrentViewId: "); pw.println(mCurrentViewId);
-        pw.print(prefix); pw.print("mDestroyed: "); pw.println(mDestroyed);
-        pw.print(prefix); pw.print("mShowingSaveUi: "); pw.println(mSessionFlags.mShowingSaveUi);
-        pw.print(prefix); pw.print("mPendingSaveUi: "); pw.println(mPendingSaveUi);
+        pw.print(prefix);
+        pw.print("mCurrentViewId: ");
+        pw.println(mCurrentViewId);
+        pw.print(prefix);
+        pw.print("mDestroyed: ");
+        pw.println(mDestroyed);
+        pw.print(prefix);
+        pw.print("mShowingSaveUi: ");
+        pw.println(mSessionFlags.mShowingSaveUi);
+        pw.print(prefix);
+        pw.print("mPendingSaveUi: ");
+        pw.println(mPendingSaveUi);
         final int numberViews = mViewStates.size();
-        pw.print(prefix); pw.print("mViewStates size: "); pw.println(mViewStates.size());
+        pw.print(prefix);
+        pw.print("mViewStates size: ");
+        pw.println(mViewStates.size());
         for (int i = 0; i < numberViews; i++) {
-            pw.print(prefix); pw.print("ViewState at #"); pw.println(i);
+            pw.print(prefix);
+            pw.print("ViewState at #");
+            pw.println(i);
             mViewStates.valueAt(i).dump(prefix2, pw);
         }
 
-        pw.print(prefix); pw.print("mContexts: " );
+        pw.print(prefix);
+        pw.print("mContexts: ");
         if (mContexts != null) {
             int numContexts = mContexts.size();
             for (int i = 0; i < numContexts; i++) {
                 FillContext context = mContexts.get(i);
 
-                pw.print(prefix2); pw.print(context);
+                pw.print(prefix2);
+                pw.print(context);
                 if (sVerbose) {
                     pw.println("AssistStructure dumped at logcat)");
 
@@ -6500,43 +7202,62 @@
             pw.println("null");
         }
 
-        pw.print(prefix); pw.print("mHasCallback: "); pw.println(mHasCallback);
+        pw.print(prefix);
+        pw.print("mHasCallback: ");
+        pw.println(mHasCallback);
         if (mClientState != null) {
-            pw.print(prefix); pw.print("mClientState: "); pw.print(mClientState.getSize()); pw
-                .println(" bytes");
+            pw.print(prefix);
+            pw.print("mClientState: ");
+            pw.print(mClientState.getSize());
+            pw.println(" bytes");
         }
-        pw.print(prefix); pw.print("mCompatMode: "); pw.println(mCompatMode);
-        pw.print(prefix); pw.print("mUrlBar: ");
+        pw.print(prefix);
+        pw.print("mCompatMode: ");
+        pw.println(mCompatMode);
+        pw.print(prefix);
+        pw.print("mUrlBar: ");
         if (mUrlBar == null) {
             pw.println("N/A");
         } else {
-            pw.print("id="); pw.print(mUrlBar.getAutofillId());
-            pw.print(" domain="); pw.print(mUrlBar.getWebDomain());
-            pw.print(" text="); Helper.printlnRedactedText(pw, mUrlBar.getText());
+            pw.print("id=");
+            pw.print(mUrlBar.getAutofillId());
+            pw.print(" domain=");
+            pw.print(mUrlBar.getWebDomain());
+            pw.print(" text=");
+            Helper.printlnRedactedText(pw, mUrlBar.getText());
         }
-        pw.print(prefix); pw.print("mSaveOnAllViewsInvisible: "); pw.println(
-                mSaveOnAllViewsInvisible);
-        pw.print(prefix); pw.print("mSelectedDatasetIds: "); pw.println(mSelectedDatasetIds);
+        pw.print(prefix);
+        pw.print("mSaveOnAllViewsInvisible: ");
+        pw.println(mSaveOnAllViewsInvisible);
+        pw.print(prefix);
+        pw.print("mSelectedDatasetIds: ");
+        pw.println(mSelectedDatasetIds);
         if (mSessionFlags.mAugmentedAutofillOnly) {
-            pw.print(prefix); pw.println("For Augmented Autofill Only");
+            pw.print(prefix);
+            pw.println("For Augmented Autofill Only");
         }
         if (mSessionFlags.mFillDialogDisabled) {
-            pw.print(prefix); pw.println("Fill Dialog disabled");
+            pw.print(prefix);
+            pw.println("Fill Dialog disabled");
         }
         if (mLastFillDialogTriggerIds != null) {
-            pw.print(prefix); pw.println("Last Fill Dialog trigger ids: ");
+            pw.print(prefix);
+            pw.println("Last Fill Dialog trigger ids: ");
             pw.println(mSelectedDatasetIds);
         }
         if (mAugmentedAutofillDestroyer != null) {
-            pw.print(prefix); pw.println("has mAugmentedAutofillDestroyer");
+            pw.print(prefix);
+            pw.println("has mAugmentedAutofillDestroyer");
         }
         if (mAugmentedRequestsLogs != null) {
-            pw.print(prefix); pw.print("number augmented requests: ");
+            pw.print(prefix);
+            pw.print("number augmented requests: ");
             pw.println(mAugmentedRequestsLogs.size());
         }
 
         if (mAugmentedAutofillableIds != null) {
-            pw.print(prefix); pw.print("mAugmentedAutofillableIds: ");
+            pw.print(prefix);
+            pw.print("mAugmentedAutofillableIds: ");
             pw.println(mAugmentedAutofillableIds);
         }
         if (mRemoteFillService != null) {
@@ -6545,21 +7266,32 @@
     }
 
     private static void dumpRequestLog(@NonNull PrintWriter pw, @NonNull LogMaker log) {
-        pw.print("CAT="); pw.print(log.getCategory());
+        pw.print("CAT=");
+        pw.print(log.getCategory());
         pw.print(", TYPE=");
         final int type = log.getType();
         switch (type) {
-            case MetricsEvent.TYPE_SUCCESS: pw.print("SUCCESS"); break;
-            case MetricsEvent.TYPE_FAILURE: pw.print("FAILURE"); break;
-            case MetricsEvent.TYPE_CLOSE: pw.print("CLOSE"); break;
-            default: pw.print("UNSUPPORTED");
+            case MetricsEvent.TYPE_SUCCESS:
+                pw.print("SUCCESS");
+                break;
+            case MetricsEvent.TYPE_FAILURE:
+                pw.print("FAILURE");
+                break;
+            case MetricsEvent.TYPE_CLOSE:
+                pw.print("CLOSE");
+                break;
+            default:
+                pw.print("UNSUPPORTED");
         }
-        pw.print('('); pw.print(type); pw.print(')');
-        pw.print(", PKG="); pw.print(log.getPackageName());
-        pw.print(", SERVICE="); pw.print(log
-                .getTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE));
-        pw.print(", ORDINAL="); pw.print(log
-                .getTaggedData(MetricsEvent.FIELD_AUTOFILL_REQUEST_ORDINAL));
+        pw.print('(');
+        pw.print(type);
+        pw.print(')');
+        pw.print(", PKG=");
+        pw.print(log.getPackageName());
+        pw.print(", SERVICE=");
+        pw.print(log.getTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE));
+        pw.print(", ORDINAL=");
+        pw.print(log.getTaggedData(MetricsEvent.FIELD_AUTOFILL_REQUEST_ORDINAL));
         dumpNumericValue(pw, log, "FLAGS", MetricsEvent.FIELD_AUTOFILL_FLAGS);
         dumpNumericValue(pw, log, "NUM_DATASETS", MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS);
         dumpNumericValue(pw, log, "UI_LATENCY", MetricsEvent.FIELD_AUTOFILL_DURATION);
@@ -6569,64 +7301,86 @@
             pw.print(", AUTH_STATUS=");
             switch (authStatus) {
                 case MetricsEvent.AUTOFILL_AUTHENTICATED:
-                    pw.print("AUTHENTICATED"); break;
+                    pw.print("AUTHENTICATED");
+                    break;
                 case MetricsEvent.AUTOFILL_DATASET_AUTHENTICATED:
-                    pw.print("DATASET_AUTHENTICATED"); break;
+                    pw.print("DATASET_AUTHENTICATED");
+                    break;
                 case MetricsEvent.AUTOFILL_INVALID_AUTHENTICATION:
-                    pw.print("INVALID_AUTHENTICATION"); break;
+                    pw.print("INVALID_AUTHENTICATION");
+                    break;
                 case MetricsEvent.AUTOFILL_INVALID_DATASET_AUTHENTICATION:
-                    pw.print("INVALID_DATASET_AUTHENTICATION"); break;
-                default: pw.print("UNSUPPORTED");
+                    pw.print("INVALID_DATASET_AUTHENTICATION");
+                    break;
+                default:
+                    pw.print("UNSUPPORTED");
             }
-            pw.print('('); pw.print(authStatus); pw.print(')');
+            pw.print('(');
+            pw.print(authStatus);
+            pw.print(')');
         }
-        dumpNumericValue(pw, log, "FC_IDS",
-                MetricsEvent.FIELD_AUTOFILL_NUM_FIELD_CLASSIFICATION_IDS);
-        dumpNumericValue(pw, log, "COMPAT_MODE",
-                MetricsEvent.FIELD_AUTOFILL_COMPAT_MODE);
+        dumpNumericValue(
+                pw, log, "FC_IDS", MetricsEvent.FIELD_AUTOFILL_NUM_FIELD_CLASSIFICATION_IDS);
+        dumpNumericValue(pw, log, "COMPAT_MODE", MetricsEvent.FIELD_AUTOFILL_COMPAT_MODE);
     }
 
-    private static void dumpNumericValue(@NonNull PrintWriter pw, @NonNull LogMaker log,
-            @NonNull String field, int tag) {
+    private static void dumpNumericValue(
+            @NonNull PrintWriter pw, @NonNull LogMaker log, @NonNull String field, int tag) {
         final int value = getNumericValue(log, tag);
         if (value != 0) {
-            pw.print(", "); pw.print(field); pw.print('='); pw.print(value);
+            pw.print(", ");
+            pw.print(field);
+            pw.print('=');
+            pw.print(value);
         }
     }
 
-    void sendCredentialManagerResponseToApp(@Nullable GetCredentialResponse response,
-            @Nullable GetCredentialException exception, @NonNull AutofillId viewId) {
+    void sendCredentialManagerResponseToApp(
+            @Nullable GetCredentialResponse response,
+            @Nullable GetCredentialException exception,
+            @NonNull AutofillId viewId) {
         synchronized (mLock) {
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#sendCredentialManagerResponseToApp() rejected "
-                        + "- session: " + id + " destroyed");
+                Slog.w(
+                        TAG,
+                        "Call to Session#sendCredentialManagerResponseToApp() rejected "
+                                + "- session: "
+                                + id
+                                + " destroyed");
                 return;
             }
             try {
                 final ViewState viewState = mViewStates.get(viewId);
                 if (mService.getMaster().getIsFillFieldsFromCurrentSessionOnly()
-                        && viewState != null && viewState.id.getSessionId() != id) {
+                        && viewState != null
+                        && viewState.id.getSessionId() != id) {
                     if (sVerbose) {
-                        Slog.v(TAG, "Skipping sending credential response to view: "
-                                + viewId + " as it isn't part of the current session: " + id);
+                        Slog.v(
+                                TAG,
+                                "Skipping sending credential response to view: "
+                                        + viewId
+                                        + " as it isn't part of the current session: "
+                                        + id);
                     }
                 }
                 if (exception != null) {
                     if (viewId.isVirtualInt()) {
-                        sendResponseToViewNode(viewId, /*response=*/ null, exception);
+                        sendResponseToViewNode(viewId, /* response= */ null, exception);
                     } else {
-                        mClient.onGetCredentialException(id, viewId, exception.getType(),
-                                exception.getMessage());
+                        mClient.onGetCredentialException(
+                                id, viewId, exception.getType(), exception.getMessage());
                     }
                 } else if (response != null) {
                     if (viewId.isVirtualInt()) {
-                        sendResponseToViewNode(viewId, response, /*exception=*/ null);
+                        sendResponseToViewNode(viewId, response, /* exception= */ null);
                     } else {
                         mClient.onGetCredentialResponse(id, viewId, response);
                     }
                 } else {
-                    Slog.w(TAG, "sendCredentialManagerResponseToApp called with null response"
-                            + "and exception");
+                    Slog.w(
+                            TAG,
+                            "sendCredentialManagerResponseToApp called with null response"
+                                    + "and exception");
                 }
             } catch (RemoteException e) {
                 Slog.w(TAG, "Error sending credential response to activity: " + e);
@@ -6635,23 +7389,20 @@
     }
 
     @GuardedBy("mLock")
-    private void sendResponseToViewNode(AutofillId viewId, GetCredentialResponse response,
-            GetCredentialException exception) {
+    private void sendResponseToViewNode(
+            AutofillId viewId, GetCredentialResponse response, GetCredentialException exception) {
         ViewNode viewNode = getViewNodeFromContextsLocked(viewId);
         if (viewNode != null && viewNode.getPendingCredentialCallback() != null) {
             Bundle resultData = new Bundle();
             if (response != null) {
                 resultData.putParcelable(
-                        CredentialProviderService.EXTRA_GET_CREDENTIAL_RESPONSE,
-                        response);
-                viewNode.getPendingCredentialCallback().send(SUCCESS_CREDMAN_SELECTOR,
-                        resultData);
+                        CredentialProviderService.EXTRA_GET_CREDENTIAL_RESPONSE, response);
+                viewNode.getPendingCredentialCallback().send(SUCCESS_CREDMAN_SELECTOR, resultData);
             } else if (exception != null) {
                 resultData.putStringArray(
                         CredentialProviderService.EXTRA_GET_CREDENTIAL_EXCEPTION,
                         new String[] {exception.getType(), exception.getMessage()});
-                viewNode.getPendingCredentialCallback().send(FAILURE_CREDMAN_SELECTOR,
-                        resultData);
+                viewNode.getPendingCredentialCallback().send(FAILURE_CREDMAN_SELECTOR, resultData);
             }
         } else {
             Slog.w(TAG, "View node not found after GetCredentialResponse");
@@ -6661,8 +7412,9 @@
     void autoFillApp(Dataset dataset) {
         synchronized (mLock) {
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#autoFillApp() rejected - session: "
-                        + id + " destroyed");
+                Slog.w(
+                        TAG,
+                        "Call to Session#autoFillApp() rejected - session: " + id + " destroyed");
                 return;
             }
             try {
@@ -6671,8 +7423,11 @@
                 final List<AutofillId> ids = new ArrayList<>(entryCount);
                 final List<AutofillValue> values = new ArrayList<>(entryCount);
                 boolean waitingDatasetAuth = false;
-                boolean hideHighlight = (entryCount == 1
-                        && dataset.getFieldIds().get(0).equals(mCurrentViewId));
+                boolean hideHighlight =
+                        highlightAutofillSingleField()
+                                ? false
+                                : (entryCount == 1
+                                        && dataset.getFieldIds().get(0).equals(mCurrentViewId));
                 // Count how many views are filtered because they are not in current session
                 int numOfViewsFiltered = 0;
                 for (int i = 0; i < entryCount; i++) {
@@ -6682,10 +7437,15 @@
                     final AutofillId viewId = dataset.getFieldIds().get(i);
                     final ViewState viewState = mViewStates.get(viewId);
                     if (mService.getMaster().getIsFillFieldsFromCurrentSessionOnly()
-                            && viewState != null && viewState.id.getSessionId() != id) {
+                            && viewState != null
+                            && viewState.id.getSessionId() != id) {
                         if (sVerbose) {
-                            Slog.v(TAG, "Skipping filling view: " +
-                                    viewId + " as it isn't part of the current session: " + id);
+                            Slog.v(
+                                    TAG,
+                                    "Skipping filling view: "
+                                            + viewId
+                                            + " as it isn't part of the current session: "
+                                            + id);
                         }
                         numOfViewsFiltered += 1;
                         continue;
@@ -6721,8 +7481,12 @@
                     }
                     // does not matter the value of isPrimary because null response won't be
                     // overridden.
-                    setViewStatesLocked(null, dataset, ViewState.STATE_AUTOFILLED,
-                            /* clearResponse= */ false, /* isPrimary= */ true);
+                    setViewStatesLocked(
+                            null,
+                            dataset,
+                            ViewState.STATE_AUTOFILLED,
+                            /* clearResponse= */ false,
+                            /* isPrimary= */ true);
                 }
             } catch (RemoteException e) {
                 Slog.w(TAG, "Error autofilling activity: " + e);
@@ -6750,7 +7514,7 @@
         mSessionCommittedEventLogger.maybeSetCommitReason(val);
         mSessionCommittedEventLogger.maybeSetRequestCount(mRequestCount);
         mSessionCommittedEventLogger.maybeSetSessionDurationMillis(
-            SystemClock.elapsedRealtime() - mStartTime);
+                SystemClock.elapsedRealtime() - mStartTime);
         mFillRequestEventLogger.logAndEndEvent();
         mFillResponseEventLogger.logAndEndEvent();
         mPresentationStatsEventLogger.logAndEndEvent("log all events");
@@ -6808,8 +7572,8 @@
             }
         }
 
-        final int totalAugmentedRequests = mAugmentedRequestsLogs == null ? 0
-                : mAugmentedRequestsLogs.size();
+        final int totalAugmentedRequests =
+                mAugmentedRequestsLogs == null ? 0 : mAugmentedRequestsLogs.size();
         if (totalAugmentedRequests > 0) {
             if (sVerbose) {
                 Slog.v(TAG, "destroyLocked(): logging " + totalRequests + " augmented requests");
@@ -6820,11 +7584,12 @@
             }
         }
 
-        final LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_SESSION_FINISHED)
-                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUMBER_REQUESTS, totalRequests);
+        final LogMaker log =
+                newLogMaker(MetricsEvent.AUTOFILL_SESSION_FINISHED)
+                        .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUMBER_REQUESTS, totalRequests);
         if (totalAugmentedRequests > 0) {
-            log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUMBER_AUGMENTED_REQUESTS,
-                    totalAugmentedRequests);
+            log.addTaggedData(
+                    MetricsEvent.FIELD_AUTOFILL_NUMBER_AUGMENTED_REQUESTS, totalAugmentedRequests);
         }
         if (mSessionFlags.mAugmentedAutofillOnly) {
             log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_AUGMENTED_ONLY, 1);
@@ -6846,8 +7611,12 @@
     @GuardedBy("mLock")
     void forceRemoveFromServiceIfForAugmentedOnlyLocked() {
         if (sVerbose) {
-            Slog.v(TAG, "forceRemoveFromServiceIfForAugmentedOnlyLocked(" + this.id + "): "
-                    + mSessionFlags.mAugmentedAutofillOnly);
+            Slog.v(
+                    TAG,
+                    "forceRemoveFromServiceIfForAugmentedOnlyLocked("
+                            + this.id
+                            + "): "
+                            + mSessionFlags.mAugmentedAutofillOnly);
         }
         if (!mSessionFlags.mAugmentedAutofillOnly) return;
 
@@ -6880,9 +7649,7 @@
         }
     }
 
-    /**
-     * Thread-safe version of {@link #removeFromServiceLocked()}.
-     */
+    /** Thread-safe version of {@link #removeFromServiceLocked()}. */
     private void removeFromService() {
         synchronized (mLock) {
             removeFromServiceLocked();
@@ -6897,8 +7664,11 @@
     void removeFromServiceLocked() {
         if (sVerbose) Slog.v(TAG, "removeFromServiceLocked(" + this.id + "): " + mPendingSaveUi);
         if (mDestroyed) {
-            Slog.w(TAG, "Call to Session#removeFromServiceLocked() rejected - session: "
-                    + id + " destroyed");
+            Slog.w(
+                    TAG,
+                    "Call to Session#removeFromServiceLocked() rejected - session: "
+                            + id
+                            + " destroyed");
             return;
         }
         if (isSaveUiPendingLocked()) {
@@ -6922,18 +7692,16 @@
     }
 
     /**
-     * Checks whether this session is hiding the Save UI to handle a custom description link for
-     * a specific {@code token} created by
-     * {@link PendingUi#PendingUi(IBinder, int, IAutoFillManagerClient)}.
+     * Checks whether this session is hiding the Save UI to handle a custom description link for a
+     * specific {@code token} created by {@link PendingUi#PendingUi(IBinder, int,
+     * IAutoFillManagerClient)}.
      */
     @GuardedBy("mLock")
     boolean isSaveUiPendingForTokenLocked(@NonNull IBinder token) {
         return isSaveUiPendingLocked() && token.equals(mPendingSaveUi.getToken());
     }
 
-    /**
-     * Checks whether this session is hiding the Save UI to handle a custom description link.
-     */
+    /** Checks whether this session is hiding the Save UI to handle a custom description link. */
     @GuardedBy("mLock")
     private boolean isSaveUiPendingLocked() {
         return mPendingSaveUi != null && mPendingSaveUi.getState() == PendingUi.STATE_PENDING;
@@ -6942,8 +7710,8 @@
     // Return latest response index in mResponses SparseArray.
     @GuardedBy("mLock")
     private int getLastResponseIndexLocked() {
-        if (mResponses == null  || mResponses.size() == 0) {
-          return -1;
+        if (mResponses == null || mResponses.size() == 0) {
+            return -1;
         }
         List<Integer> requestIdList = new ArrayList<>();
         final int responseCount = mResponses.size();
@@ -6967,15 +7735,16 @@
 
     @GuardedBy("mLock")
     private void logAuthenticationStatusLocked(int requestId, int status) {
-        addTaggedDataToRequestLogLocked(requestId,
-                MetricsEvent.FIELD_AUTOFILL_AUTHENTICATION_STATUS, status);
+        addTaggedDataToRequestLogLocked(
+                requestId, MetricsEvent.FIELD_AUTOFILL_AUTHENTICATION_STATUS, status);
     }
 
     @GuardedBy("mLock")
     private void addTaggedDataToRequestLogLocked(int requestId, int tag, @Nullable Object value) {
         final LogMaker requestLog = mRequestLogs.get(requestId);
         if (requestLog == null) {
-            Slog.w(TAG,
+            Slog.w(
+                    TAG,
                     "addTaggedDataToRequestLogLocked(tag=" + tag + "): no log for id " + requestId);
             return;
         }
@@ -6983,20 +7752,33 @@
     }
 
     @GuardedBy("mLock")
-    private void logAugmentedAutofillRequestLocked(int mode,
-            ComponentName augmentedRemoteServiceName, AutofillId focusedId, boolean isWhitelisted,
+    private void logAugmentedAutofillRequestLocked(
+            int mode,
+            ComponentName augmentedRemoteServiceName,
+            AutofillId focusedId,
+            boolean isWhitelisted,
             Boolean isInline) {
         final String historyItem =
-                "aug:id=" + id + " u=" + uid + " m=" + mode
-                        + " a=" + ComponentName.flattenToShortString(mComponentName)
-                        + " f=" + focusedId
-                        + " s=" + augmentedRemoteServiceName
-                        + " w=" + isWhitelisted
-                        + " i=" + isInline;
+                "aug:id="
+                        + id
+                        + " u="
+                        + uid
+                        + " m="
+                        + mode
+                        + " a="
+                        + ComponentName.flattenToShortString(mComponentName)
+                        + " f="
+                        + focusedId
+                        + " s="
+                        + augmentedRemoteServiceName
+                        + " w="
+                        + isWhitelisted
+                        + " i="
+                        + isInline;
         mService.getMaster().logRequestLocked(historyItem);
     }
 
-    private void wtf(@Nullable Exception e, String fmt, Object...args) {
+    private void wtf(@Nullable Exception e, String fmt, Object... args) {
         final String message = String.format(fmt, args);
         synchronized (mLock) {
             mWtfHistory.log(message);
@@ -7051,13 +7833,9 @@
         mClassificationState.updateResponseReceived(response);
     }
 
-    public void onClassificationRequestFailure(int requestId, @Nullable CharSequence message) {
+    public void onClassificationRequestFailure(int requestId, @Nullable CharSequence message) {}
 
-    }
-
-    public void onClassificationRequestTimeout(int requestId) {
-
-    }
+    public void onClassificationRequestTimeout(int requestId) {}
 
     @Override
     public void onServiceDied(@NonNull RemoteFieldClassificationService service) {
@@ -7070,12 +7848,12 @@
 
     @Override
     public void logFieldClassificationEvent(
-            long startTime, FieldClassificationResponse response,
+            long startTime,
+            FieldClassificationResponse response,
             @FieldClassificationEventLogger.FieldClassificationStatus int status) {
         final FieldClassificationEventLogger logger = FieldClassificationEventLogger.createLogger();
         logger.startNewLogForRequest();
-        logger.maybeSetLatencyMillis(
-                SystemClock.elapsedRealtime() - startTime);
+        logger.maybeSetLatencyMillis(SystemClock.elapsedRealtime() - startTime);
         logger.maybeSetAppPackageUid(uid);
         logger.maybeSetNextFillRequestId(mFillRequestIdSnapshot + 1);
         logger.maybeSetRequestId(sIdCounterForPcc.get());
diff --git a/services/core/java/com/android/server/notification/NotificationManagerInternal.java b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
index f3d6a2d..d5d4070 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerInternal.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
@@ -44,7 +44,7 @@
 
     void onConversationRemoved(String pkg, int uid, Set<String> shortcuts);
 
-    /** Get the number of notification channels for a given package */
+    /** Get the number of app created notification channels for a given package */
     int getNumNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted);
 
     /** Does the specified package/uid have permission to post notifications? */
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 828e02c..62d7622 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -4392,8 +4392,9 @@
             List<NotificationChannel> channels = channelsList.getList();
             final int channelsSize = channels.size();
             ParceledListSlice<NotificationChannel> oldChannels =
-                    mPreferencesHelper.getNotificationChannels(pkg, uid, true);
-            final boolean hadChannel = oldChannels != null && !oldChannels.getList().isEmpty();
+                    mPreferencesHelper.getNotificationChannels(pkg, uid, true, false);
+            final boolean hadNonBundleChannel =
+                    oldChannels != null && !oldChannels.getList().isEmpty();
             boolean needsPolicyFileChange = false;
             boolean hasRequestedNotificationPermission = false;
             for (int i = 0; i < channelsSize; i++) {
@@ -4410,13 +4411,18 @@
                             mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(),
                                     false),
                             NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
-                    boolean hasChannel = hadChannel || hasRequestedNotificationPermission;
-                    if (!hasChannel) {
+                    boolean hasNonBundleChannel =
+                            hadNonBundleChannel || hasRequestedNotificationPermission;
+                    if (!hasNonBundleChannel) {
                         ParceledListSlice<NotificationChannel> currChannels =
-                                mPreferencesHelper.getNotificationChannels(pkg, uid, true);
-                        hasChannel = currChannels != null && !currChannels.getList().isEmpty();
+                                mPreferencesHelper.getNotificationChannels(pkg, uid, true, false);
+                        hasNonBundleChannel =
+                                currChannels != null && !currChannels.getList().isEmpty();
                     }
-                    if (!hadChannel && hasChannel && !hasRequestedNotificationPermission
+                    // show perm prompt if new non-bundle channel added and the user has not
+                    // seen the prompt
+                    if (!hadNonBundleChannel && hasNonBundleChannel
+                            && !hasRequestedNotificationPermission
                             && startingTaskId != ActivityTaskManager.INVALID_TASK_ID) {
                         hasRequestedNotificationPermission = true;
                         if (mPermissionPolicyInternal == null) {
@@ -4651,7 +4657,7 @@
         public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
                 int uid, boolean includeDeleted) {
             enforceSystemOrSystemUI("getNotificationChannelsForPackage");
-            return mPreferencesHelper.getNotificationChannels(pkg, uid, includeDeleted);
+            return mPreferencesHelper.getNotificationChannels(pkg, uid, includeDeleted, true);
         }
 
         @Override
@@ -4783,7 +4789,7 @@
                     /* ignore */
                 }
                 return mPreferencesHelper.getNotificationChannels(
-                        targetPkg, targetUid, false /* includeDeleted */);
+                        targetPkg, targetUid, false /* includeDeleted */, true);
             }
             throw new SecurityException("Pkg " + callingPkg
                     + " cannot read channels for " + targetPkg + " in " + userId);
@@ -6652,7 +6658,7 @@
             verifyPrivilegedListener(token, user, true);
 
             return mPreferencesHelper.getNotificationChannels(pkg,
-                    getUidForPackageAndUser(pkg, user), false /* includeDeleted */);
+                    getUidForPackageAndUser(pkg, user), false /* includeDeleted */, true);
         }
 
         @Override
@@ -7693,8 +7699,9 @@
     }
 
     int getNumNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted) {
-        return mPreferencesHelper.getNotificationChannels(pkg, uid, includeDeleted).getList()
-                .size();
+        // don't show perm prompt if the only channels are bundle channels
+        return mPreferencesHelper.getNotificationChannels(
+                pkg, uid, includeDeleted, false).getList().size();
     }
 
     void cancelNotificationInternal(String pkg, String opPkg, int callingUid, int callingPid,
@@ -8005,11 +8012,16 @@
     }
 
     /**
-     * Returns a channel, if exists, and restores deleted conversation channels.
+     * Returns a channel, if exists and is not a bundle channel, and restores deleted
+     * conversation channels.
      */
     @Nullable
     private NotificationChannel getNotificationChannelRestoreDeleted(String pkg,
             int callingUid, int notificationUid, String channelId, String conversationId) {
+        if (SYSTEM_RESERVED_IDS.contains(channelId)) {
+            // apps cannot post to these channels directly, in case they post incorrect content
+            return null;
+        }
         // Restore a deleted conversation channel, if exists. Otherwise use the parent channel.
         NotificationChannel channel = mPreferencesHelper.getConversationNotificationChannel(
                 pkg, notificationUid, channelId, conversationId,
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 3349b13..c9edc410 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -1870,7 +1870,7 @@
 
     @Override
     public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid,
-            boolean includeDeleted) {
+            boolean includeDeleted, boolean includeBundles) {
         Objects.requireNonNull(pkg);
         List<NotificationChannel> channels = new ArrayList<>();
         synchronized (mLock) {
@@ -1882,7 +1882,9 @@
             for (int i = 0; i < N; i++) {
                 final NotificationChannel nc = r.channels.valueAt(i);
                 if (includeDeleted || !nc.isDeleted()) {
-                    channels.add(nc);
+                    if (includeBundles || !SYSTEM_RESERVED_IDS.contains(nc.getId())) {
+                        channels.add(nc);
+                    }
                 }
             }
             return new ParceledListSlice<>(channels);
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index 8df24c9..001e91c 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -55,5 +55,5 @@
     void permanentlyDeleteNotificationChannel(String pkg, int uid, String channelId);
     void permanentlyDeleteNotificationChannels(String pkg, int uid);
     ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid,
-            boolean includeDeleted);
+            boolean includeDeleted, boolean includeBundles);
 }
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index eb62b56..8ba56c5 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -771,6 +771,10 @@
     public void onGroupRemoved(int groupId) {
         mInteractivityByGroupId.remove(groupId);
         mWakefulnessSessionObserver.removePowerGroup(groupId);
+        if (mFlags.isPerDisplayWakeByTouchEnabled()) {
+            resetDisplayInteractivities();
+            mInputManagerInternal.setDisplayInteractivities(mDisplayInteractivities);
+        }
     }
 
     /**
diff --git a/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java b/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
index a1db182..1c7fc63 100644
--- a/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
+++ b/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
@@ -54,6 +54,7 @@
 import android.provider.Settings;
 import android.testing.TestableContext;
 import android.util.IntArray;
+import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.view.Display;
 import android.view.DisplayAddress;
@@ -384,6 +385,32 @@
     }
 
     @Test
+    public void testOnGroupRemoved_perDisplayWakeByTouchEnabled() {
+        createNotifier();
+        // GIVEN per-display wake by touch is enabled and one display group has been defined
+        when(mPowerManagerFlags.isPerDisplayWakeByTouchEnabled()).thenReturn(true);
+        final int groupId = 313;
+        final int displayId1 = 3113;
+        final int displayId2 = 4114;
+        final int[] displays = new int[]{displayId1, displayId2};
+        when(mDisplayManagerInternal.getDisplayIds()).thenReturn(IntArray.wrap(displays));
+        when(mDisplayManagerInternal.getDisplayIdsForGroup(groupId)).thenReturn(displays);
+        mNotifier.onGroupWakefulnessChangeStarted(
+                groupId, WAKEFULNESS_AWAKE, PowerManager.WAKE_REASON_TAP, /* eventTime= */ 1000);
+        final SparseBooleanArray expectedDisplayInteractivities = new SparseBooleanArray();
+        expectedDisplayInteractivities.put(displayId1, true);
+        expectedDisplayInteractivities.put(displayId2, true);
+        verify(mInputManagerInternal).setDisplayInteractivities(expectedDisplayInteractivities);
+
+        // WHEN display group is removed
+        when(mDisplayManagerInternal.getDisplayIdsByGroupsIds()).thenReturn(new SparseArray<>());
+        mNotifier.onGroupRemoved(groupId);
+
+        // THEN native input manager is informed that displays in that group no longer exist
+        verify(mInputManagerInternal).setDisplayInteractivities(new SparseBooleanArray());
+    }
+
+    @Test
     public void testOnWakeLockListener_RemoteException_NoRethrow() throws RemoteException {
         when(mPowerManagerFlags.improveWakelockLatency()).thenReturn(true);
         createNotifier();
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index becb9fd..e845d80 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -4838,7 +4838,7 @@
                 null, mPkg, Process.myUserHandle());
 
         verify(mPreferencesHelper, times(1)).getNotificationChannels(
-                anyString(), anyInt(), anyBoolean());
+                anyString(), anyInt(), anyBoolean(), anyBoolean());
     }
 
     @Test
@@ -4856,7 +4856,7 @@
         }
 
         verify(mPreferencesHelper, never()).getNotificationChannels(
-                anyString(), anyInt(), anyBoolean());
+                anyString(), anyInt(), anyBoolean(), anyBoolean());
     }
 
     @Test
@@ -4871,7 +4871,7 @@
                 null, mPkg, Process.myUserHandle());
 
         verify(mPreferencesHelper, times(1)).getNotificationChannels(
-                anyString(), anyInt(), anyBoolean());
+                anyString(), anyInt(), anyBoolean(), anyBoolean());
     }
 
     @Test
@@ -4891,7 +4891,7 @@
         }
 
         verify(mPreferencesHelper, never()).getNotificationChannels(
-                anyString(), anyInt(), anyBoolean());
+                anyString(), anyInt(), anyBoolean(), anyBoolean());
     }
 
     @Test
@@ -4913,7 +4913,7 @@
         }
 
         verify(mPreferencesHelper, never()).getNotificationChannels(
-                anyString(), anyInt(), anyBoolean());
+                anyString(), anyInt(), anyBoolean(), anyBoolean());
     }
 
     @Test
@@ -17062,4 +17062,20 @@
         assertThat(mService.hasFlag(captor.getValue().getNotification().flags,
                 FLAG_PROMOTED_ONGOING)).isFalse();
     }
+
+    @Test
+    @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION)
+    public void testAppCannotUseReservedBundleChannels() throws Exception {
+        mBinderService.getBubblePreferenceForPackage(mPkg, mUid);
+        NotificationChannel news = mBinderService.getNotificationChannel(
+                mPkg, mContext.getUserId(), mPkg, NEWS_ID);
+        assertThat(news).isNotNull();
+
+        NotificationRecord nr = generateNotificationRecord(news);
+        mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(),
+                nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+        waitForIdle();
+
+        assertThat(mService.mNotificationList).isEmpty();
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 404ede6..b92bdb5 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -2547,7 +2547,7 @@
 
         // Returns only non-deleted channels
         List<NotificationChannel> channels =
-                mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false).getList();
+                mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false, true).getList();
         // Default channel + non-deleted channel + system defaults
         assertEquals(notificationClassification() ? 6 : 2, channels.size());
         for (NotificationChannel nc : channels) {
@@ -2557,7 +2557,7 @@
         }
 
         // Returns deleted channels too
-        channels = mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, true).getList();
+        channels = mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, true, true).getList();
         // Includes system channel(s)
         assertEquals(notificationClassification() ? 7 : 3, channels.size());
         for (NotificationChannel nc : channels) {
@@ -3199,7 +3199,8 @@
         mHelper.permanentlyDeleteNotificationChannels(PKG_N_MR1, UID_N_MR1);
 
         // Only default channel remains
-        assertEquals(1, mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, true).getList().size());
+        assertEquals(1, mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, true, true)
+                .getList().size());
     }
 
     @Test
@@ -3315,12 +3316,12 @@
         // user 0 records remain
         for (int i = 0; i < user0Uids.length; i++) {
             assertEquals(notificationClassification() ? 5 : 1,
-                    mHelper.getNotificationChannels(PKG_N_MR1, user0Uids[i], false)
+                    mHelper.getNotificationChannels(PKG_N_MR1, user0Uids[i], false, true)
                             .getList().size());
         }
         // user 1 records are gone
         for (int i = 0; i < user1Uids.length; i++) {
-            assertEquals(0, mHelper.getNotificationChannels(PKG_N_MR1, user1Uids[i], false)
+            assertEquals(0, mHelper.getNotificationChannels(PKG_N_MR1, user1Uids[i], false, true)
                     .getList().size());
         }
     }
@@ -3337,7 +3338,7 @@
                 new int[]{UID_N_MR1}));
 
         assertEquals(0, mHelper.getNotificationChannels(
-                PKG_N_MR1, UID_N_MR1, true).getList().size());
+                PKG_N_MR1, UID_N_MR1, true, true).getList().size());
 
         // Not deleted
         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false,
@@ -3346,7 +3347,8 @@
         assertFalse(mHelper.onPackagesChanged(false, USER_SYSTEM,
                 new String[]{PKG_N_MR1}, new int[]{UID_N_MR1}));
         assertEquals(notificationClassification() ? 6 : 2,
-                mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false).getList().size());
+                mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false, true)
+                        .getList().size());
     }
 
     @Test
@@ -3405,7 +3407,7 @@
         assertTrue(mHelper.canShowBadge(PKG_O, UID_O));
         assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
         assertEquals(0, mHelper.getAppLockedFields(PKG_O, UID_O));
-        assertEquals(0, mHelper.getNotificationChannels(PKG_O, UID_O, true).getList().size());
+        assertEquals(0, mHelper.getNotificationChannels(PKG_O, UID_O, true, true).getList().size());
         assertEquals(0, mHelper.getNotificationChannelGroups(PKG_O, UID_O).size());
 
         NotificationChannel channel = getChannel();
@@ -3419,7 +3421,8 @@
     public void testRecordDefaults() throws Exception {
         assertEquals(true, mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
         assertEquals(notificationClassification() ? 5 : 1,
-                mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false).getList().size());
+                mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false, true)
+                        .getList().size());
     }
 
     @Test
@@ -6363,6 +6366,15 @@
 
     @Test
     @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION)
+    public void testGetNotificationChannels_omitBundleChannels() {
+        // do something that triggers settings creation for an app
+        mHelper.setShowBadge(PKG_O, UID_O, true);
+
+        assertThat(mHelper.getNotificationChannels(PKG_O, UID_O, true, false).getList()).isEmpty();
+    }
+
+    @Test
+    @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION)
     public void testNotificationBundles() {
         // do something that triggers settings creation for an app
         mHelper.setShowBadge(PKG_O, UID_O, true);
diff --git a/tests/Input/src/com/android/test/input/UinputRecordingIntegrationTests.kt b/tests/Input/src/com/android/test/input/UinputRecordingIntegrationTests.kt
index 9f4df90..1a29c0f 100644
--- a/tests/Input/src/com/android/test/input/UinputRecordingIntegrationTests.kt
+++ b/tests/Input/src/com/android/test/input/UinputRecordingIntegrationTests.kt
@@ -21,6 +21,7 @@
 import android.graphics.PointF
 import android.hardware.input.InputManager
 import android.os.ParcelFileDescriptor
+import android.platform.test.annotations.FlakyTest
 import android.util.Log
 import android.util.Size
 import android.view.InputEvent
@@ -39,7 +40,6 @@
 import junit.framework.Assert.fail
 import org.hamcrest.Matchers.allOf
 import org.junit.Before
-import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
 import org.junit.rules.TestName
@@ -108,7 +108,7 @@
         parser = InputJsonParser(instrumentation.context)
     }
 
-    @Ignore("b/366602644")
+    @FlakyTest(bugId = 366602644)
     @Test
     fun testEvemuRecording() {
         VirtualDisplayActivityScenario.AutoClose<CaptureEventActivity>(