Merge "Change FRR thresholds for U-QPR1" into udc-qpr-dev
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 363e554..cba95a7 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -9236,8 +9236,8 @@
             }
 
             while (parentGroup != null && !parentGroup.isImportantForAutofill()) {
-                ignoredParentLeft += parentGroup.mLeft;
-                ignoredParentTop += parentGroup.mTop;
+                ignoredParentLeft += parentGroup.mLeft - parentGroup.mScrollX;
+                ignoredParentTop += parentGroup.mTop - parentGroup.mScrollY;
 
                 viewParent = parentGroup.getParent();
                 if (viewParent instanceof View) {
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index 03d7450..1ed06b4 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -82,6 +82,7 @@
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_SCROLL_FLING;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLASHSCREEN_AVD;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLASHSCREEN_EXIT_ANIM;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLIT_SCREEN_DOUBLE_TAP_DIVIDER;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLIT_SCREEN_ENTER;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLIT_SCREEN_EXIT;
 import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLIT_SCREEN_RESIZE;
@@ -272,7 +273,9 @@
     public static final int CUJ_IME_INSETS_SHOW_ANIMATION = 80;
     public static final int CUJ_IME_INSETS_HIDE_ANIMATION = 81;
 
-    private static final int LAST_CUJ = CUJ_IME_INSETS_HIDE_ANIMATION;
+    public static final int CUJ_SPLIT_SCREEN_DOUBLE_TAP_DIVIDER = 82;
+
+    private static final int LAST_CUJ = CUJ_SPLIT_SCREEN_DOUBLE_TAP_DIVIDER;
     private static final int NO_STATSD_LOGGING = -1;
 
     // Used to convert CujType to InteractionType enum value for statsd logging.
@@ -364,6 +367,7 @@
         CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_SHADE_EXPAND_FROM_STATUS_BAR] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SHADE_EXPAND_FROM_STATUS_BAR;
         CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_IME_INSETS_SHOW_ANIMATION] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__IME_INSETS_SHOW_ANIMATION;
         CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_IME_INSETS_HIDE_ANIMATION] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__IME_INSETS_HIDE_ANIMATION;
+        CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_SPLIT_SCREEN_DOUBLE_TAP_DIVIDER] = UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLIT_SCREEN_DOUBLE_TAP_DIVIDER;
     }
 
     private static class InstanceHolder {
@@ -466,6 +470,7 @@
             CUJ_SHADE_EXPAND_FROM_STATUS_BAR,
             CUJ_IME_INSETS_SHOW_ANIMATION,
             CUJ_IME_INSETS_HIDE_ANIMATION,
+            CUJ_SPLIT_SCREEN_DOUBLE_TAP_DIVIDER,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface CujType {
@@ -1083,6 +1088,8 @@
                 return "IME_INSETS_SHOW_ANIMATION";
             case CUJ_IME_INSETS_HIDE_ANIMATION:
                 return "IME_INSETS_HIDE_ANIMATION";
+            case CUJ_SPLIT_SCREEN_DOUBLE_TAP_DIVIDER:
+                return "SPLIT_SCREEN_DOUBLE_TAP_DIVIDER";
         }
         return "UNKNOWN";
     }
diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl
index e27cd97..31092536 100644
--- a/data/keyboards/Generic.kl
+++ b/data/keyboards/Generic.kl
@@ -439,8 +439,10 @@
 key usage 0x0c0173 MEDIA_AUDIO_TRACK
 key usage 0x0c019C PROFILE_SWITCH
 key usage 0x0c01A2 ALL_APPS
-key usage 0x0d0044 STYLUS_BUTTON_PRIMARY
-key usage 0x0d005a STYLUS_BUTTON_SECONDARY
+# TODO(b/297094448): Add stylus button mappings as a fallback when we have a way to determine
+#   if a device can actually report it.
+# key usage 0x0d0044 STYLUS_BUTTON_PRIMARY
+# key usage 0x0d005a STYLUS_BUTTON_SECONDARY
 
 # Joystick and game controller axes.
 # Axes that are not mapped will be assigned generic axis numbers by the input subsystem.
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java
index 1e6e503..0112e32 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/WindowAreaComponentImpl.java
@@ -518,8 +518,11 @@
             return WindowAreaComponent.STATUS_UNSUPPORTED;
         }
 
-        if (mCurrentDeviceState == mConcurrentDisplayState
-                || !ArrayUtils.contains(mCurrentSupportedDeviceStates, mConcurrentDisplayState)
+        if (mCurrentDeviceState == mConcurrentDisplayState) {
+            return WindowAreaComponent.STATUS_ACTIVE;
+        }
+
+        if (!ArrayUtils.contains(mCurrentSupportedDeviceStates, mConcurrentDisplayState)
                 || isDeviceFolded()) {
             return WindowAreaComponent.STATUS_UNAVAILABLE;
         }
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 5d7e532..755dba0 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
@@ -24,6 +24,7 @@
 import static android.view.WindowManager.DOCKED_RIGHT;
 import static android.view.WindowManager.DOCKED_TOP;
 
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_SPLIT_SCREEN_DOUBLE_TAP_DIVIDER;
 import static com.android.internal.jank.InteractionJankMonitor.CUJ_SPLIT_SCREEN_RESIZE;
 import static com.android.wm.shell.common.split.DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_END;
 import static com.android.wm.shell.common.split.DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_START;
@@ -661,10 +662,22 @@
         set.setDuration(FLING_SWITCH_DURATION);
         set.addListener(new AnimatorListenerAdapter() {
             @Override
+            public void onAnimationStart(Animator animation) {
+                InteractionJankMonitorUtils.beginTracing(CUJ_SPLIT_SCREEN_DOUBLE_TAP_DIVIDER,
+                        mContext, getDividerLeash(), null /*tag*/);
+            }
+
+            @Override
             public void onAnimationEnd(Animator animation) {
                 mDividePosition = dividerPos;
                 updateBounds(mDividePosition);
                 finishCallback.accept(insets);
+                InteractionJankMonitorUtils.endTracing(CUJ_SPLIT_SCREEN_DOUBLE_TAP_DIVIDER);
+            }
+
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                InteractionJankMonitorUtils.cancelTracing(CUJ_SPLIT_SCREEN_DOUBLE_TAP_DIVIDER);
             }
         });
         set.start();
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index cda919f..4a79a98 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -267,17 +267,22 @@
     }
 
     /**
-     * Set a pending intent for your media button receiver to allow restarting
-     * playback after the session has been stopped. If your app is started in
-     * this way an {@link Intent#ACTION_MEDIA_BUTTON} intent will be sent via
-     * the pending intent.
-     * <p>
-     * The pending intent is recommended to be explicit to follow the security recommendation of
-     * {@link PendingIntent#getActivity}.
+     * Set a pending intent for your media button receiver to allow restarting playback after the
+     * session has been stopped.
+     *
+     * <p>If your app is started in this way an {@link Intent#ACTION_MEDIA_BUTTON} intent will be
+     * sent via the pending intent.
+     *
+     * <p>The provided {@link PendingIntent} must not target an activity. Passing an activity
+     * pending intent will cause the call to be ignored. Refer to this <a
+     * href="https://developer.android.com/guide/components/activities/background-starts">guide</a>
+     * for more information.
+     *
+     * <p>The pending intent is recommended to be explicit to follow the security recommendation of
+     * {@link PendingIntent#getService}.
      *
      * @param mbr The {@link PendingIntent} to send the media button event to.
      * @see PendingIntent#getActivity
-     *
      * @deprecated Use {@link #setMediaButtonBroadcastReceiver(ComponentName)} instead.
      */
     @Deprecated
@@ -285,7 +290,7 @@
         try {
             mBinder.setMediaButtonReceiver(mbr);
         } catch (RemoteException e) {
-            Log.wtf(TAG, "Failure in setMediaButtonReceiver.", e);
+            e.rethrowFromSystemServer();
         }
     }
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index f60f8db..765edd7 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1948,6 +1948,9 @@
             cacheName = Settings.System.ALARM_ALERT_CACHE;
         }
         if (cacheName != null) {
+            if (!isValidAudioUri(name, value)) {
+                return false;
+            }
             final File cacheFile = new File(
                     getRingtoneCacheDir(owningUserId), cacheName);
             cacheFile.delete();
@@ -1980,6 +1983,34 @@
         }
     }
 
+    private boolean isValidAudioUri(String name, String uri) {
+        if (uri != null) {
+            Uri audioUri = Uri.parse(uri);
+            if (Settings.AUTHORITY.equals(
+                    ContentProvider.getAuthorityWithoutUserId(audioUri.getAuthority()))) {
+                // Don't accept setting the default uri to self-referential URIs like
+                // Settings.System.DEFAULT_RINGTONE_URI, which is an alias to the value of this
+                // setting.
+                return false;
+            }
+            final String mimeType = getContext().getContentResolver().getType(audioUri);
+            if (mimeType == null) {
+                Slog.e(LOG_TAG,
+                        "mutateSystemSetting for setting: " + name + " URI: " + audioUri
+                        + " ignored: failure to find mimeType (no access from this context?)");
+                return false;
+            }
+            if (!(mimeType.startsWith("audio/") || mimeType.equals("application/ogg")
+                    || mimeType.equals("application/x-flac"))) {
+                Slog.e(LOG_TAG,
+                        "mutateSystemSetting for setting: " + name + " URI: " + audioUri
+                        + " ignored: associated mimeType: " + mimeType + " is not an audio type");
+                return false;
+            }
+        }
+        return true;
+    }
+
     private boolean hasWriteSecureSettingsPermission() {
         // Write secure settings is a more protected permission. If caller has it we are good.
         return getContext().checkCallingOrSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/DemotingTestWithoutBugDetector.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/DemotingTestWithoutBugDetector.kt
index 09762b0..2fc56c9 100644
--- a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/DemotingTestWithoutBugDetector.kt
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/DemotingTestWithoutBugDetector.kt
@@ -43,7 +43,9 @@
                 if (node.qualifiedName in DEMOTING_ANNOTATION_BUG_ID) {
                     if (!containsBugId(node)) {
                         val location = context.getLocation(node)
-                        val message = "Please attach a bug id to track demoted test"
+                        val message =
+                            """Please attach a bug id to track demoted test, """ +
+                                """e.g. @FlakyTest(bugId = 123)"""
                         context.report(ISSUE, node, location, message)
                     }
                 }
@@ -51,7 +53,8 @@
                 if (node.qualifiedName == DEMOTING_ANNOTATION_IGNORE) {
                     if (!containsBugString(node)) {
                         val location = context.getLocation(node)
-                        val message = "Please attach a bug (e.g. b/123) to track demoted test"
+                        val message =
+                            """Please attach a bug to track demoted test, e.g. @Ignore("b/123")"""
                         context.report(ISSUE, node, location, message)
                     }
                 }
diff --git a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DemotingTestWithoutBugDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DemotingTestWithoutBugDetectorTest.kt
index a1e6f92..ee6e0ce 100644
--- a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DemotingTestWithoutBugDetectorTest.kt
+++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DemotingTestWithoutBugDetectorTest.kt
@@ -98,7 +98,7 @@
             .run()
             .expect(
                 """
-                src/test/pkg/TestClass.java:4: Warning: Please attach a bug id to track demoted test [DemotingTestWithoutBug]
+                src/test/pkg/TestClass.java:4: Warning: Please attach a bug id to track demoted test, e.g. @FlakyTest(bugId = 123) [DemotingTestWithoutBug]
                 @FlakyTest
                 ~~~~~~~~~~
                 0 errors, 1 warnings
@@ -126,7 +126,7 @@
             .run()
             .expect(
                 """
-                src/test/pkg/TestClass.java:4: Warning: Please attach a bug id to track demoted test [DemotingTestWithoutBug]
+                src/test/pkg/TestClass.java:4: Warning: Please attach a bug id to track demoted test, e.g. @FlakyTest(bugId = 123) [DemotingTestWithoutBug]
                 @FlakyTest
                 ~~~~~~~~~~
                 0 errors, 1 warnings
@@ -181,7 +181,7 @@
             .run()
             .expect(
                 """
-                src/test/pkg/TestClass.java:4: Warning: Please attach a bug id to track demoted test [DemotingTestWithoutBug]
+                src/test/pkg/TestClass.java:4: Warning: Please attach a bug id to track demoted test, e.g. @FlakyTest(bugId = 123) [DemotingTestWithoutBug]
                 @Platinum(devices = "foo,bar")
                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                 0 errors, 1 warnings
@@ -236,7 +236,7 @@
             .run()
             .expect(
                 """
-                src/test/pkg/TestClass.java:4: Warning: Please attach a bug (e.g. b/123) to track demoted test [DemotingTestWithoutBug]
+                src/test/pkg/TestClass.java:4: Warning: Please attach a bug to track demoted test, e.g. @Ignore("b/123") [DemotingTestWithoutBug]
                 @Ignore
                 ~~~~~~~
                 0 errors, 1 warnings
@@ -264,7 +264,7 @@
             .run()
             .expect(
                 """
-                src/test/pkg/TestClass.java:4: Warning: Please attach a bug (e.g. b/123) to track demoted test [DemotingTestWithoutBug]
+                src/test/pkg/TestClass.java:4: Warning: Please attach a bug to track demoted test, e.g. @Ignore("b/123") [DemotingTestWithoutBug]
                 @Ignore("Not ready")
                 ~~~~~~~~~~~~~~~~~~~~
                 0 errors, 1 warnings
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 4aad6e7..0deee34 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -657,6 +657,14 @@
     <integer-array name="config_face_help_msgs_defer_until_timeout">
     </integer-array>
 
+    <!-- Which face help messages to ignore when determining the % of frames that meet
+         config_face_help_msgs_defer_until_timeout_threshold -->
+    <integer-array name="config_face_help_msgs_ignore">
+        <item>20</item> <!-- FACE_ACQUIRED_START -->
+        <item>23</item> <!-- FACE_ACQUIRED_UNKNOWN -->
+        <item>24</item> <!-- FACE_ACQUIRED_FIRST_FRAME_RECEIVED -->
+    </integer-array>
+
     <!-- Percentage of face auth frames received required to show a deferred message at
          FACE_ERROR_TIMEOUT. See config_face_help_msgs_defer_until_timeout for messages
          that are deferred.-->
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
index 33e453c..823bd2d 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
@@ -23,6 +23,7 @@
 import android.view.SurfaceControl;
 import com.android.systemui.shared.recents.ISystemUiProxy;
 
+// Next ID: 29
 oneway interface IOverviewProxy {
 
     void onActiveNavBarRegionChanges(in Region activeRegion) = 11;
@@ -56,6 +57,13 @@
     void onAssistantVisibilityChanged(float visibility) = 14;
 
     /**
+     * Sent when the assistant has been invoked with the given type (defined in AssistManager) and
+     * should be shown. This method should be used if SystemUiProxy#setAssistantOverridesRequested
+     * was previously called including this invocation type.
+     */
+    void onAssistantOverrideInvoked(int invocationType) = 28;
+
+    /**
      * Sent when some system ui state changes.
      */
     void onSystemUiStateChanged(int stateFlags) = 16;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index 4b31498..dc34ef7 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -67,6 +67,15 @@
     oneway void startAssistant(in Bundle bundle) = 13;
 
     /**
+     * Indicates that the given Assist invocation types should be handled by Launcher via
+     * OverviewProxy#onAssistantOverrideInvoked and should not be invoked by SystemUI.
+     *
+     * @param invocationTypes The invocation types that will henceforth be handled via
+     *         OverviewProxy (Launcher); other invocation types should be handled by SysUI.
+     */
+    oneway void setAssistantOverridesRequested(in int[] invocationTypes) = 53;
+
+    /**
      * Notifies that the accessibility button in the system's navigation area has been clicked
      */
     oneway void notifyAccessibilityButtonClicked(int displayId) = 15;
@@ -135,5 +144,5 @@
      */
     oneway void onStatusBarTrackpadEvent(in MotionEvent event) = 52;
 
-    // Next id = 53
+    // Next id = 54
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java
index e3de8c7..a9928d8 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java
@@ -131,7 +131,7 @@
             mLiveData.observeForever(mObserver);
         }
         mConfigurationController.addCallback(mConfigurationListener);
-        mDumpManager.registerDumpable(
+        mDumpManager.registerNormalDumpable(
                 TAG + "@" + Integer.toHexString(
                         KeyguardSliceViewController.this.hashCode()),
                 KeyguardSliceViewController.this);
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/BiometricMessageDeferralLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/BiometricMessageDeferralLogger.kt
index 54738c6..2d854d9 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/BiometricMessageDeferralLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/BiometricMessageDeferralLogger.kt
@@ -49,6 +49,12 @@
         )
     }
 
+    fun logFrameIgnored(
+        acquiredInfo: Int,
+    ) {
+        logBuffer.log(tag, DEBUG, { int1 = acquiredInfo }, { "frameIgnored acquiredInfo=$int1" })
+    }
+
     fun logFrameProcessed(
         acquiredInfo: Int,
         totalFrames: Int,
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 590056f..165bb6c 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -44,6 +44,7 @@
 import dagger.Lazy;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 import javax.inject.Inject;
@@ -136,6 +137,7 @@
     protected final Context mContext;
     private final AssistDisclosure mAssistDisclosure;
     private final PhoneStateMonitor mPhoneStateMonitor;
+    private final OverviewProxyService mOverviewProxyService;
     private final UiController mUiController;
     protected final Lazy<SysUiState> mSysUiState;
     protected final AssistLogger mAssistLogger;
@@ -164,6 +166,9 @@
     private final CommandQueue mCommandQueue;
     protected final AssistUtils mAssistUtils;
 
+    // Invocation types that should be sent over OverviewProxy instead of handled here.
+    private int[] mAssistOverrideInvocationTypes;
+
     @Inject
     public AssistManager(
             DeviceProvisionedController controller,
@@ -184,6 +189,7 @@
         mCommandQueue = commandQueue;
         mAssistUtils = assistUtils;
         mAssistDisclosure = new AssistDisclosure(context, uiHandler);
+        mOverviewProxyService = overviewProxyService;
         mPhoneStateMonitor = phoneStateMonitor;
         mAssistLogger = assistLogger;
         mUserTracker = userTracker;
@@ -197,7 +203,7 @@
 
         mSysUiState = sysUiState;
 
-        overviewProxyService.addCallback(new OverviewProxyService.OverviewProxyListener() {
+        mOverviewProxyService.addCallback(new OverviewProxyService.OverviewProxyListener() {
             @Override
             public void onAssistantProgress(float progress) {
                 // Progress goes from 0 to 1 to indicate how close the assist gesture is to
@@ -260,6 +266,20 @@
     }
 
     public void startAssist(Bundle args) {
+        if (shouldOverrideAssist(args)) {
+            try {
+                if (mOverviewProxyService.getProxy() == null) {
+                    Log.w(TAG, "No OverviewProxyService to invoke assistant override");
+                    return;
+                }
+                mOverviewProxyService.getProxy().onAssistantOverrideInvoked(
+                        args.getInt(INVOCATION_TYPE_KEY));
+            } catch (RemoteException e) {
+                Log.w(TAG, "Unable to invoke assistant via OverviewProxyService override", e);
+            }
+            return;
+        }
+
         final ComponentName assistComponent = getAssistInfo();
         if (assistComponent == null) {
             return;
@@ -283,6 +303,24 @@
         startAssistInternal(args, assistComponent, isService);
     }
 
+    private boolean shouldOverrideAssist(Bundle args) {
+        if (args == null || !args.containsKey(INVOCATION_TYPE_KEY)) {
+            return false;
+        }
+
+        int invocationType = args.getInt(INVOCATION_TYPE_KEY);
+        return mAssistOverrideInvocationTypes != null && Arrays.stream(
+                mAssistOverrideInvocationTypes).anyMatch(override -> override == invocationType);
+    }
+
+    /**
+     * @param invocationTypes The invocation types that will henceforth be handled via
+     *         OverviewProxy (Launcher); other invocation types should be handled by this class.
+     */
+    public void setAssistantOverridesRequested(int[] invocationTypes) {
+        mAssistOverrideInvocationTypes = invocationTypes;
+    }
+
     /** Called when the user is performing an assistant invocation action (e.g. Active Edge) */
     public void onInvocationProgress(int type, float progress) {
         mUiController.onInvocationProgress(type, progress);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/FaceHelpMessageDeferral.kt b/packages/SystemUI/src/com/android/systemui/biometrics/FaceHelpMessageDeferral.kt
index e16121d..320e362 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/FaceHelpMessageDeferral.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/FaceHelpMessageDeferral.kt
@@ -25,7 +25,7 @@
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.dump.DumpManager
 import java.io.PrintWriter
-import java.util.*
+import java.util.Objects
 import javax.inject.Inject
 
 /**
@@ -42,6 +42,7 @@
 ) :
     BiometricMessageDeferral(
         resources.getIntArray(R.array.config_face_help_msgs_defer_until_timeout).toHashSet(),
+        resources.getIntArray(R.array.config_face_help_msgs_ignore).toHashSet(),
         resources.getFloat(R.dimen.config_face_help_msgs_defer_until_timeout_threshold),
         logBuffer,
         dumpManager
@@ -50,10 +51,11 @@
 /**
  * @property messagesToDefer messages that shouldn't show immediately when received, but may be
  *   shown later if the message is the most frequent acquiredInfo processed and meets [threshold]
- *   percentage of all passed acquired frames.
+ *   percentage of all acquired frames, excluding [acquiredInfoToIgnore].
  */
 open class BiometricMessageDeferral(
     private val messagesToDefer: Set<Int>,
+    private val acquiredInfoToIgnore: Set<Int>,
     private val threshold: Float,
     private val logBuffer: BiometricMessageDeferralLogger,
     dumpManager: DumpManager
@@ -98,12 +100,20 @@
         return messagesToDefer.contains(acquiredMsgId)
     }
 
-    /** Adds the acquiredInfo frame to the counts. We account for all frames. */
+    /**
+     * Adds the acquiredInfo frame to the counts. We account for frames not included in
+     * acquiredInfoToIgnore.
+     */
     fun processFrame(acquiredInfo: Int) {
         if (messagesToDefer.isEmpty()) {
             return
         }
 
+        if (acquiredInfoToIgnore.contains(acquiredInfo)) {
+            logBuffer.logFrameIgnored(acquiredInfo)
+            return
+        }
+
         totalFrames++
 
         val newAcquiredInfoCount = acquiredInfoToFrequency.getOrDefault(acquiredInfo, 0) + 1
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 6d68eef..8b23b5a 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -285,11 +285,7 @@
     /** Enables preview loading animation in the wallpaper picker. */
     // TODO(b/274443705): Tracking Bug
     @JvmField
-    val WALLPAPER_PICKER_PREVIEW_ANIMATION =
-            unreleasedFlag(
-                    "wallpaper_picker_preview_animation",
-                teamfood = true
-            )
+    val WALLPAPER_PICKER_PREVIEW_ANIMATION = releasedFlag("wallpaper_picker_preview_animation")
 
     /** Stop running face auth when the display state changes to OFF. */
     // TODO(b/294221702): Tracking bug.
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
index 8225c47..c6f73ef 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
@@ -453,6 +453,11 @@
     }
 
     @Override
+    public void setAssistantOverridesRequested(int[] invocationTypes) {
+        mAssistManagerLazy.get().setAssistantOverridesRequested(invocationTypes);
+    }
+
+    @Override
     public void onNavigationModeChanged(int mode) {
         mNavBarMode = mode;
         updateAssistantAvailability();
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index ae0ab84..555269d 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -394,6 +394,11 @@
         }
 
         @Override
+        public void setAssistantOverridesRequested(int[] invocationTypes) {
+            mAssistManagerLazy.get().setAssistantOverridesRequested(invocationTypes);
+        }
+
+        @Override
         public void onHomeRotationEnabled(boolean enabled) {
             mView.getRotationButtonController().setHomeRotationEnabled(enabled);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 1e82d44..3a64a6a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -326,6 +326,12 @@
         }
 
         @Override
+        public void setAssistantOverridesRequested(int[] invocationTypes) {
+            verifyCallerAndClearCallingIdentityPostMain("setAssistantOverridesRequested", () ->
+                    notifyAssistantOverrideRequested(invocationTypes));
+        }
+
+        @Override
         public void notifyAccessibilityButtonClicked(int displayId) {
             verifyCallerAndClearCallingIdentity("notifyAccessibilityButtonClicked", () ->
                     AccessibilityManager.getInstance(mContext)
@@ -908,6 +914,12 @@
         }
     }
 
+    private void notifyAssistantOverrideRequested(int[] invocationTypes) {
+        for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
+            mConnectionCallbacks.get(i).setAssistantOverridesRequested(invocationTypes);
+        }
+    }
+
     public void notifyAssistantVisibilityChanged(float visibility) {
         try {
             if (mOverviewProxy != null) {
@@ -1051,6 +1063,7 @@
         default void onAssistantProgress(@FloatRange(from = 0.0, to = 1.0) float progress) {}
         default void onAssistantGestureCompletion(float velocity) {}
         default void startAssistant(Bundle bundle) {}
+        default void setAssistantOverridesRequested(int[] invocationTypes) {}
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
index c1b905a..91547a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
@@ -144,13 +144,24 @@
         }
     }
 
-    private fun removeHun(animate: Boolean) {
-        if (!headsUpManager.isAlerting(notificationKey)) {
-            return
-        }
+    private val headsUpNotificationRow: ExpandableNotificationRow? get() {
+        val summaryEntry = notificationEntry.parent?.summary
 
+        return when {
+            headsUpManager.isAlerting(notificationKey) -> notification
+            summaryEntry == null -> null
+            headsUpManager.isAlerting(summaryEntry.key) -> summaryEntry.row
+            else -> null
+        }
+    }
+
+    private fun removeHun(animate: Boolean) {
+        val row = headsUpNotificationRow ?: return
+
+        // TODO: b/297247841 - Call on the row we're removing, which may differ from notification.
         HeadsUpUtil.setNeedsHeadsUpDisappearAnimationAfterClick(notification, animate)
-        headsUpManager.removeNotification(notificationKey, true /* releaseImmediately */, animate)
+
+        headsUpManager.removeNotification(row.entry.key, true /* releaseImmediately */, animate)
     }
 
     override fun onLaunchAnimationCancelled(newKeyguardOccludedState: Boolean?) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index b2d26d9..90e10a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -497,14 +497,14 @@
         return stackHeight / stackEndHeight;
     }
 
-    private boolean hasNonDismissableNotifs(StackScrollAlgorithmState algorithmState) {
+    private boolean hasNonClearableNotifs(StackScrollAlgorithmState algorithmState) {
         for (int i = 0; i < algorithmState.visibleChildren.size(); i++) {
             View child = algorithmState.visibleChildren.get(i);
             if (!(child instanceof ExpandableNotificationRow)) {
                 continue;
             }
             final ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-            if (!row.canViewBeDismissed()) {
+            if (!row.canViewBeCleared()) {
                 return true;
             }
         }
@@ -579,7 +579,7 @@
                 ((FooterView.FooterViewState) viewState).hideContent =
                         isShelfShowing || noSpaceForFooter
                                 || (ambientState.isClearAllInProgress()
-                                && !hasNonDismissableNotifs(algorithmState));
+                                && !hasNonClearableNotifs(algorithmState));
             }
         } else {
             if (view instanceof EmptyShadeView) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceHelpMessageDeferralTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceHelpMessageDeferralTest.kt
index ad9fc95..ab5d8bea5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceHelpMessageDeferralTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceHelpMessageDeferralTest.kt
@@ -184,7 +184,43 @@
         assertFalse(biometricMessageDeferral.shouldDefer(4))
     }
 
-    private fun createMsgDeferral(messagesToDefer: Set<Int>): BiometricMessageDeferral {
-        return BiometricMessageDeferral(messagesToDefer, threshold, logger, dumpManager)
+    @Test
+    fun testDeferredMessage_meetThresholdWithIgnoredFrames() {
+        val biometricMessageDeferral =
+            createMsgDeferral(
+                messagesToDefer = setOf(1),
+                acquiredInfoToIgnore = setOf(4),
+            )
+
+        // WHEN more nonDeferredMessages are shown than the deferred message; HOWEVER the
+        // nonDeferredMessages are in acquiredInfoToIgnore
+        val totalMessages = 10
+        val nonDeferredMessagesCount = (totalMessages * threshold).toInt() + 1
+        for (i in 0 until nonDeferredMessagesCount) {
+            biometricMessageDeferral.processFrame(4)
+            biometricMessageDeferral.updateMessage(4, "non-deferred-msg")
+        }
+        for (i in nonDeferredMessagesCount until totalMessages) {
+            biometricMessageDeferral.processFrame(1)
+            biometricMessageDeferral.updateMessage(1, "msgId-1")
+        }
+
+        // THEN the deferred message met the threshold excluding the acquiredInfoToIgnore,
+        // so the message id deferred
+        assertTrue(biometricMessageDeferral.shouldDefer(1))
+        assertEquals("msgId-1", biometricMessageDeferral.getDeferredMessage())
+    }
+
+    private fun createMsgDeferral(
+        messagesToDefer: Set<Int>,
+        acquiredInfoToIgnore: Set<Int> = emptySet(),
+    ): BiometricMessageDeferral {
+        return BiometricMessageDeferral(
+            messagesToDefer,
+            acquiredInfoToIgnore,
+            threshold,
+            logger,
+            dumpManager,
+        )
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt
index e66eb70..470d340 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt
@@ -1,5 +1,6 @@
 package com.android.systemui.statusbar.notification
 
+import android.app.Notification.GROUP_ALERT_SUMMARY
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.testing.TestableLooper.RunWithLooper
@@ -7,20 +8,26 @@
 import com.android.internal.jank.InteractionJankMonitor
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
 import com.android.systemui.statusbar.notification.data.repository.NotificationExpansionRepository
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer
 import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
 import com.android.systemui.statusbar.policy.HeadsUpUtil
+import com.android.systemui.tests.R
 import junit.framework.Assert.assertFalse
 import junit.framework.Assert.assertTrue
 import kotlinx.coroutines.test.TestScope
+import org.junit.Assert.assertNotSame
+import org.junit.Assert.assertSame
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mock
+import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when`
 import org.mockito.junit.MockitoJUnit
@@ -118,6 +125,35 @@
     }
 
     @Test
+    fun testAlertingSummaryHunRemovedOnNonAlertingChildLaunch() {
+        val GROUP_KEY = "test_group_key"
+
+        val summary = NotificationEntryBuilder().setGroup(mContext, GROUP_KEY).setId(0).apply {
+            modifyNotification(mContext).setSmallIcon(R.drawable.ic_person)
+        }.build()
+        assertNotSame(summary.key, notification.entry.key)
+
+        notificationTestHelper.createRow(summary)
+
+        GroupEntryBuilder().setKey(GROUP_KEY).setSummary(summary).addChild(notification.entry)
+                .build()
+        assertSame(summary, notification.entry.parent?.summary)
+
+        `when`(headsUpManager.isAlerting(notificationKey)).thenReturn(false)
+        `when`(headsUpManager.isAlerting(summary.key)).thenReturn(true)
+
+        assertNotSame(GROUP_ALERT_SUMMARY, summary.sbn.notification.groupAlertBehavior)
+        assertNotSame(GROUP_ALERT_SUMMARY, notification.entry.sbn.notification.groupAlertBehavior)
+
+        controller.onLaunchAnimationEnd(isExpandingFullyAbove = true)
+
+        verify(headsUpManager).removeNotification(
+                summary.key, true /* releaseImmediately */, false /* animate */)
+        verify(headsUpManager, never()).removeNotification(
+                notification.entry.key, true /* releaseImmediately */, false /* animate */)
+    }
+
+    @Test
     fun testNotificationIsExpandingDuringAnimation() {
         controller.onIntentStarted(willAnimate = true)
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index 1ab2b38..b7574a3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -269,6 +269,10 @@
         return generateRow(notification, PKG, UID, USER_HANDLE, mDefaultInflationFlags);
     }
 
+    public ExpandableNotificationRow createRow(NotificationEntry entry) throws Exception {
+        return generateRow(entry, mDefaultInflationFlags);
+    }
+
     /**
      * Create a row with the specified content views inflated in addition to the default.
      *
@@ -538,18 +542,6 @@
             @InflationFlag int extraInflationFlags,
             int importance)
             throws Exception {
-        // 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.
-        mFeatureFlags.setDefault(Flags.IMPROVED_HUN_ANIMATIONS);
-
-        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
-                mContext.LAYOUT_INFLATER_SERVICE);
-        mRow = (ExpandableNotificationRow) inflater.inflate(
-                R.layout.status_bar_notification_row,
-                null /* root */,
-                false /* attachToRoot */);
-        ExpandableNotificationRow row = mRow;
-
         final NotificationChannel channel =
                 new NotificationChannel(
                         notification.getChannelId(),
@@ -569,6 +561,25 @@
                 .setChannel(channel)
                 .build();
 
+        return generateRow(entry, extraInflationFlags);
+    }
+
+    private ExpandableNotificationRow generateRow(
+            NotificationEntry entry,
+            @InflationFlag int extraInflationFlags)
+            throws Exception {
+        // 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.
+        mFeatureFlags.setDefault(Flags.IMPROVED_HUN_ANIMATIONS);
+
+        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
+                mContext.LAYOUT_INFLATER_SERVICE);
+        mRow = (ExpandableNotificationRow) inflater.inflate(
+                R.layout.status_bar_notification_row,
+                null /* root */,
+                false /* attachToRoot */);
+        ExpandableNotificationRow row = mRow;
+
         entry.setRow(row);
         mIconManager.createIcons(entry);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
index 987861d..42f7b52 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
@@ -14,6 +14,8 @@
 import com.android.systemui.statusbar.StatusBarState
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.ExpandableView
+import com.android.systemui.statusbar.notification.row.FooterView
+import com.android.systemui.statusbar.notification.row.FooterView.FooterViewState
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
 import com.android.systemui.util.mockito.mock
 import com.google.common.truth.Expect
@@ -47,6 +49,7 @@
     private val emptyShadeView = EmptyShadeView(context, /* attrs= */ null).apply {
         layout(/* l= */ 0, /* t= */ 0, /* r= */ 100, /* b= */ 100)
     }
+    private val footerView = FooterView(context, /*attrs=*/null)
     private val ambientState = AmbientState(
             context,
             dumpManager,
@@ -325,6 +328,57 @@
     }
 
     @Test
+    fun resetViewStates_noSpaceForFooter_footerHidden() {
+        ambientState.isShadeExpanded = true
+        ambientState.stackEndHeight = 0f // no space for the footer in the stack
+        hostView.addView(footerView)
+
+        stackScrollAlgorithm.resetViewStates(ambientState, 0)
+
+        assertThat((footerView.viewState as FooterViewState).hideContent).isTrue()
+    }
+
+    @Test
+    fun resetViewStates_clearAllInProgress_hasNonClearableRow_footerVisible() {
+        whenever(notificationRow.canViewBeCleared()).thenReturn(false)
+        ambientState.isClearAllInProgress = true
+        ambientState.isShadeExpanded = true
+        ambientState.stackEndHeight = 1000f // plenty space for the footer in the stack
+        hostView.addView(footerView)
+
+        stackScrollAlgorithm.resetViewStates(ambientState, 0)
+
+        assertThat(footerView.viewState.hidden).isFalse()
+        assertThat((footerView.viewState as FooterViewState).hideContent).isFalse()
+    }
+
+    @Test
+    fun resetViewStates_clearAllInProgress_allRowsClearable_footerHidden() {
+        whenever(notificationRow.canViewBeCleared()).thenReturn(true)
+        ambientState.isClearAllInProgress = true
+        ambientState.isShadeExpanded = true
+        ambientState.stackEndHeight = 1000f // plenty space for the footer in the stack
+        hostView.addView(footerView)
+
+        stackScrollAlgorithm.resetViewStates(ambientState, 0)
+
+        assertThat((footerView.viewState as FooterViewState).hideContent).isTrue()
+    }
+
+    @Test
+    fun resetViewStates_clearAllInProgress_allRowsRemoved_emptyShade_footerHidden() {
+        ambientState.isClearAllInProgress = true
+        ambientState.isShadeExpanded = true
+        ambientState.stackEndHeight = 1000f // plenty space for the footer in the stack
+        hostView.removeAllViews() // remove all rows
+        hostView.addView(footerView)
+
+        stackScrollAlgorithm.resetViewStates(ambientState, 0)
+
+        assertThat((footerView.viewState as FooterViewState).hideContent).isTrue()
+    }
+
+    @Test
     fun getGapForLocation_onLockscreen_returnsSmallGap() {
         val gap = stackScrollAlgorithm.getGapForLocation(
                 /* fractionToShade= */ 0f, /* onKeyguard= */ true)
diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java
index 496bdf4..0eb459f 100644
--- a/services/core/java/com/android/server/audio/SpatializerHelper.java
+++ b/services/core/java/com/android/server/audio/SpatializerHelper.java
@@ -541,7 +541,6 @@
         }
         loglogi("addCompatibleAudioDevice: dev=" + ada);
         final AdiDeviceState deviceState = findDeviceStateForAudioDeviceAttributes(ada);
-        initSAState(deviceState);
         AdiDeviceState updatedDevice = null; // non-null on update.
         if (deviceState != null) {
             if (forceEnable && !deviceState.isSAEnabled()) {
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 9185a00..4084462 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -1062,6 +1062,14 @@
                         != 0) {
                     return;
                 }
+
+                if (pi != null && pi.isActivity()) {
+                    Log.w(
+                            TAG,
+                            "Ignoring invalid media button receiver targeting an activity: " + pi);
+                    return;
+                }
+
                 mMediaButtonReceiverHolder =
                         MediaButtonReceiverHolder.create(mUserId, pi, mPackageName);
                 mService.onMediaButtonReceiverChanged(MediaSessionRecord.this);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 71502c6..a38c79a 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -5651,9 +5651,10 @@
         // to be some edge cases where we change our visibility but client visibility never gets
         // updated.
         // If we're becoming invisible, update the client visibility if we are not running an
-        // animation. Otherwise, we'll update client visibility in onAnimationFinished.
-        if (visible || usingShellTransitions
-                || !isAnimating(PARENTS, ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS)) {
+        // animation and aren't in RESUMED state. Otherwise, we'll update client visibility in
+        // onAnimationFinished or activityStopped.
+        if (visible || (mState != RESUMED && (usingShellTransitions || !isAnimating(
+                PARENTS, ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_RECENTS)))) {
             setClientVisible(visible);
         }
 
diff --git a/services/core/java/com/android/server/wm/AsyncRotationController.java b/services/core/java/com/android/server/wm/AsyncRotationController.java
index 0250475..0a2bbd4 100644
--- a/services/core/java/com/android/server/wm/AsyncRotationController.java
+++ b/services/core/java/com/android/server/wm/AsyncRotationController.java
@@ -455,13 +455,11 @@
      * or seamless transformation in a rotated display.
      */
     boolean shouldFreezeInsetsPosition(WindowState w) {
-        if (TransitionController.SYNC_METHOD != BLASTSyncEngine.METHOD_BLAST) {
-            // Expect a screenshot layer has covered the screen, so it is fine to let client side
-            // insets animation runner update the position directly.
-            return false;
-        }
-        return mTransitionOp != OP_LEGACY && !mIsStartTransactionCommitted
-                && isTargetToken(w.mToken);
+        // Non-change transition (OP_APP_SWITCH) and METHOD_BLAST don't use screenshot so the
+        // insets should keep original position before the start transaction is applied.
+        return mTransitionOp != OP_LEGACY && (mTransitionOp == OP_APP_SWITCH
+                || TransitionController.SYNC_METHOD == BLASTSyncEngine.METHOD_BLAST)
+                && !mIsStartTransactionCommitted && isTargetToken(w.mToken);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 83fd725..098f32b 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -225,7 +225,6 @@
                 final DisplayContent dc = mRootWindowContainer.getDefaultDisplay();
                 dc.requestTransitionAndLegacyPrepare(
                         TRANSIT_TO_FRONT, TRANSIT_FLAG_KEYGUARD_APPEARING);
-                dc.mWallpaperController.showWallpaperInTransition(false /* showHome */);
                 mWindowManager.executeAppTransition();
             }
         }
@@ -282,8 +281,6 @@
                     TRANSIT_TO_BACK, transitFlags, null /* trigger */, dc);
             updateKeyguardSleepToken();
 
-            // Make the home wallpaper visible
-            dc.mWallpaperController.showWallpaperInTransition(true /* showHome */);
             // Some stack visibility might change (e.g. docked stack)
             mRootWindowContainer.resumeFocusedTasksTopActivities();
             mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 00bedcd..9c08c74 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -314,31 +314,6 @@
                         || !mWallpaperTarget.mActivityRecord.isWaitingForTransitionStart());
     }
 
-    /**
-     * Make one wallpaper visible, according to {@attr showHome}.
-     * This is called during the keyguard unlocking transition
-     * (see {@link KeyguardController#keyguardGoingAway(int, int)}),
-     * or when a keyguard unlock is cancelled (see {@link KeyguardController})
-     */
-    public void showWallpaperInTransition(boolean showHome) {
-        updateWallpaperWindowsTarget(mFindResults);
-
-        if (!mFindResults.hasTopShowWhenLockedWallpaper()) {
-            Slog.w(TAG, "There is no wallpaper for the lock screen");
-            return;
-        }
-        WindowState hideWhenLocked = mFindResults.mTopWallpaper.mTopHideWhenLockedWallpaper;
-        WindowState showWhenLocked = mFindResults.mTopWallpaper.mTopShowWhenLockedWallpaper;
-        if (!mFindResults.hasTopHideWhenLockedWallpaper()) {
-            // Shared wallpaper, ensure its visibility
-            showWhenLocked.mToken.asWallpaperToken().updateWallpaperWindows(true);
-        } else {
-            // Separate lock and home wallpapers: show the correct wallpaper in transition
-            hideWhenLocked.mToken.asWallpaperToken().updateWallpaperWindowsInTransition(showHome);
-            showWhenLocked.mToken.asWallpaperToken().updateWallpaperWindowsInTransition(!showHome);
-        }
-    }
-
     void hideDeferredWallpapersIfNeededLegacy() {
         for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) {
             final WallpaperWindowToken token = mWallpaperTokens.get(i);
@@ -840,10 +815,7 @@
             }
         }
 
-        if (!mDisplayContent.isKeyguardGoingAway() || !mIsLockscreenLiveWallpaperEnabled) {
-            // When keyguard goes away, KeyguardController handles the visibility
-            updateWallpaperTokens(visible, mDisplayContent.isKeyguardLocked());
-        }
+        updateWallpaperTokens(visible, mDisplayContent.isKeyguardLocked());
 
         if (DEBUG_WALLPAPER) {
             Slog.v(TAG, "adjustWallpaperWindows: wallpaper visibility " + visible
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index 8e0ad0d..c7fd147 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -128,20 +128,6 @@
         }
     }
 
-    /**
-     * Update the visibility of the token to {@param visible}. If a transition will collect the
-     * wallpaper, then the visibility will be committed during the execution of the transition.
-     *
-     * waitingToShow is reset at the beginning of the transition:
-     * {@link Transition#onTransactionReady(int, SurfaceControl.Transaction)}
-     */
-    void updateWallpaperWindowsInTransition(boolean visible) {
-        if (mTransitionController.isCollecting() && mVisibleRequested != visible) {
-            waitingToShow = true;
-        }
-        updateWallpaperWindows(visible);
-    }
-
     void updateWallpaperWindows(boolean visible) {
         if (mVisibleRequested != visible) {
             ProtoLog.d(WM_DEBUG_WALLPAPER, "Wallpaper token %s visible=%b",
@@ -212,12 +198,9 @@
         commitVisibility(visible);
     }
 
-    /**
-     * Commits the visibility of this token. This will directly update the visibility unless the
-     * wallpaper is in a transition.
-     */
+    /** Commits the visibility of this token. This will directly update the visibility. */
     void commitVisibility(boolean visible) {
-        if (visible == isVisible() || waitingToShow) return;
+        if (visible == isVisible()) return;
 
         ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
                 "commitVisibility: %s: visible=%b mVisibleRequested=%b", this,
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index 7544fda..be4ef6f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -1197,7 +1197,7 @@
         final AsyncRotationController asyncRotationController =
                 mDisplayContent.getAsyncRotationController();
         assertNotNull(asyncRotationController);
-        assertShouldFreezeInsetsPosition(asyncRotationController, statusBar, true);
+        assertTrue(asyncRotationController.shouldFreezeInsetsPosition(statusBar));
         assertTrue(app.getTask().inTransition());
 
         player.start();
@@ -1222,6 +1222,7 @@
         assertFalse(asyncRotationController.isTargetToken(navBar.mToken));
         navBar.finishDrawing(null /* postDrawTransaction */, Integer.MAX_VALUE);
         assertTrue(asyncRotationController.isTargetToken(navBar.mToken));
+        assertTrue(asyncRotationController.shouldFreezeInsetsPosition(navBar));
 
         player.startTransition();
         // Non-app windows should not be collected.