Merge "Add preinstalled-packages-asl-files.xml config file" into udc-dev
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 63da0a2..d375760 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2916,6 +2916,14 @@
             }
         }
 
+        if (isStyle(CallStyle.class) & extras != null) {
+            Person callPerson = extras.getParcelable(EXTRA_CALL_PERSON);
+            if (callPerson != null) {
+                visitor.accept(callPerson.getIconUri());
+            }
+            visitIconUri(visitor, extras.getParcelable(EXTRA_VERIFICATION_ICON));
+        }
+
         if (mBubbleMetadata != null) {
             visitIconUri(visitor, mBubbleMetadata.getIcon());
         }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 74a69a6..307f306 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -12349,7 +12349,9 @@
                             null, new String[] { getType() },
                             new ClipData.Item(text, htmlText, null, stream));
                     setClipData(clipData);
-                    addFlags(FLAG_GRANT_READ_URI_PERMISSION);
+                    if (stream != null) {
+                        addFlags(FLAG_GRANT_READ_URI_PERMISSION);
+                    }
                     return true;
                 }
             } catch (ClassCastException e) {
@@ -12388,7 +12390,9 @@
                     }
 
                     setClipData(clipData);
-                    addFlags(FLAG_GRANT_READ_URI_PERMISSION);
+                    if (streams != null) {
+                        addFlags(FLAG_GRANT_READ_URI_PERMISSION);
+                    }
                     return true;
                 }
             } catch (ClassCastException e) {
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 048289f..960d10a 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2628,6 +2628,15 @@
             return Build.VERSION_CODES.CUR_DEVELOPMENT;
         }
 
+        // STOPSHIP: hack for the pre-release SDK
+        if (platformSdkCodenames.length == 0
+                && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
+                targetCode)) {
+            Slog.w(TAG, "Package requires development platform " + targetCode
+                    + ", returning current version " + Build.VERSION.SDK_INT);
+            return Build.VERSION.SDK_INT;
+        }
+
         // Otherwise, we're looking at an incompatible pre-release SDK.
         if (platformSdkCodenames.length > 0) {
             outError[0] = "Requires development platform " + targetCode
@@ -2699,6 +2708,15 @@
             return Build.VERSION_CODES.CUR_DEVELOPMENT;
         }
 
+        // STOPSHIP: hack for the pre-release SDK
+        if (platformSdkCodenames.length == 0
+                && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
+                minCode)) {
+            Slog.w(TAG, "Package requires min development platform " + minCode
+                    + ", returning current version " + Build.VERSION.SDK_INT);
+            return Build.VERSION.SDK_INT;
+        }
+
         // Otherwise, we're looking at an incompatible pre-release SDK.
         if (platformSdkCodenames.length > 0) {
             outError[0] = "Requires development platform " + minCode
diff --git a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
index 3e1c5bb..8cc4cdb 100644
--- a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
@@ -316,6 +316,15 @@
             return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
         }
 
+        // STOPSHIP: hack for the pre-release SDK
+        if (platformSdkCodenames.length == 0
+                && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
+                        minCode)) {
+            Slog.w(TAG, "Parsed package requires min development platform " + minCode
+                    + ", returning current version " + Build.VERSION.SDK_INT);
+            return input.success(Build.VERSION.SDK_INT);
+        }
+
         // Otherwise, we're looking at an incompatible pre-release SDK.
         if (platformSdkCodenames.length > 0) {
             return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK,
@@ -368,19 +377,27 @@
             return input.success(targetVers);
         }
 
+        // If it's a pre-release SDK and the codename matches this platform, it
+        // definitely targets this SDK.
+        if (matchTargetCode(platformSdkCodenames, targetCode)) {
+            return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
+        }
+
+        // STOPSHIP: hack for the pre-release SDK
+        if (platformSdkCodenames.length == 0
+                && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
+                        targetCode)) {
+            Slog.w(TAG, "Parsed package requires development platform " + targetCode
+                    + ", returning current version " + Build.VERSION.SDK_INT);
+            return input.success(Build.VERSION.SDK_INT);
+        }
+
         try {
             if (allowUnknownCodenames && UnboundedSdkLevel.isAtMost(targetCode)) {
                 return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
             }
         } catch (IllegalArgumentException e) {
-            // isAtMost() throws it when encountering an older SDK codename
-            return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK, e.getMessage());
-        }
-
-        // If it's a pre-release SDK and the codename matches this platform, it
-        // definitely targets this SDK.
-        if (matchTargetCode(platformSdkCodenames, targetCode)) {
-            return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
+            return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK, "Bad package SDK");
         }
 
         // Otherwise, we're looking at an incompatible pre-release SDK.
diff --git a/core/java/android/util/IntArray.java b/core/java/android/util/IntArray.java
index bc0e35d..511cb2d 100644
--- a/core/java/android/util/IntArray.java
+++ b/core/java/android/util/IntArray.java
@@ -43,7 +43,7 @@
      * Creates an empty IntArray with the default initial capacity.
      */
     public IntArray() {
-        this(10);
+        this(0);
     }
 
     /**
diff --git a/core/java/android/util/LongArray.java b/core/java/android/util/LongArray.java
index 53dddeb..9f269ed 100644
--- a/core/java/android/util/LongArray.java
+++ b/core/java/android/util/LongArray.java
@@ -48,7 +48,7 @@
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public LongArray() {
-        this(10);
+        this(0);
     }
 
     /**
diff --git a/core/java/android/window/BackNavigationInfo.java b/core/java/android/window/BackNavigationInfo.java
index e0ee683..e44f436 100644
--- a/core/java/android/window/BackNavigationInfo.java
+++ b/core/java/android/window/BackNavigationInfo.java
@@ -94,26 +94,29 @@
     @Nullable
     private final IOnBackInvokedCallback mOnBackInvokedCallback;
     private final boolean mPrepareRemoteAnimation;
+    private final boolean mAnimationCallback;
     @Nullable
     private final CustomAnimationInfo mCustomAnimationInfo;
 
     /**
      * Create a new {@link BackNavigationInfo} instance.
      *
-     * @param type                    The {@link BackTargetType} of the destination (what will be
-     * @param onBackNavigationDone    The callback to be called once the client is done with the
-     *                                back preview.
-     * @param onBackInvokedCallback   The back callback registered by the current top level window.
+     * @param type                  The {@link BackTargetType} of the destination (what will be
+     * @param onBackNavigationDone  The callback to be called once the client is done with the
+     *                              back preview.
+     * @param onBackInvokedCallback The back callback registered by the current top level window.
      */
     private BackNavigationInfo(@BackTargetType int type,
             @Nullable RemoteCallback onBackNavigationDone,
             @Nullable IOnBackInvokedCallback onBackInvokedCallback,
             boolean isPrepareRemoteAnimation,
+            boolean isAnimationCallback,
             @Nullable CustomAnimationInfo customAnimationInfo) {
         mType = type;
         mOnBackNavigationDone = onBackNavigationDone;
         mOnBackInvokedCallback = onBackInvokedCallback;
         mPrepareRemoteAnimation = isPrepareRemoteAnimation;
+        mAnimationCallback = isAnimationCallback;
         mCustomAnimationInfo = customAnimationInfo;
     }
 
@@ -122,6 +125,7 @@
         mOnBackNavigationDone = in.readTypedObject(RemoteCallback.CREATOR);
         mOnBackInvokedCallback = IOnBackInvokedCallback.Stub.asInterface(in.readStrongBinder());
         mPrepareRemoteAnimation = in.readBoolean();
+        mAnimationCallback = in.readBoolean();
         mCustomAnimationInfo = in.readTypedObject(CustomAnimationInfo.CREATOR);
     }
 
@@ -132,6 +136,7 @@
         dest.writeTypedObject(mOnBackNavigationDone, flags);
         dest.writeStrongInterface(mOnBackInvokedCallback);
         dest.writeBoolean(mPrepareRemoteAnimation);
+        dest.writeBoolean(mAnimationCallback);
         dest.writeTypedObject(mCustomAnimationInfo, flags);
     }
 
@@ -159,7 +164,7 @@
     }
 
     /**
-     * Return true if the core is preparing a back gesture nimation.
+     * Return true if the core is preparing a back gesture animation.
      * @hide
      */
     public boolean isPrepareRemoteAnimation() {
@@ -167,6 +172,14 @@
     }
 
     /**
+     * Return true if the callback is {@link OnBackAnimationCallback}.
+     * @hide
+     */
+    public boolean isAnimationCallback() {
+        return mAnimationCallback;
+    }
+
+    /**
      * Callback to be called when the back preview is finished in order to notify the server that
      * it can clean up the resources created for the animation.
      * @hide
@@ -214,6 +227,8 @@
                 + "mType=" + typeToString(mType) + " (" + mType + ")"
                 + ", mOnBackNavigationDone=" + mOnBackNavigationDone
                 + ", mOnBackInvokedCallback=" + mOnBackInvokedCallback
+                + ", mPrepareRemoteAnimation=" + mPrepareRemoteAnimation
+                + ", mAnimationCallback=" + mAnimationCallback
                 + ", mCustomizeAnimationInfo=" + mCustomAnimationInfo
                 + '}';
     }
@@ -343,6 +358,7 @@
         private IOnBackInvokedCallback mOnBackInvokedCallback = null;
         private boolean mPrepareRemoteAnimation;
         private CustomAnimationInfo mCustomAnimationInfo;
+        private boolean mAnimationCallback = false;
 
         /**
          * @see BackNavigationInfo#getType()
@@ -387,6 +403,7 @@
             mCustomAnimationInfo.mWindowAnimations = windowAnimations;
             return this;
         }
+
         /**
          * Set resources ids for customize activity animation.
          */
@@ -402,12 +419,21 @@
         }
 
         /**
+         * @param isAnimationCallback whether the callback is {@link OnBackAnimationCallback}
+         */
+        public Builder setAnimationCallback(boolean isAnimationCallback) {
+            mAnimationCallback = isAnimationCallback;
+            return this;
+        }
+
+        /**
          * Builds and returns an instance of {@link BackNavigationInfo}
          */
         public BackNavigationInfo build() {
             return new BackNavigationInfo(mType, mOnBackNavigationDone,
                     mOnBackInvokedCallback,
                     mPrepareRemoteAnimation,
+                    mAnimationCallback,
                     mCustomAnimationInfo);
         }
     }
diff --git a/core/java/android/window/OnBackInvokedCallbackInfo.java b/core/java/android/window/OnBackInvokedCallbackInfo.java
index 6480da3..bb5fe96 100644
--- a/core/java/android/window/OnBackInvokedCallbackInfo.java
+++ b/core/java/android/window/OnBackInvokedCallbackInfo.java
@@ -28,15 +28,20 @@
     @NonNull
     private final IOnBackInvokedCallback mCallback;
     private @OnBackInvokedDispatcher.Priority int mPriority;
+    private final boolean mIsAnimationCallback;
 
-    public OnBackInvokedCallbackInfo(@NonNull IOnBackInvokedCallback callback, int priority) {
+    public OnBackInvokedCallbackInfo(@NonNull IOnBackInvokedCallback callback,
+            int priority,
+            boolean isAnimationCallback) {
         mCallback = callback;
         mPriority = priority;
+        mIsAnimationCallback = isAnimationCallback;
     }
 
     private OnBackInvokedCallbackInfo(@NonNull Parcel in) {
         mCallback = IOnBackInvokedCallback.Stub.asInterface(in.readStrongBinder());
         mPriority = in.readInt();
+        mIsAnimationCallback = in.readBoolean();
     }
 
     @Override
@@ -48,6 +53,7 @@
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeStrongInterface(mCallback);
         dest.writeInt(mPriority);
+        dest.writeBoolean(mIsAnimationCallback);
     }
 
     public static final Creator<OnBackInvokedCallbackInfo> CREATOR =
@@ -77,9 +83,16 @@
         return mPriority;
     }
 
+    public boolean isAnimationCallback() {
+        return mIsAnimationCallback;
+    }
+
     @Override
     public String toString() {
         return "OnBackInvokedCallbackInfo{"
-                + "mCallback=" + mCallback + ", mPriority=" + mPriority + '}';
+                + "mCallback=" + mCallback
+                + ", mPriority=" + mPriority
+                + ", mIsAnimationCallback=" + mIsAnimationCallback
+                + '}';
     }
 }
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index 8066f50..51382a4 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -193,7 +193,10 @@
                                 ? ((ImeOnBackInvokedDispatcher.ImeOnBackInvokedCallback)
                                         callback).getIOnBackInvokedCallback()
                                 : new OnBackInvokedCallbackWrapper(callback);
-                callbackInfo = new OnBackInvokedCallbackInfo(iCallback, priority);
+                callbackInfo = new OnBackInvokedCallbackInfo(
+                        iCallback,
+                        priority,
+                        callback instanceof OnBackAnimationCallback);
             }
             mWindowSession.setOnBackInvokedCallbackInfo(mWindow, callbackInfo);
         } catch (RemoteException e) {
diff --git a/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java b/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java
index 2b08a55..853fe2f 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java
@@ -77,6 +77,10 @@
         /** Gating the removal of sorting-notifications-by-interruptiveness. */
         public static final Flag NO_SORT_BY_INTERRUPTIVENESS =
                 devFlag("persist.sysui.notification.no_sort_by_interruptiveness");
+
+        /** Gating the logging of DND state change events. */
+        public static final Flag LOG_DND_STATE_EVENTS =
+                devFlag("persist.sysui.notification.log_dnd_state_events");
     }
 
     //// == End of flags.  Everything below this line is the implementation. == ////
diff --git a/core/java/com/android/internal/inputmethod/InputMethodDebug.java b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
index 1b4afd6..bb8bdf5 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodDebug.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
@@ -255,6 +255,12 @@
                 return "HIDE_SOFT_INPUT_IMM_DEPRECATION";
             case SoftInputShowHideReason.HIDE_WINDOW_GAINED_FOCUS_WITHOUT_EDITOR:
                 return "HIDE_WINDOW_GAINED_FOCUS_WITHOUT_EDITOR";
+            case SoftInputShowHideReason.SHOW_IME_SCREENSHOT_FROM_IMMS:
+                return "SHOW_IME_SCREENSHOT_FROM_IMMS";
+            case SoftInputShowHideReason.REMOVE_IME_SCREENSHOT_FROM_IMMS:
+                return "REMOVE_IME_SCREENSHOT_FROM_IMMS";
+            case SoftInputShowHideReason.HIDE_WHEN_INPUT_TARGET_INVISIBLE:
+                return "HIDE_WHEN_INPUT_TARGET_INVISIBLE";
             default:
                 return "Unknown=" + reason;
         }
diff --git a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
index ec9184b..6e9cd44 100644
--- a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
+++ b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
@@ -65,7 +65,10 @@
         SoftInputShowHideReason.HIDE_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT,
         SoftInputShowHideReason.HIDE_SOFT_INPUT_EXTRACT_INPUT_CHANGED,
         SoftInputShowHideReason.HIDE_SOFT_INPUT_IMM_DEPRECATION,
-        SoftInputShowHideReason.HIDE_WINDOW_GAINED_FOCUS_WITHOUT_EDITOR
+        SoftInputShowHideReason.HIDE_WINDOW_GAINED_FOCUS_WITHOUT_EDITOR,
+        SoftInputShowHideReason.SHOW_IME_SCREENSHOT_FROM_IMMS,
+        SoftInputShowHideReason.REMOVE_IME_SCREENSHOT_FROM_IMMS,
+        SoftInputShowHideReason.HIDE_WHEN_INPUT_TARGET_INVISIBLE,
 })
 public @interface SoftInputShowHideReason {
     /** Show soft input by {@link android.view.inputmethod.InputMethodManager#showSoftInput}. */
@@ -259,4 +262,20 @@
      */
     int HIDE_WINDOW_GAINED_FOCUS_WITHOUT_EDITOR =
             ImeProtoEnums.REASON_HIDE_WINDOW_GAINED_FOCUS_WITHOUT_EDITOR;
+
+    /**
+     * Shows ime screenshot by {@link com.android.server.inputmethod.InputMethodManagerService}.
+     */
+    int SHOW_IME_SCREENSHOT_FROM_IMMS = ImeProtoEnums.REASON_SHOW_IME_SCREENSHOT_FROM_IMMS;
+
+    /**
+     * Removes ime screenshot by {@link com.android.server.inputmethod.InputMethodManagerService}.
+     */
+    int REMOVE_IME_SCREENSHOT_FROM_IMMS = ImeProtoEnums.REASON_REMOVE_IME_SCREENSHOT_FROM_IMMS;
+
+    /**
+     * Hide soft input when the input target being removed or being obscured by an non-IME
+     * focusable overlay window.
+     */
+    int HIDE_WHEN_INPUT_TARGET_INVISIBLE = ImeProtoEnums.REASON_HIDE_WHEN_INPUT_TARGET_INVISIBLE;
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index e62477f..f6c9fab 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1036,9 +1036,9 @@
         android:protectionLevel="dangerous" />
 
     <!-- @SystemApi @hide Allows an application to communicate over satellite.
-         Only granted if the application is a system app. -->
+         Only granted if the application is a system app or privileged app. -->
     <permission android:name="android.permission.SATELLITE_COMMUNICATION"
-                android:protectionLevel="internal|role" />
+                android:protectionLevel="role|signature|privileged" />
 
     <!-- ====================================================================== -->
     <!-- Permissions for accessing external storage                             -->
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index c7395dd..a57a051 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -146,10 +146,6 @@
     <bool name="config_enhanced_iwlan_handover_check">true</bool>
     <java-symbol type="bool" name="config_enhanced_iwlan_handover_check" />
 
-    <!-- Whether using the new SubscriptionManagerService or the old SubscriptionController -->
-    <bool name="config_using_subscription_manager_service">true</bool>
-    <java-symbol type="bool" name="config_using_subscription_manager_service" />
-
     <!-- Whether asynchronously update the subscription database or not. Async mode increases
          the performance, but sync mode reduces the chance of database/cache out-of-sync. -->
     <bool name="config_subscription_database_async_update">true</bool>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index b0932d6..c6462f1 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5897,9 +5897,9 @@
     <string name="resolver_cant_access_personal_apps_explanation">This content can\u2019t be opened with personal apps</string>
 
     <!-- Error message. This text lets the user know that they need to turn on work apps in order to share or open content. There's also a button a user can tap to turn on the apps. [CHAR LIMIT=NONE] -->
-    <string name="resolver_turn_on_work_apps">Work profile is paused</string>
-    <!-- Button text. This button turns on a user's work profile so they can access their work apps and data. [CHAR LIMIT=NONE] -->
-    <string name="resolver_switch_on_work">Tap to turn on</string>
+    <string name="resolver_turn_on_work_apps">Work apps are paused</string>
+    <!-- Button text. This button unpauses a user's work apps and data. [CHAR LIMIT=NONE] -->
+    <string name="resolver_switch_on_work">Unpause</string>
 
     <!-- Error message. This text lets the user know that their current work apps don't support the specific content. [CHAR LIMIT=NONE] -->
     <string name="resolver_no_work_apps_available">No work apps</string>
diff --git a/core/tests/coretests/res/drawable-nodpi/test_too_big.png b/core/tests/coretests/res/drawable-nodpi/test_too_big.png
new file mode 100644
index 0000000..3754072
--- /dev/null
+++ b/core/tests/coretests/res/drawable-nodpi/test_too_big.png
Binary files differ
diff --git a/core/tests/coretests/src/android/animation/ValueAnimatorTests.java b/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
index a53d57f..a102b3e 100644
--- a/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
+++ b/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
@@ -1127,6 +1127,31 @@
         mActivityRule.runOnUiThread(() -> {});
     }
 
+    @Test
+    public void restartValueAnimator() throws Throwable {
+        CountDownLatch latch = new CountDownLatch(1);
+        ValueAnimator.AnimatorUpdateListener listener = new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                if (((float) animation.getAnimatedValue()) != A1_START_VALUE) {
+                    latch.countDown();
+                }
+            }
+        };
+        a1.addUpdateListener(listener);
+
+        mActivityRule.runOnUiThread(() -> {
+            a1.start();
+        });
+
+        // wait for a change in the value
+        assertTrue(latch.await(2, TimeUnit.SECONDS));
+
+        mActivityRule.runOnUiThread(() -> {
+            a1.start();
+            assertEquals(A1_START_VALUE, a1.getAnimatedValue());
+        });
+    }
     class MyUpdateListener implements ValueAnimator.AnimatorUpdateListener {
         boolean wasRunning = false;
         long firstRunningFrameTime = -1;
diff --git a/core/tests/coretests/src/android/graphics/drawable/IconTest.java b/core/tests/coretests/src/android/graphics/drawable/IconTest.java
index 75390a2..5d92296 100644
--- a/core/tests/coretests/src/android/graphics/drawable/IconTest.java
+++ b/core/tests/coretests/src/android/graphics/drawable/IconTest.java
@@ -20,6 +20,7 @@
 
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.RecordingCanvas;
 import android.graphics.Region;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -371,6 +372,90 @@
         }
     }
 
+    private int getMaxWidth(int origWidth, int origHeight, int maxNumPixels) {
+        float aspRatio = (float) origWidth / (float) origHeight;
+        int newHeight = (int) Math.sqrt(maxNumPixels / aspRatio);
+        return (int) (newHeight * aspRatio);
+    }
+
+    private int getMaxHeight(int origWidth, int origHeight, int maxNumPixels) {
+        float aspRatio = (float) origWidth / (float) origHeight;
+        return (int) Math.sqrt(maxNumPixels / aspRatio);
+    }
+
+    @SmallTest
+    public void testScaleDownMaxSizeWithBitmap() throws Exception {
+        final int bmpWidth = 13_000;
+        final int bmpHeight = 10_000;
+        final int bmpBpp = 4;
+        final int maxNumPixels = RecordingCanvas.MAX_BITMAP_SIZE / bmpBpp;
+        final int maxWidth = getMaxWidth(bmpWidth, bmpHeight, maxNumPixels);
+        final int maxHeight = getMaxHeight(bmpWidth, bmpHeight, maxNumPixels);
+
+        final Bitmap bm = Bitmap.createBitmap(bmpWidth, bmpHeight, Bitmap.Config.ARGB_8888);
+        final Icon ic = Icon.createWithBitmap(bm);
+        final Drawable drawable = ic.loadDrawable(mContext);
+
+        assertThat(drawable.getIntrinsicWidth()).isEqualTo(maxWidth);
+        assertThat(drawable.getIntrinsicHeight()).isEqualTo(maxHeight);
+    }
+
+    @SmallTest
+    public void testScaleDownMaxSizeWithAdaptiveBitmap() throws Exception {
+        final int bmpWidth = 20_000;
+        final int bmpHeight = 10_000;
+        final int bmpBpp = 4;
+        final int maxNumPixels = RecordingCanvas.MAX_BITMAP_SIZE / bmpBpp;
+        final int maxWidth = getMaxWidth(bmpWidth, bmpHeight, maxNumPixels);
+        final int maxHeight = getMaxHeight(bmpWidth, bmpHeight, maxNumPixels);
+
+        final Bitmap bm = Bitmap.createBitmap(bmpWidth, bmpHeight, Bitmap.Config.ARGB_8888);
+        final Icon ic = Icon.createWithAdaptiveBitmap(bm);
+        final AdaptiveIconDrawable adaptiveDrawable = (AdaptiveIconDrawable) ic.loadDrawable(
+                mContext);
+        final Drawable drawable = adaptiveDrawable.getForeground();
+
+        assertThat(drawable.getIntrinsicWidth()).isEqualTo(maxWidth);
+        assertThat(drawable.getIntrinsicHeight()).isEqualTo(maxHeight);
+    }
+
+    @SmallTest
+    public void testScaleDownMaxSizeWithResource() throws Exception {
+        final Icon ic = Icon.createWithResource(getContext(), R.drawable.test_too_big);
+        final BitmapDrawable drawable = (BitmapDrawable) ic.loadDrawable(mContext);
+
+        assertThat(drawable.getBitmap().getByteCount()).isAtMost(RecordingCanvas.MAX_BITMAP_SIZE);
+    }
+
+    @SmallTest
+    public void testScaleDownMaxSizeWithFile() throws Exception {
+        final Bitmap bit1 = ((BitmapDrawable) getContext().getDrawable(R.drawable.test_too_big))
+                .getBitmap();
+        final File dir = getContext().getExternalFilesDir(null);
+        final File file1 = new File(dir, "file1-too-big.png");
+        bit1.compress(Bitmap.CompressFormat.PNG, 100,
+                new FileOutputStream(file1));
+
+        final Icon ic = Icon.createWithFilePath(file1.toString());
+        final BitmapDrawable drawable = (BitmapDrawable) ic.loadDrawable(mContext);
+
+        assertThat(drawable.getBitmap().getByteCount()).isAtMost(RecordingCanvas.MAX_BITMAP_SIZE);
+    }
+
+    @SmallTest
+    public void testScaleDownMaxSizeWithData() throws Exception {
+        final int bmpBpp = 4;
+        final Bitmap originalBits = ((BitmapDrawable) getContext().getDrawable(
+                R.drawable.test_too_big)).getBitmap();
+        final ByteArrayOutputStream ostream = new ByteArrayOutputStream(
+                originalBits.getWidth() * originalBits.getHeight() * bmpBpp);
+        originalBits.compress(Bitmap.CompressFormat.PNG, 100, ostream);
+        final byte[] pngdata = ostream.toByteArray();
+        final Icon ic = Icon.createWithData(pngdata, 0, pngdata.length);
+        final BitmapDrawable drawable = (BitmapDrawable) ic.loadDrawable(mContext);
+
+        assertThat(drawable.getBitmap().getByteCount()).isAtMost(RecordingCanvas.MAX_BITMAP_SIZE);
+    }
 
     // ======== utils ========
 
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 8ece337..40cb7f2 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -518,6 +518,8 @@
         <permission name="android.permission.LOG_FOREGROUND_RESOURCE_USE"/>
         <!-- Permission required for CTS test - CtsVoiceInteractionTestCases -->
         <permission name="android.permission.SOUND_TRIGGER_RUN_IN_BATTERY_SAVER"/>
+        <!-- Permission required for CTS test - SatelliteManagerTest -->
+        <permission name="android.permission.SATELLITE_COMMUNICATION"/>
     </privapp-permissions>
 
     <privapp-permissions package="com.android.statementservice">
diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java
index a76d74e..708feeb 100644
--- a/graphics/java/android/graphics/drawable/Icon.java
+++ b/graphics/java/android/graphics/drawable/Icon.java
@@ -35,6 +35,7 @@
 import android.graphics.BitmapFactory;
 import android.graphics.BlendMode;
 import android.graphics.PorterDuff;
+import android.graphics.RecordingCanvas;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Build;
@@ -70,6 +71,7 @@
 
 public final class Icon implements Parcelable {
     private static final String TAG = "Icon";
+    private static final boolean DEBUG = false;
 
     /**
      * An icon that was created using {@link Icon#createWithBitmap(Bitmap)}.
@@ -361,15 +363,52 @@
     }
 
     /**
+     * Resizes image if size too large for Canvas to draw
+     * @param bitmap Bitmap to be resized if size > {@link RecordingCanvas.MAX_BITMAP_SIZE}
+     * @return resized bitmap
+     */
+    private Bitmap fixMaxBitmapSize(Bitmap bitmap) {
+        if (bitmap != null && bitmap.getByteCount() > RecordingCanvas.MAX_BITMAP_SIZE) {
+            int bytesPerPixel = bitmap.getRowBytes() / bitmap.getWidth();
+            int maxNumPixels = RecordingCanvas.MAX_BITMAP_SIZE / bytesPerPixel;
+            float aspRatio = (float) bitmap.getWidth() / (float) bitmap.getHeight();
+            int newHeight = (int) Math.sqrt(maxNumPixels / aspRatio);
+            int newWidth = (int) (newHeight * aspRatio);
+
+            if (DEBUG) {
+                Log.d(TAG,
+                        "Image size too large: " + bitmap.getByteCount() + ". Resizing bitmap to: "
+                                + newWidth + " " + newHeight);
+            }
+
+            return scaleDownIfNecessary(bitmap, newWidth, newHeight);
+        }
+        return bitmap;
+    }
+
+    /**
+     * Resizes BitmapDrawable if size too large for Canvas to draw
+     * @param drawable Drawable to be resized if size > {@link RecordingCanvas.MAX_BITMAP_SIZE}
+     * @return resized Drawable
+     */
+    private Drawable fixMaxBitmapSize(Resources res, Drawable drawable) {
+        if (drawable instanceof BitmapDrawable) {
+            Bitmap scaledBmp = fixMaxBitmapSize(((BitmapDrawable) drawable).getBitmap());
+            return new BitmapDrawable(res, scaledBmp);
+        }
+        return drawable;
+    }
+
+    /**
      * Do the heavy lifting of loading the drawable, but stop short of applying any tint.
      */
     private Drawable loadDrawableInner(Context context) {
         switch (mType) {
             case TYPE_BITMAP:
-                return new BitmapDrawable(context.getResources(), getBitmap());
+                return new BitmapDrawable(context.getResources(), fixMaxBitmapSize(getBitmap()));
             case TYPE_ADAPTIVE_BITMAP:
                 return new AdaptiveIconDrawable(null,
-                    new BitmapDrawable(context.getResources(), getBitmap()));
+                    new BitmapDrawable(context.getResources(), fixMaxBitmapSize(getBitmap())));
             case TYPE_RESOURCE:
                 if (getResources() == null) {
                     // figure out where to load resources from
@@ -400,7 +439,8 @@
                     }
                 }
                 try {
-                    return getResources().getDrawable(getResId(), context.getTheme());
+                    return fixMaxBitmapSize(getResources(),
+                            getResources().getDrawable(getResId(), context.getTheme()));
                 } catch (RuntimeException e) {
                     Log.e(TAG, String.format("Unable to load resource 0x%08x from pkg=%s",
                                     getResId(),
@@ -409,21 +449,21 @@
                 }
                 break;
             case TYPE_DATA:
-                return new BitmapDrawable(context.getResources(),
-                    BitmapFactory.decodeByteArray(getDataBytes(), getDataOffset(), getDataLength())
-                );
+                return new BitmapDrawable(context.getResources(), fixMaxBitmapSize(
+                        BitmapFactory.decodeByteArray(getDataBytes(), getDataOffset(),
+                                getDataLength())));
             case TYPE_URI:
                 InputStream is = getUriInputStream(context);
                 if (is != null) {
                     return new BitmapDrawable(context.getResources(),
-                            BitmapFactory.decodeStream(is));
+                            fixMaxBitmapSize(BitmapFactory.decodeStream(is)));
                 }
                 break;
             case TYPE_URI_ADAPTIVE_BITMAP:
                 is = getUriInputStream(context);
                 if (is != null) {
                     return new AdaptiveIconDrawable(null, new BitmapDrawable(context.getResources(),
-                            BitmapFactory.decodeStream(is)));
+                            fixMaxBitmapSize(BitmapFactory.decodeStream(is))));
                 }
                 break;
         }
diff --git a/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml b/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml
index dcce4698..ab64f9e 100644
--- a/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml
+++ b/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml
@@ -67,7 +67,7 @@
 
     <!-- Temporarily extending the background to show an edu text hint for opening the menu -->
     <FrameLayout
-        android:id="@+id/tv_pip_menu_edu_text_drawer_placeholder"
+        android:id="@+id/tv_pip_menu_edu_text_container"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_below="@+id/tv_pip"
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index 47d3a5c..dc27ceb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -20,6 +20,9 @@
 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW;
 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_BACK_ANIMATION;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityTaskManager;
@@ -37,7 +40,9 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings.Global;
+import android.util.DisplayMetrics;
 import android.util.Log;
+import android.util.MathUtils;
 import android.util.SparseArray;
 import android.view.IRemoteAnimationRunner;
 import android.view.InputDevice;
@@ -56,6 +61,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.view.AppearanceRegion;
+import com.android.wm.shell.animation.FlingAnimationUtils;
 import com.android.wm.shell.common.ExternalInterfaceBinder;
 import com.android.wm.shell.common.RemoteCallable;
 import com.android.wm.shell.common.ShellExecutor;
@@ -80,6 +86,17 @@
     public static boolean IS_U_ANIMATION_ENABLED =
             SystemProperties.getInt("persist.wm.debug.predictive_back_anim",
                     SETTING_VALUE_ON) == SETTING_VALUE_ON;
+
+    public static final float FLING_MAX_LENGTH_SECONDS = 0.1f;     // 100ms
+    public static final float FLING_SPEED_UP_FACTOR = 0.6f;
+
+    /**
+     * The maximum additional progress in case of fling gesture.
+     * The end animation starts after the user lifts the finger from the screen, we continue to
+     * fire {@link BackEvent}s until the velocity reaches 0.
+     */
+    private static final float MAX_FLING_PROGRESS = 0.3f; /* 30% of the screen */
+
     /** Predictive back animation developer option */
     private final AtomicBoolean mEnableAnimations = new AtomicBoolean(false);
     /**
@@ -96,6 +113,7 @@
     private boolean mShouldStartOnNextMoveEvent = false;
     /** @see #setTriggerBack(boolean) */
     private boolean mTriggerBack;
+    private FlingAnimationUtils mFlingAnimationUtils;
 
     @Nullable
     private BackNavigationInfo mBackNavigationInfo;
@@ -174,6 +192,11 @@
         mBgHandler = bgHandler;
         shellInit.addInitCallback(this::onInit, this);
         mAnimationBackground = backAnimationBackground;
+        DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
+        mFlingAnimationUtils = new FlingAnimationUtils.Builder(displayMetrics)
+                .setMaxLengthSeconds(FLING_MAX_LENGTH_SECONDS)
+                .setSpeedUpFactor(FLING_SPEED_UP_FACTOR)
+                .build();
     }
 
     @VisibleForTesting
@@ -465,6 +488,78 @@
         }
     }
 
+
+    /**
+     * Allows us to manage the fling gesture, it smoothly animates the current progress value to
+     * the final position, calculated based on the current velocity.
+     *
+     * @param callback the callback to be invoked when the animation ends.
+     */
+    private void dispatchOrAnimateOnBackInvoked(IOnBackInvokedCallback callback) {
+        if (callback == null) {
+            return;
+        }
+
+        boolean animationStarted = false;
+
+        if (mBackNavigationInfo != null && mBackNavigationInfo.isAnimationCallback()) {
+
+            final BackMotionEvent backMotionEvent = mTouchTracker.createProgressEvent();
+            if (backMotionEvent != null) {
+                // Constraints - absolute values
+                float minVelocity = mFlingAnimationUtils.getMinVelocityPxPerSecond();
+                float maxVelocity = mFlingAnimationUtils.getHighVelocityPxPerSecond();
+                float maxX = mTouchTracker.getMaxX(); // px
+                float maxFlingDistance = maxX * MAX_FLING_PROGRESS; // px
+
+                // Current state
+                float currentX = backMotionEvent.getTouchX();
+                float velocity = MathUtils.constrain(backMotionEvent.getVelocityX(),
+                        -maxVelocity, maxVelocity);
+
+                // Target state
+                float animationFaction = velocity / maxVelocity; // value between -1 and 1
+                float flingDistance = animationFaction * maxFlingDistance; // px
+                float endX = MathUtils.constrain(currentX + flingDistance, 0f, maxX);
+
+                if (!Float.isNaN(endX)
+                        && currentX != endX
+                        && Math.abs(velocity) >= minVelocity) {
+                    ValueAnimator animator = ValueAnimator.ofFloat(currentX, endX);
+
+                    mFlingAnimationUtils.apply(
+                            /* animator = */ animator,
+                            /* currValue = */ currentX,
+                            /* endValue = */ endX,
+                            /* velocity = */ velocity,
+                            /* maxDistance = */ maxFlingDistance
+                    );
+
+                    animator.addUpdateListener(animation -> {
+                        Float animatedValue = (Float) animation.getAnimatedValue();
+                        float progress = mTouchTracker.getProgress(animatedValue);
+                        final BackMotionEvent backEvent = mTouchTracker
+                                .createProgressEvent(progress);
+                        dispatchOnBackProgressed(mActiveCallback, backEvent);
+                    });
+
+                    animator.addListener(new AnimatorListenerAdapter() {
+                        @Override
+                        public void onAnimationEnd(Animator animation) {
+                            dispatchOnBackInvoked(callback);
+                        }
+                    });
+                    animator.start();
+                    animationStarted = true;
+                }
+            }
+        }
+
+        if (!animationStarted) {
+            dispatchOnBackInvoked(callback);
+        }
+    }
+
     private void dispatchOnBackInvoked(IOnBackInvokedCallback callback) {
         if (callback == null) {
             return;
@@ -530,7 +625,7 @@
         if (mBackNavigationInfo != null) {
             final IOnBackInvokedCallback callback = mBackNavigationInfo.getOnBackInvokedCallback();
             if (mTriggerBack) {
-                dispatchOnBackInvoked(callback);
+                dispatchOrAnimateOnBackInvoked(callback);
             } else {
                 dispatchOnBackCancelled(callback);
             }
@@ -605,7 +700,7 @@
 
         // The next callback should be {@link #onBackAnimationFinished}.
         if (mTriggerBack) {
-            dispatchOnBackInvoked(mActiveCallback);
+            dispatchOrAnimateOnBackInvoked(mActiveCallback);
         } else {
             dispatchOnBackCancelled(mActiveCallback);
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
index 904574b..7a00f5b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
@@ -16,7 +16,10 @@
 
 package com.android.wm.shell.back;
 
+import android.annotation.FloatRange;
 import android.os.SystemProperties;
+import android.util.MathUtils;
+import android.view.MotionEvent;
 import android.view.RemoteAnimationTarget;
 import android.window.BackEvent;
 import android.window.BackMotionEvent;
@@ -99,28 +102,42 @@
     }
 
     BackMotionEvent createProgressEvent() {
-        float progressThreshold = PROGRESS_THRESHOLD >= 0
-                ? PROGRESS_THRESHOLD : mProgressThreshold;
-        progressThreshold = progressThreshold == 0 ? 1 : progressThreshold;
         float progress = 0;
         // Progress is always 0 when back is cancelled and not restarted.
         if (!mCancelled) {
-            // If back is committed, progress is the distance between the last and first touch
-            // point, divided by the max drag distance. Otherwise, it's the distance between
-            // the last touch point and the starting threshold, divided by max drag distance.
-            // The starting threshold is initially the first touch location, and updated to
-            // the location everytime back is restarted after being cancelled.
-            float startX = mTriggerBack ? mInitTouchX : mStartThresholdX;
-            float deltaX = Math.max(
-                    mSwipeEdge == BackEvent.EDGE_LEFT
-                            ? mLatestTouchX - startX
-                            : startX - mLatestTouchX,
-                    0);
-            progress = Math.min(Math.max(deltaX / progressThreshold, 0), 1);
+            progress = getProgress(mLatestTouchX);
         }
         return createProgressEvent(progress);
     }
 
+    /**
+     * Progress value computed from the touch position.
+     *
+     * @param touchX the X touch position of the {@link MotionEvent}.
+     * @return progress value
+     */
+    @FloatRange(from = 0.0, to = 1.0)
+    float getProgress(float touchX) {
+        // If back is committed, progress is the distance between the last and first touch
+        // point, divided by the max drag distance. Otherwise, it's the distance between
+        // the last touch point and the starting threshold, divided by max drag distance.
+        // The starting threshold is initially the first touch location, and updated to
+        // the location everytime back is restarted after being cancelled.
+        float startX = mTriggerBack ? mInitTouchX : mStartThresholdX;
+        float deltaX = Math.abs(startX - touchX);
+        float maxX = getMaxX();
+        maxX = maxX == 0 ? 1 : maxX;
+        return MathUtils.constrain(deltaX / maxX, 0, 1);
+    }
+
+    /**
+     * Maximum X value (in pixels).
+     * Progress is considered to be completed (1f) when this limit is exceeded.
+     */
+    float getMaxX() {
+        return PROGRESS_THRESHOLD >= 0 ? PROGRESS_THRESHOLD : mProgressThreshold;
+    }
+
     BackMotionEvent createProgressEvent(float progress) {
         return new BackMotionEvent(
                 /* touchX = */ mLatestTouchX,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 713ace6..b6216b3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -623,11 +623,11 @@
      * Removes PiP immediately.
      */
     public void removePip() {
-        if (!mPipTransitionState.isInPip() || mToken == null) {
+        if (!mPipTransitionState.isInPip() || mToken == null || mLeash == null) {
             ProtoLog.wtf(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                     "%s: Not allowed to removePip in current state"
-                            + " mState=%d mToken=%s", TAG, mPipTransitionState.getTransitionState(),
-                    mToken);
+                            + " mState=%d mToken=%s mLeash=%s", TAG,
+                    mPipTransitionState.getTransitionState(), mToken, mLeash);
             return;
         }
 
@@ -1532,6 +1532,9 @@
             if (snapshotSurface != null) {
                 mSyncTransactionQueue.queue(wct);
                 mSyncTransactionQueue.runInSync(t -> {
+                    // reset the pinch gesture
+                    maybePerformFinishResizeCallback();
+
                     // Scale the snapshot from its pre-resize bounds to the post-resize bounds.
                     mSurfaceTransactionHelper.scale(t, snapshotSurface, preResizeBounds,
                             snapshotDest);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipAction.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipAction.java
index 222307f..5f6b3fe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipAction.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipAction.java
@@ -31,6 +31,12 @@
 
 abstract class TvPipAction {
 
+    /**
+     * Extras key for adding a boolean to the {@link Notification.Action} to differentiate custom
+     * from system actions, most importantly to identify custom close actions.
+     **/
+    public static final String EXTRA_IS_PIP_CUSTOM_ACTION = "EXTRA_IS_PIP_CUSTOM_ACTION";
+
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = {"ACTION_"}, value = {
             ACTION_FULLSCREEN,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipCustomAction.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipCustomAction.java
index bca27a5..977aad4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipCustomAction.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipCustomAction.java
@@ -86,7 +86,7 @@
         Bundle extras = new Bundle();
         extras.putCharSequence(Notification.EXTRA_PICTURE_CONTENT_DESCRIPTION,
                 mRemoteAction.getContentDescription());
-        extras.putBoolean(Notification.EXTRA_CONTAINS_CUSTOM_VIEW, true);
+        extras.putBoolean(TvPipAction.EXTRA_IS_PIP_CUSTOM_ACTION, true);
         builder.addExtras(extras);
 
         builder.setSemanticAction(isCloseAction()
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuEduTextDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuEduTextDrawer.java
index 6eef225..f86f987 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuEduTextDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuEduTextDrawer.java
@@ -23,6 +23,7 @@
 
 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE;
 
+import android.animation.Animator;
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.graphics.drawable.Drawable;
@@ -115,6 +116,10 @@
         scheduleLifecycleEvents();
     }
 
+    int getEduTextDrawerHeight() {
+        return getVisibility() == GONE ? 0 : getHeight();
+    }
+
     private void scheduleLifecycleEvents() {
         final int startScrollDelay = mContext.getResources().getInteger(
                 R.integer.pip_edu_text_start_scroll_delay);
@@ -226,20 +231,41 @@
                 .start();
 
         // Start animation to close the drawer by animating its height to 0
-        final ValueAnimator heightAnimation = ValueAnimator.ofInt(getHeight(), 0);
-        heightAnimation.setDuration(eduTextSlideExitAnimationDuration);
-        heightAnimation.setInterpolator(TvPipInterpolators.BROWSE);
-        heightAnimation.addUpdateListener(animator -> {
+        final ValueAnimator heightAnimator = ValueAnimator.ofInt(getHeight(), 0);
+        heightAnimator.setDuration(eduTextSlideExitAnimationDuration);
+        heightAnimator.setInterpolator(TvPipInterpolators.BROWSE);
+        heightAnimator.addUpdateListener(animator -> {
             final ViewGroup.LayoutParams params = getLayoutParams();
             params.height = (int) animator.getAnimatedValue();
             setLayoutParams(params);
-            if (params.height == 0) {
-                setVisibility(GONE);
+        });
+        heightAnimator.addListener(new Animator.AnimatorListener() {
+            @Override
+            public void onAnimationStart(@NonNull Animator animator) {
+            }
+
+            @Override
+            public void onAnimationEnd(@NonNull Animator animator) {
+                onCloseEduTextAnimationEnd();
+            }
+
+            @Override
+            public void onAnimationCancel(@NonNull Animator animator) {
+                onCloseEduTextAnimationEnd();
+            }
+
+            @Override
+            public void onAnimationRepeat(@NonNull Animator animator) {
             }
         });
-        heightAnimation.start();
+        heightAnimator.start();
 
-        mListener.onCloseEduText();
+        mListener.onCloseEduTextAnimationStart();
+    }
+
+    public void onCloseEduTextAnimationEnd() {
+        setVisibility(GONE);
+        mListener.onCloseEduTextAnimationEnd();
     }
 
     /**
@@ -270,11 +296,8 @@
      * A listener for edu text drawer event states.
      */
     interface Listener {
-        /**
-         *  The edu text closing impacts the size of the Picture-in-Picture window and influences
-         *  how it is positioned on the screen.
-         */
-        void onCloseEduText();
+        void onCloseEduTextAnimationStart();
+        void onCloseEduTextAnimationEnd();
     }
 
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
index 6eb719b..d076418 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
@@ -57,7 +57,8 @@
  * A View that represents Pip Menu on TV. It's responsible for displaying the Pip menu actions from
  * the TvPipActionsProvider as well as the buttons for manually moving the PiP.
  */
-public class TvPipMenuView extends FrameLayout implements TvPipActionsProvider.Listener {
+public class TvPipMenuView extends FrameLayout implements TvPipActionsProvider.Listener,
+        TvPipMenuEduTextDrawer.Listener {
     private static final String TAG = "TvPipMenuView";
 
     private final TvPipMenuView.Listener mListener;
@@ -76,6 +77,7 @@
     private final View mDimLayer;
 
     private final TvPipMenuEduTextDrawer mEduTextDrawer;
+    private final ViewGroup mEduTextContainer;
 
     private final int mPipMenuOuterSpace;
     private final int mPipMenuBorderWidth;
@@ -139,9 +141,9 @@
         mPipMenuBorderWidth = context.getResources()
                 .getDimensionPixelSize(R.dimen.pip_menu_border_width);
 
-        mEduTextDrawer = new TvPipMenuEduTextDrawer(mContext, mainHandler, mListener);
-        ((FrameLayout) findViewById(R.id.tv_pip_menu_edu_text_drawer_placeholder))
-                .addView(mEduTextDrawer);
+        mEduTextDrawer = new TvPipMenuEduTextDrawer(mContext, mainHandler, this);
+        mEduTextContainer = (ViewGroup) findViewById(R.id.tv_pip_menu_edu_text_container);
+        mEduTextContainer.addView(mEduTextDrawer);
     }
 
     void onPipTransitionToTargetBoundsStarted(Rect targetBounds) {
@@ -235,11 +237,13 @@
      * pip menu when it gains focus.
      */
     private void updatePipFrameBounds() {
-        final ViewGroup.LayoutParams pipFrameParams = mPipFrameView.getLayoutParams();
-        if (pipFrameParams != null) {
-            pipFrameParams.width = mCurrentPipBounds.width() + 2 * mPipMenuBorderWidth;
-            pipFrameParams.height = mCurrentPipBounds.height() + 2 * mPipMenuBorderWidth;
-            mPipFrameView.setLayoutParams(pipFrameParams);
+        if (mPipFrameView.getVisibility() == VISIBLE) {
+            final ViewGroup.LayoutParams pipFrameParams = mPipFrameView.getLayoutParams();
+            if (pipFrameParams != null) {
+                pipFrameParams.width = mCurrentPipBounds.width() + 2 * mPipMenuBorderWidth;
+                pipFrameParams.height = mCurrentPipBounds.height() + 2 * mPipMenuBorderWidth;
+                mPipFrameView.setLayoutParams(pipFrameParams);
+            }
         }
 
         final ViewGroup.LayoutParams pipViewParams = mPipView.getLayoutParams();
@@ -262,7 +266,7 @@
     Rect getPipMenuContainerBounds(Rect pipBounds) {
         final Rect menuUiBounds = new Rect(pipBounds);
         menuUiBounds.inset(-mPipMenuOuterSpace, -mPipMenuOuterSpace);
-        menuUiBounds.bottom += mEduTextDrawer.getHeight();
+        menuUiBounds.bottom += mEduTextDrawer.getEduTextDrawerHeight();
         return menuUiBounds;
     }
 
@@ -406,6 +410,17 @@
     }
 
     @Override
+    public void onCloseEduTextAnimationStart() {
+        mListener.onCloseEduText();
+    }
+
+    @Override
+    public void onCloseEduTextAnimationEnd() {
+        mPipFrameView.setVisibility(GONE);
+        mEduTextContainer.setVisibility(GONE);
+    }
+
+    @Override
     public boolean dispatchKeyEvent(KeyEvent event) {
         if (event.getAction() == ACTION_UP) {
 
@@ -551,7 +566,7 @@
         }
     }
 
-    interface Listener extends TvPipMenuEduTextDrawer.Listener {
+    interface Listener {
 
         void onBackPress();
 
@@ -573,5 +588,11 @@
          * has lost focus.
          */
         void onPipWindowFocusChanged(boolean focused);
+
+        /**
+         *  The edu text closing impacts the size of the Picture-in-Picture window and influences
+         *  how it is positioned on the screen.
+         */
+        void onCloseEduText();
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
index c9b3a1a..c4a0e9c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
@@ -32,6 +32,8 @@
             Consts.TAG_WM_SHELL),
     WM_SHELL_TRANSITIONS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
             Consts.TAG_WM_SHELL),
+    WM_SHELL_RECENTS_TRANSITION(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
+            Consts.TAG_WM_SHELL),
     WM_SHELL_DRAG_AND_DROP(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
             Consts.TAG_WM_SHELL),
     WM_SHELL_STARTING_WINDOW(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
index a8b209f..b554872 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
@@ -47,7 +47,9 @@
 import android.window.WindowContainerToken;
 import android.window.WindowContainerTransaction;
 
+import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.transition.Transitions;
 import com.android.wm.shell.util.TransitionUtil;
@@ -96,6 +98,8 @@
 
     void startRecentsTransition(PendingIntent intent, Intent fillIn, Bundle options,
             IApplicationThread appThread, IRecentsAnimationRunner listener) {
+        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+                "RecentsTransitionHandler.startRecentsTransition");
         // only care about latest one.
         mAnimApp = appThread;
         WindowContainerTransaction wct = new WindowContainerTransaction();
@@ -116,7 +120,7 @@
             mixer.setRecentsTransition(transition);
         }
         if (transition == null) {
-            controller.cancel();
+            controller.cancel("startRecentsTransition");
             return;
         }
         controller.setTransition(transition);
@@ -127,6 +131,7 @@
     public WindowContainerTransaction handleRequest(IBinder transition,
             TransitionRequestInfo request) {
         // do not directly handle requests. Only entry point should be via startRecentsTransition
+        Slog.e(TAG, "RecentsTransitionHandler.handleRequest: Unexpected transition request");
         return null;
     }
 
@@ -143,11 +148,17 @@
             SurfaceControl.Transaction finishTransaction,
             Transitions.TransitionFinishCallback finishCallback) {
         final int controllerIdx = findController(transition);
-        if (controllerIdx < 0) return false;
+        if (controllerIdx < 0) {
+            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+                    "RecentsTransitionHandler.startAnimation: no controller found");
+            return false;
+        }
         final RecentsController controller = mControllers.get(controllerIdx);
         Transitions.setRunningRemoteTransitionDelegate(mAnimApp);
         mAnimApp = null;
         if (!controller.start(info, startTransaction, finishTransaction, finishCallback)) {
+            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+                    "RecentsTransitionHandler.startAnimation: failed to start animation");
             return false;
         }
         return true;
@@ -168,7 +179,7 @@
             SurfaceControl.Transaction finishTransaction) {
         final int idx = findController(transition);
         if (idx < 0) return;
-        mControllers.get(idx).cancel();
+        mControllers.get(idx).cancel("onTransitionConsumed");
     }
 
     /** There is only one of these and it gets reset on finish. */
@@ -213,27 +224,38 @@
 
         RecentsController(IRecentsAnimationRunner listener) {
             mListener = listener;
-            mDeathHandler = () -> finish(mWillFinishToHome, false /* leaveHint */);
+            mDeathHandler = () -> {
+                ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+                        "RecentsController.DeathRecipient: binder died");
+                finish(mWillFinishToHome, false /* leaveHint */);
+            };
             try {
                 mListener.asBinder().linkToDeath(mDeathHandler, 0 /* flags */);
             } catch (RemoteException e) {
+                Slog.e(TAG, "RecentsController: failed to link to death", e);
                 mListener = null;
             }
         }
 
         void setTransition(IBinder transition) {
+            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+                    "RecentsController.setTransition: id=%s", transition);
             mTransition = transition;
         }
 
-        void cancel() {
+        void cancel(String reason) {
             // restoring (to-home = false) involves submitting more WM changes, so by default, use
             // toHome = true when canceling.
-            cancel(true /* toHome */);
+            cancel(true /* toHome */, reason);
         }
 
-        void cancel(boolean toHome) {
+        void cancel(boolean toHome, String reason) {
+            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+                    "RecentsController.cancel: toHome=%b reason=%s", toHome, reason);
             if (mListener != null) {
                 try {
+                    ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+                            "RecentsController.cancel: calling onAnimationCanceled");
                     mListener.onAnimationCanceled(null, null);
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Error canceling recents animation", e);
@@ -267,6 +289,8 @@
                 }
             }
             try {
+                ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+                        "RecentsController.cancel: calling onAnimationCanceled with snapshots");
                 mListener.onAnimationCanceled(taskIds, snapshots);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Error canceling recents animation", e);
@@ -276,6 +300,7 @@
         }
 
         void cleanUp() {
+            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "RecentsController.cleanup");
             if (mListener != null && mDeathHandler != null) {
                 mListener.asBinder().unlinkToDeath(mDeathHandler, 0 /* flags */);
                 mDeathHandler = null;
@@ -299,6 +324,7 @@
 
         boolean start(TransitionInfo info, SurfaceControl.Transaction t,
                 SurfaceControl.Transaction finishT, Transitions.TransitionFinishCallback finishCB) {
+            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "RecentsController.start");
             if (mListener == null || mTransition == null) {
                 cleanUp();
                 return false;
@@ -358,6 +384,8 @@
                             info.getChanges().size() - i, info, t, mLeashMap);
                     apps.add(target);
                     if (TransitionUtil.isClosingType(change.getMode())) {
+                        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+                                "  adding pausing taskId=%d", taskInfo.taskId);
                         // raise closing (pausing) task to "above" layer so it isn't covered
                         t.setLayer(target.leash, info.getChanges().size() * 3 - i);
                         mPausingTasks.add(new TaskState(change, target.leash));
@@ -372,19 +400,23 @@
                     } else if (taskInfo != null && taskInfo.topActivityType == ACTIVITY_TYPE_HOME) {
                         // do nothing
                     } else if (TransitionUtil.isOpeningType(change.getMode())) {
+                        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+                                "  adding opening taskId=%d", taskInfo.taskId);
                         mOpeningTasks.add(new TaskState(change, target.leash));
                     }
                 }
             }
             t.apply();
             try {
+                ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+                        "RecentsController.start: calling onAnimationStart");
                 mListener.onAnimationStart(this,
                         apps.toArray(new RemoteAnimationTarget[apps.size()]),
                         wallpapers.toArray(new RemoteAnimationTarget[wallpapers.size()]),
                         new Rect(0, 0, 0, 0), new Rect());
             } catch (RemoteException e) {
                 Slog.e(TAG, "Error starting recents animation", e);
-                cancel();
+                cancel("onAnimationStart() failed");
             }
             return true;
         }
@@ -393,14 +425,19 @@
         void merge(TransitionInfo info, SurfaceControl.Transaction t,
                 Transitions.TransitionFinishCallback finishCallback) {
             if (mFinishCB == null) {
+                ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+                        "RecentsController.merge: skip, no finish callback");
                 // This was no-op'd (likely a repeated start) and we've already sent finish.
                 return;
             }
             if (info.getType() == TRANSIT_SLEEP) {
+                ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+                        "RecentsController.merge: transit_sleep");
                 // A sleep event means we need to stop animations immediately, so cancel here.
-                cancel();
+                cancel("transit_sleep");
                 return;
             }
+            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "RecentsController.merge");
             ArrayList<TransitionInfo.Change> openingTasks = null;
             ArrayList<TransitionInfo.Change> closingTasks = null;
             mOpeningSeparateHome = false;
@@ -417,7 +454,7 @@
                         && taskInfo.configuration.windowConfiguration.isAlwaysOnTop()) {
                     // Tasks that are always on top (e.g. bubbles), will handle their own transition
                     // as they are on top of everything else. So cancel the merge here.
-                    cancel();
+                    cancel("task #" + taskInfo.taskId + " is always_on_top");
                     return;
                 }
                 hasTaskChange = hasTaskChange || taskInfo != null;
@@ -448,7 +485,7 @@
                     // Finish recents animation if the display is changed, so the default
                     // transition handler can play the animation such as rotation effect.
                     if (change.hasFlags(TransitionInfo.FLAG_IS_DISPLAY)) {
-                        cancel(mWillFinishToHome);
+                        cancel(mWillFinishToHome, "display change");
                         return;
                     }
                     // Don't consider order-only changes as changing apps.
@@ -492,7 +529,10 @@
                                 + " something unexpected: " + change.getTaskInfo().taskId);
                         continue;
                     }
-                    mPausingTasks.add(mOpeningTasks.remove(openingIdx));
+                    final TaskState openingTask = mOpeningTasks.remove(openingIdx);
+                    ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+                            "  pausing opening taskId=%d", openingTask.mTaskInfo.taskId);
+                    mPausingTasks.add(openingTask);
                     didMergeThings = true;
                 }
             }
@@ -509,7 +549,10 @@
                         // Something is showing/opening a previously-pausing app.
                         appearedTargets[i] = TransitionUtil.newTarget(
                                 change, layer, mPausingTasks.get(pausingIdx).mLeash);
-                        mOpeningTasks.add(mPausingTasks.remove(pausingIdx));
+                        final TaskState pausingTask = mPausingTasks.remove(pausingIdx);
+                        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+                                "  opening pausing taskId=%d", pausingTask.mTaskInfo.taskId);
+                        mOpeningTasks.add(pausingTask);
                         // Setup hides opening tasks initially, so make it visible again (since we
                         // are already showing it).
                         t.show(change.getLeash());
@@ -522,6 +565,8 @@
                         final int rootIdx = TransitionUtil.rootIndexFor(change, mInfo);
                         t.reparent(appearedTargets[i].leash, mInfo.getRoot(rootIdx).getLeash());
                         t.setLayer(appearedTargets[i].leash, layer);
+                        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+                                "  opening new taskId=%d", appearedTargets[i].taskId);
                         mOpeningTasks.add(new TaskState(change, appearedTargets[i].leash));
                     }
                 }
@@ -539,7 +584,7 @@
                         + foundRecentsClosing);
                 if (foundRecentsClosing) {
                     mWillFinishToHome = false;
-                    cancel(false /* toHome */);
+                    cancel(false /* toHome */, "didn't merge");
                 }
                 return;
             }
@@ -549,6 +594,8 @@
             info.releaseAnimSurfaces();
             if (appearedTargets == null) return;
             try {
+                ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+                        "RecentsController.merge: calling onTasksAppeared");
                 mListener.onTasksAppeared(appearedTargets);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Error sending appeared tasks to recents animation", e);
@@ -572,6 +619,8 @@
         @Override
         public TaskSnapshot screenshotTask(int taskId) {
             try {
+                ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+                        "RecentsController.screenshotTask: taskId=%d", taskId);
                 return ActivityTaskManager.getService().takeTaskSnapshot(taskId);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Failed to screenshot task", e);
@@ -582,12 +631,19 @@
         @Override
         public void setInputConsumerEnabled(boolean enabled) {
             mExecutor.execute(() -> {
-                if (mFinishCB == null || !enabled) return;
+                if (mFinishCB == null || !enabled) {
+                    ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+                            "RecentsController.setInputConsumerEnabled: skip, cb?=%b enabled?=%b",
+                            mFinishCB != null, enabled);
+                    return;
+                }
                 // transient launches don't receive focus automatically. Since we are taking over
                 // the gesture now, take focus explicitly.
                 // This also moves recents back to top if the user gestured before a switch
                 // animation finished.
                 try {
+                    ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+                            "RecentsController.setInputConsumerEnabled: set focus to recents");
                     ActivityTaskManager.getService().setFocusedTask(mRecentsTaskId);
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Failed to set focused task", e);
@@ -602,6 +658,8 @@
         @Override
         public void setFinishTaskTransaction(int taskId,
                 PictureInPictureSurfaceTransaction finishTransaction, SurfaceControl overlay) {
+            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+                    "RecentsController.setFinishTaskTransaction: taskId=%d", taskId);
             mExecutor.execute(() -> {
                 if (mFinishCB == null) return;
                 mPipTransaction = finishTransaction;
@@ -619,6 +677,9 @@
                 Slog.e(TAG, "Duplicate call to finish");
                 return;
             }
+            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+                    "RecentsController.finishInner: toHome=%b userLeaveHint=%b willFinishToHome=%b",
+                    toHome, sendUserLeaveHint, mWillFinishToHome);
             final Transitions.TransitionFinishCallback finishCB = mFinishCB;
             mFinishCB = null;
 
@@ -630,6 +691,7 @@
                 else wct.restoreTransientOrder(mRecentsTask);
             }
             if (!toHome && !mWillFinishToHome && mPausingTasks != null && mState == STATE_NORMAL) {
+                ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "  returning to app");
                 // The gesture is returning to the pausing-task(s) rather than continuing with
                 // recents, so end the transition by moving the app back to the top (and also
                 // re-showing it's task).
@@ -642,6 +704,7 @@
                     wct.restoreTransientOrder(mRecentsTask);
                 }
             } else if (toHome && mOpeningSeparateHome && mPausingTasks != null) {
+                ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "  3p launching home");
                 // Special situation where 3p launcher was changed during recents (this happens
                 // during tapltests...). Here we get both "return to home" AND "home opening".
                 // This is basically going home, but we have to restore the recents and home order.
@@ -660,6 +723,7 @@
                     wct.restoreTransientOrder(mRecentsTask);
                 }
             } else {
+                ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "  normal finish");
                 // The general case: committing to recents, going home, or switching tasks.
                 for (int i = 0; i < mOpeningTasks.size(); ++i) {
                     t.show(mOpeningTasks.get(i).mTaskSurface);
@@ -716,6 +780,8 @@
          */
         @Override
         public void detachNavigationBarFromApp(boolean moveHomeToTop) {
+            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
+                    "RecentsController.detachNavigationBarFromApp");
             mExecutor.execute(() -> {
                 if (mTransition == null) return;
                 try {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index bdb7d44..08b0bf7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -429,6 +429,7 @@
                         && (change.getFlags() & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) == 0) {
                     t.setAlpha(leash, 0.f);
                 }
+                finishT.show(leash);
             } else if (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK) {
                 finishT.hide(leash);
             }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index d95c7a4..3d8bd38 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -135,12 +135,15 @@
         mShellExecutor.flushAll();
     }
 
-    private void createNavigationInfo(int backType, boolean enableAnimation) {
+    private void createNavigationInfo(int backType,
+            boolean enableAnimation,
+            boolean isAnimationCallback) {
         BackNavigationInfo.Builder builder = new BackNavigationInfo.Builder()
                 .setType(backType)
                 .setOnBackNavigationDone(new RemoteCallback((bundle) -> {}))
                 .setOnBackInvokedCallback(mAppCallback)
-                .setPrepareRemoteAnimation(enableAnimation);
+                .setPrepareRemoteAnimation(enableAnimation)
+                .setAnimationCallback(isAnimationCallback);
 
         createNavigationInfo(builder);
     }
@@ -218,7 +221,9 @@
     @Test
     public void backToHome_dispatchesEvents() throws RemoteException {
         registerAnimation(BackNavigationInfo.TYPE_RETURN_TO_HOME);
-        createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME, true);
+        createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME,
+                /* enableAnimation = */ true,
+                /* isAnimationCallback = */ false);
 
         doMotionEvent(MotionEvent.ACTION_DOWN, 0);
 
@@ -240,6 +245,32 @@
     }
 
     @Test
+    public void backToHomeWithAnimationCallback_dispatchesEvents() throws RemoteException {
+        registerAnimation(BackNavigationInfo.TYPE_RETURN_TO_HOME);
+        createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME,
+                /* enableAnimation = */ true,
+                /* isAnimationCallback = */ true);
+
+        doMotionEvent(MotionEvent.ACTION_DOWN, 0);
+
+        // Check that back start and progress is dispatched when first move.
+        doMotionEvent(MotionEvent.ACTION_MOVE, 100, 3000);
+
+        simulateRemoteAnimationStart(BackNavigationInfo.TYPE_RETURN_TO_HOME);
+
+        verify(mAnimatorCallback).onBackStarted(any(BackMotionEvent.class));
+        verify(mBackAnimationRunner).onAnimationStart(anyInt(), any(), any(), any(), any());
+        ArgumentCaptor<BackMotionEvent> backEventCaptor =
+                ArgumentCaptor.forClass(BackMotionEvent.class);
+        verify(mAnimatorCallback, atLeastOnce()).onBackProgressed(backEventCaptor.capture());
+
+        // Check that back invocation is dispatched.
+        mController.setTriggerBack(true);   // Fake trigger back
+        doMotionEvent(MotionEvent.ACTION_UP, 0);
+        verify(mAnimatorCallback).onBackInvoked();
+    }
+
+    @Test
     public void animationDisabledFromSettings() throws RemoteException {
         // Toggle the setting off
         Settings.Global.putString(mContentResolver, Settings.Global.ENABLE_BACK_ANIMATION, "0");
@@ -254,7 +285,9 @@
         ArgumentCaptor<BackMotionEvent> backEventCaptor =
                 ArgumentCaptor.forClass(BackMotionEvent.class);
 
-        createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME, false);
+        createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME,
+                /* enableAnimation = */ false,
+                /* isAnimationCallback = */ false);
 
         triggerBackGesture();
         releaseBackGesture();
@@ -271,7 +304,9 @@
     @Test
     public void ignoresGesture_transitionInProgress() throws RemoteException {
         registerAnimation(BackNavigationInfo.TYPE_RETURN_TO_HOME);
-        createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME, true);
+        createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME,
+                /* enableAnimation = */ true,
+                /* isAnimationCallback = */ false);
 
         triggerBackGesture();
         simulateRemoteAnimationStart(BackNavigationInfo.TYPE_RETURN_TO_HOME);
@@ -309,7 +344,9 @@
     @Test
     public void acceptsGesture_transitionTimeout() throws RemoteException {
         registerAnimation(BackNavigationInfo.TYPE_RETURN_TO_HOME);
-        createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME, true);
+        createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME,
+                /* enableAnimation = */ true,
+                /* isAnimationCallback = */ false);
 
         // In case it is still running in animation.
         doNothing().when(mAnimatorCallback).onBackInvoked();
@@ -334,7 +371,9 @@
     public void cancelBackInvokeWhenLostFocus() throws RemoteException {
         registerAnimation(BackNavigationInfo.TYPE_RETURN_TO_HOME);
 
-        createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME, true);
+        createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME,
+                /* enableAnimation = */ true,
+                /* isAnimationCallback = */ false);
 
         doMotionEvent(MotionEvent.ACTION_DOWN, 0);
         // Check that back start and progress is dispatched when first move.
@@ -454,7 +493,9 @@
 
         mController.registerAnimation(type, animationRunner);
 
-        createNavigationInfo(type, true);
+        createNavigationInfo(type,
+                /* enableAnimation = */ true,
+                /* isAnimationCallback = */ false);
 
         doMotionEvent(MotionEvent.ACTION_DOWN, 0);
 
@@ -473,11 +514,15 @@
     }
 
     private void doMotionEvent(int actionDown, int coordinate) {
+        doMotionEvent(actionDown, coordinate, 0);
+    }
+
+    private void doMotionEvent(int actionDown, int coordinate, float velocity) {
         mController.onMotionEvent(
                 /* touchX */ coordinate,
                 /* touchY */ coordinate,
-                /* velocityX = */ 0,
-                /* velocityY = */ 0,
+                /* velocityX = */ velocity,
+                /* velocityY = */ velocity,
                 /* keyAction */ actionDown,
                 /* swipeEdge */ BackEvent.EDGE_LEFT);
     }
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
index 4d2bb4c..8b74d76 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
@@ -18,6 +18,7 @@
 
 import android.app.Activity
 import android.os.IBinder
+import android.text.TextUtils
 import android.util.Log
 import androidx.activity.compose.ManagedActivityResultLauncher
 import androidx.activity.result.ActivityResult
@@ -67,9 +68,9 @@
 
     var uiMetrics: UIMetrics = UIMetrics()
 
-    init{
+    init {
         uiMetrics.logNormal(LifecycleEvent.CREDMAN_ACTIVITY_INIT,
-                credManRepo.requestInfo?.appPackageName)
+            credManRepo.requestInfo?.appPackageName)
     }
 
     /**************************************************************************/
@@ -100,7 +101,7 @@
         if (this.credManRepo.requestInfo?.token != credManRepo.requestInfo?.token) {
             this.uiMetrics.resetInstanceId()
             this.uiMetrics.logNormal(LifecycleEvent.CREDMAN_ACTIVITY_NEW_REQUEST,
-                    credManRepo.requestInfo?.appPackageName)
+                credManRepo.requestInfo?.appPackageName)
         }
     }
 
@@ -174,7 +175,7 @@
     private fun onInternalError() {
         Log.w(Constants.LOG_TAG, "UI closed due to illegal internal state")
         this.uiMetrics.logNormal(LifecycleEvent.CREDMAN_ACTIVITY_INTERNAL_ERROR,
-                credManRepo.requestInfo?.appPackageName)
+            credManRepo.requestInfo?.appPackageName)
         credManRepo.onParsingFailureCancel()
         uiState = uiState.copy(dialogState = DialogState.COMPLETE)
     }
@@ -314,10 +315,11 @@
         uiState = uiState.copy(
             createCredentialUiState = uiState.createCredentialUiState?.copy(
                 currentScreenState =
-                if (activeEntry.activeProvider.id ==
-                    userConfigRepo.getDefaultProviderId())
+                if (activeEntry.activeProvider.id == userConfigRepo.getDefaultProviderId() ||
+                    !TextUtils.isEmpty(uiState.createCredentialUiState?.requestDisplayInfo
+                        ?.appPreferredDefaultProviderId))
                     CreateScreenState.CREATION_OPTION_SELECTION
-                else CreateScreenState.MORE_OPTIONS_ROW_INTRO,
+                else CreateScreenState.DEFAULT_PROVIDER_CONFIRMATION,
                 activeEntry = activeEntry
             )
         )
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
index 96010cc..9d871ed 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
@@ -139,12 +139,12 @@
                                 onRemoteEntrySelected = viewModel::createFlowOnEntrySelected,
                                 onLog = { viewModel.logUiEvent(it) },
                         )
-                        CreateScreenState.MORE_OPTIONS_ROW_INTRO -> {
+                        CreateScreenState.DEFAULT_PROVIDER_CONFIRMATION -> {
                             if (createCredentialUiState.activeEntry == null) {
                                 viewModel.onIllegalUiState("Expect active entry to be non-null" +
                                         " upon default provider dialog.")
                             } else {
-                                MoreOptionsRowIntroCard(
+                                DefaultProviderConfirmationCard(
                                         selectedEntry = createCredentialUiState.activeEntry,
                                         onIllegalScreenState = viewModel::onIllegalUiState,
                                         onChangeDefaultSelected =
@@ -420,7 +420,7 @@
 }
 
 @Composable
-fun MoreOptionsRowIntroCard(
+fun DefaultProviderConfirmationCard(
         selectedEntry: ActiveEntry,
         onIllegalScreenState: (String) -> Unit,
         onChangeDefaultSelected: () -> Unit,
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
index 12bb629..225dbf2 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
@@ -126,6 +126,6 @@
   PROVIDER_SELECTION,
   CREATION_OPTION_SELECTION,
   MORE_OPTIONS_SELECTION,
-  MORE_OPTIONS_ROW_INTRO,
+  DEFAULT_PROVIDER_CONFIRMATION,
   EXTERNAL_ONLY_SELECTION,
 }
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java
index 96ea5b4..27aade5 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java
@@ -19,6 +19,7 @@
 import android.Manifest;
 import android.accessibilityservice.AccessibilityButtonController;
 import android.accessibilityservice.AccessibilityService;
+import android.app.KeyguardManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -82,6 +83,9 @@
 
     // TODO(b/136716947): Support multi-display once a11y framework side is ready.
     private DisplayManager mDisplayManager;
+
+    private KeyguardManager mKeyguardManager;
+
     private final DisplayManager.DisplayListener mDisplayListener =
             new DisplayManager.DisplayListener() {
         int mRotation;
@@ -114,7 +118,7 @@
     private final BroadcastReceiver mToggleMenuReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            mA11yMenuLayout.toggleVisibility();
+            toggleVisibility();
         }
     };
 
@@ -159,10 +163,7 @@
                      */
                     @Override
                     public void onClicked(AccessibilityButtonController controller) {
-                        if (SystemClock.uptimeMillis() - mLastTimeTouchedOutside
-                                > BUTTON_CLICK_TIMEOUT) {
-                            mA11yMenuLayout.toggleVisibility();
-                        }
+                        toggleVisibility();
                     }
 
                     /**
@@ -209,6 +210,7 @@
         mDisplayManager = getSystemService(DisplayManager.class);
         mDisplayManager.registerDisplayListener(mDisplayListener, null);
         mAudioManager = getSystemService(AudioManager.class);
+        mKeyguardManager = getSystemService(KeyguardManager.class);
 
         sInitialized = true;
     }
@@ -379,4 +381,12 @@
         }
         return false;
     }
+
+    private void toggleVisibility() {
+        boolean locked = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
+        if (!locked && SystemClock.uptimeMillis() - mLastTimeTouchedOutside
+                        > BUTTON_CLICK_TIMEOUT) {
+            mA11yMenuLayout.toggleVisibility();
+        }
+    }
 }
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java b/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java
index 7277392..9d1af0e 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java
+++ b/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java
@@ -33,6 +33,7 @@
 
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.app.Instrumentation;
+import android.app.KeyguardManager;
 import android.app.UiAutomation;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -44,6 +45,7 @@
 import android.os.PowerManager;
 import android.provider.Settings;
 import android.util.Log;
+import android.view.Display;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
 
@@ -69,15 +71,19 @@
     private static final int CLICK_ID = AccessibilityNodeInfo.ACTION_CLICK;
 
     private static final int TIMEOUT_SERVICE_STATUS_CHANGE_S = 5;
-    private static final int TIMEOUT_UI_CHANGE_S = 10;
+    private static final int TIMEOUT_UI_CHANGE_S = 5;
     private static final int NO_GLOBAL_ACTION = -1;
     private static final String INPUT_KEYEVENT_KEYCODE_BACK = "input keyevent KEYCODE_BACK";
+    private static final String TEST_PIN = "1234";
 
     private static Instrumentation sInstrumentation;
     private static UiAutomation sUiAutomation;
     private static AtomicInteger sLastGlobalAction;
 
     private static AccessibilityManager sAccessibilityManager;
+    private static PowerManager sPowerManager;
+    private static KeyguardManager sKeyguardManager;
+    private static DisplayManager sDisplayManager;
 
     @BeforeClass
     public static void classSetup() throws Throwable {
@@ -85,8 +91,14 @@
         sInstrumentation = InstrumentationRegistry.getInstrumentation();
         sUiAutomation = sInstrumentation.getUiAutomation(
                 UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
+        sUiAutomation.adoptShellPermissionIdentity(
+                UiAutomation.ALL_PERMISSIONS.toArray(new String[0]));
+
         final Context context = sInstrumentation.getTargetContext();
         sAccessibilityManager = context.getSystemService(AccessibilityManager.class);
+        sPowerManager = context.getSystemService(PowerManager.class);
+        sKeyguardManager = context.getSystemService(KeyguardManager.class);
+        sDisplayManager = context.getSystemService(DisplayManager.class);
 
         // Disable all a11yServices if any are active.
         if (!sAccessibilityManager.getEnabledAccessibilityServiceList(
@@ -123,12 +135,16 @@
 
     @AfterClass
     public static void classTeardown() throws Throwable {
+        clearPin();
         Settings.Secure.putString(sInstrumentation.getTargetContext().getContentResolver(),
                 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, "");
     }
 
     @Before
     public void setup() throws Throwable {
+        clearPin();
+        wakeUpScreen();
+        sUiAutomation.executeShellCommand("input keyevent KEYCODE_MENU");
         openMenu();
     }
 
@@ -138,11 +154,43 @@
         sLastGlobalAction.set(NO_GLOBAL_ACTION);
     }
 
+    private static void clearPin() throws Throwable {
+        sUiAutomation.executeShellCommand("locksettings clear --old " + TEST_PIN);
+        TestUtils.waitUntil("Device did not register as unlocked & insecure.",
+                TIMEOUT_SERVICE_STATUS_CHANGE_S,
+                () -> !sKeyguardManager.isDeviceSecure());
+    }
+
+    private static void setPin() throws Throwable {
+        sUiAutomation.executeShellCommand("locksettings set-pin " + TEST_PIN);
+        TestUtils.waitUntil("Device did not recognize as locked & secure.",
+                TIMEOUT_SERVICE_STATUS_CHANGE_S,
+                () -> sKeyguardManager.isDeviceSecure());
+    }
+
     private static boolean isMenuVisible() {
         AccessibilityNodeInfo root = sUiAutomation.getRootInActiveWindow();
         return root != null && root.getPackageName().toString().equals(PACKAGE_NAME);
     }
 
+    private static void wakeUpScreen() throws Throwable {
+        sUiAutomation.executeShellCommand("input keyevent KEYCODE_WAKEUP");
+        TestUtils.waitUntil("Screen did not wake up.",
+                TIMEOUT_UI_CHANGE_S,
+                () -> sPowerManager.isInteractive());
+    }
+
+    private static void closeScreen() throws Throwable {
+        Display display = sDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
+        setPin();
+        sUiAutomation.performGlobalAction(GLOBAL_ACTION_LOCK_SCREEN);
+        TestUtils.waitUntil("Screen did not close.",
+                TIMEOUT_UI_CHANGE_S,
+                () -> !sPowerManager.isInteractive()
+                        && display.getState() == Display.STATE_OFF
+        );
+    }
+
     private static void openMenu() throws Throwable {
         Intent intent = new Intent(PACKAGE_NAME + INTENT_TOGGLE_MENU);
         sInstrumentation.getContext().sendBroadcast(intent);
@@ -381,23 +429,24 @@
 
     @Test
     public void testOnScreenLock_closesMenu() throws Throwable {
-        openMenu();
-        Context context = sInstrumentation.getTargetContext();
-        PowerManager powerManager = context.getSystemService(PowerManager.class);
-
-        assertThat(powerManager).isNotNull();
-        assertThat(powerManager.isInteractive()).isTrue();
-
-        sUiAutomation.performGlobalAction(GLOBAL_ACTION_LOCK_SCREEN);
-        TestUtils.waitUntil("Screen did not become locked",
-                TIMEOUT_UI_CHANGE_S,
-                () -> !powerManager.isInteractive());
-
-        sUiAutomation.executeShellCommand("input keyevent KEYCODE_WAKEUP");
-        TestUtils.waitUntil("Screen did not wake up",
-                TIMEOUT_UI_CHANGE_S,
-                () -> powerManager.isInteractive());
+        closeScreen();
+        wakeUpScreen();
 
         assertThat(isMenuVisible()).isFalse();
     }
+
+    @Test
+    public void testOnScreenLock_cannotOpenMenu() throws Throwable {
+        closeScreen();
+        wakeUpScreen();
+
+        boolean timedOut = false;
+        try {
+            openMenu();
+        } catch (AssertionError e) {
+            // Expected
+            timedOut = true;
+        }
+        assertThat(timedOut).isTrue();
+    }
 }
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleAnimationConfig.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleAnimationConfig.kt
index 1786d13..91c0a5b 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleAnimationConfig.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleAnimationConfig.kt
@@ -19,17 +19,11 @@
     val maxHeight: Float = 0f,
     val pixelDensity: Float = 1f,
     var color: Int = Color.WHITE,
-    val opacity: Int = RIPPLE_DEFAULT_ALPHA,
-    val sparkleStrength: Float = RIPPLE_SPARKLE_STRENGTH,
+    val opacity: Int = RippleShader.RIPPLE_DEFAULT_ALPHA,
+    val sparkleStrength: Float = RippleShader.RIPPLE_SPARKLE_STRENGTH,
     // Null means it uses default fade parameter values.
     val baseRingFadeParams: RippleShader.FadeParams? = null,
     val sparkleRingFadeParams: RippleShader.FadeParams? = null,
     val centerFillFadeParams: RippleShader.FadeParams? = null,
     val shouldDistort: Boolean = true
-) {
-    companion object {
-        const val RIPPLE_SPARKLE_STRENGTH: Float = 0.3f
-        const val RIPPLE_DEFAULT_COLOR: Int = 0xffffffff.toInt()
-        const val RIPPLE_DEFAULT_ALPHA: Int = 115 // full opacity is 255.
-    }
-}
+)
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleShader.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleShader.kt
index b5b6037..7e56f4b 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleShader.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleShader.kt
@@ -60,6 +60,10 @@
         const val DEFAULT_CENTER_FILL_FADE_OUT_START = 0f
         const val DEFAULT_CENTER_FILL_FADE_OUT_END = 0.6f
 
+        const val RIPPLE_SPARKLE_STRENGTH: Float = 0.3f
+        const val RIPPLE_DEFAULT_COLOR: Int = 0xffffffff.toInt()
+        const val RIPPLE_DEFAULT_ALPHA: Int = 115 // full opacity is 255.
+
         private const val SHADER_UNIFORMS =
             """
             uniform vec2 in_center;
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleView.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleView.kt
index ef5ad43..b899127 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleView.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleView.kt
@@ -72,9 +72,9 @@
         this.rippleShape = rippleShape
         rippleShader = RippleShader(rippleShape)
 
-        rippleShader.color = RippleAnimationConfig.RIPPLE_DEFAULT_COLOR
+        rippleShader.color = RippleShader.RIPPLE_DEFAULT_COLOR
         rippleShader.rawProgress = 0f
-        rippleShader.sparkleStrength = RippleAnimationConfig.RIPPLE_SPARKLE_STRENGTH
+        rippleShader.sparkleStrength = RippleShader.RIPPLE_SPARKLE_STRENGTH
         rippleShader.pixelDensity = resources.displayMetrics.density
 
         ripplePaint.shader = rippleShader
@@ -209,7 +209,7 @@
      *
      * The alpha value of the color will be applied to the ripple. The alpha range is [0-255].
      */
-    fun setColor(color: Int, alpha: Int = RippleAnimationConfig.RIPPLE_DEFAULT_ALPHA) {
+    fun setColor(color: Int, alpha: Int = RippleShader.RIPPLE_DEFAULT_ALPHA) {
         rippleShader.color = ColorUtils.setAlphaComponent(color, alpha)
     }
 
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
index 204bac8..450c616 100644
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
+++ b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
@@ -316,9 +316,9 @@
     ),
     CLOCK_VIBRANT(
         CoreSpec(
-            a1 = TonalSpec(HueSource(), ChromaBound(ChromaSource(), 30.0, Chroma.MAX_VALUE)),
-            a2 = TonalSpec(HueAdd(20.0), ChromaBound(ChromaSource(), 30.0, Chroma.MAX_VALUE)),
-            a3 = TonalSpec(HueAdd(60.0), ChromaBound(ChromaSource(), 30.0, Chroma.MAX_VALUE)),
+            a1 = TonalSpec(HueSource(), ChromaBound(ChromaSource(), 70.0, Chroma.MAX_VALUE)),
+            a2 = TonalSpec(HueAdd(20.0), ChromaBound(ChromaSource(), 70.0, Chroma.MAX_VALUE)),
+            a3 = TonalSpec(HueAdd(60.0), ChromaBound(ChromaSource(), 70.0, Chroma.MAX_VALUE)),
 
             // Not Used
             n1 = TonalSpec(HueSource(), ChromaConstant(0.0)),
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt
index 5b0e290..461d390 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt
@@ -41,10 +41,10 @@
     var listeningForFaceAssistant: Boolean = false,
     var occludingAppRequestingFaceAuth: Boolean = false,
     var postureAllowsListening: Boolean = false,
-    var primaryUser: Boolean = false,
     var secureCameraLaunched: Boolean = false,
     var supportsDetect: Boolean = false,
     var switchingUser: Boolean = false,
+    var systemUser: Boolean = false,
     var udfpsFingerDown: Boolean = false,
     var userNotTrustedOrDetectionIsNeeded: Boolean = false,
 ) : KeyguardListenModel() {
@@ -69,11 +69,11 @@
             keyguardGoingAway.toString(),
             listeningForFaceAssistant.toString(),
             occludingAppRequestingFaceAuth.toString(),
-            primaryUser.toString(),
             postureAllowsListening.toString(),
             secureCameraLaunched.toString(),
             supportsDetect.toString(),
             switchingUser.toString(),
+            systemUser.toString(),
             alternateBouncerShowing.toString(),
             udfpsFingerDown.toString(),
             userNotTrustedOrDetectionIsNeeded.toString(),
@@ -109,12 +109,11 @@
                 keyguardGoingAway = model.keyguardGoingAway
                 listeningForFaceAssistant = model.listeningForFaceAssistant
                 occludingAppRequestingFaceAuth = model.occludingAppRequestingFaceAuth
-                primaryUser = model.primaryUser
                 postureAllowsListening = model.postureAllowsListening
                 secureCameraLaunched = model.secureCameraLaunched
                 supportsDetect = model.supportsDetect
                 switchingUser = model.switchingUser
-                switchingUser = model.switchingUser
+                systemUser = model.systemUser
                 udfpsFingerDown = model.udfpsFingerDown
                 userNotTrustedOrDetectionIsNeeded = model.userNotTrustedOrDetectionIsNeeded
             }
@@ -153,11 +152,11 @@
                 "keyguardGoingAway",
                 "listeningForFaceAssistant",
                 "occludingAppRequestingFaceAuth",
-                "primaryUser",
                 "postureAllowsListening",
                 "secureCameraLaunched",
                 "supportsDetect",
                 "switchingUser",
+                "systemUser",
                 "udfpsBouncerShowing",
                 "udfpsFingerDown",
                 "userNotTrustedOrDetectionIsNeeded",
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardFingerprintListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardFingerprintListenModel.kt
index b8c0ccb..f2685c5 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardFingerprintListenModel.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardFingerprintListenModel.kt
@@ -41,11 +41,11 @@
     var keyguardIsVisible: Boolean = false,
     var keyguardOccluded: Boolean = false,
     var occludingAppRequestingFp: Boolean = false,
-    var primaryUser: Boolean = false,
     var shouldListenSfpsState: Boolean = false,
     var shouldListenForFingerprintAssistant: Boolean = false,
     var strongerAuthRequired: Boolean = false,
     var switchingUser: Boolean = false,
+    var systemUser: Boolean = false,
     var udfps: Boolean = false,
     var userDoesNotHaveTrust: Boolean = false,
 ) : KeyguardListenModel() {
@@ -72,11 +72,11 @@
             keyguardIsVisible.toString(),
             keyguardOccluded.toString(),
             occludingAppRequestingFp.toString(),
-            primaryUser.toString(),
             shouldListenSfpsState.toString(),
             shouldListenForFingerprintAssistant.toString(),
             strongerAuthRequired.toString(),
             switchingUser.toString(),
+            systemUser.toString(),
             udfps.toString(),
             userDoesNotHaveTrust.toString(),
         )
@@ -112,11 +112,11 @@
                 keyguardIsVisible = model.keyguardIsVisible
                 keyguardOccluded = model.keyguardOccluded
                 occludingAppRequestingFp = model.occludingAppRequestingFp
-                primaryUser = model.primaryUser
                 shouldListenSfpsState = model.shouldListenSfpsState
                 shouldListenForFingerprintAssistant = model.shouldListenForFingerprintAssistant
                 strongerAuthRequired = model.strongerAuthRequired
                 switchingUser = model.switchingUser
+                systemUser = model.systemUser
                 udfps = model.udfps
                 userDoesNotHaveTrust = model.userDoesNotHaveTrust
             }
@@ -158,11 +158,11 @@
                 "keyguardIsVisible",
                 "keyguardOccluded",
                 "occludingAppRequestingFp",
-                "primaryUser",
                 "shouldListenSidFingerprintState",
                 "shouldListenForFingerprintAssistant",
                 "strongAuthRequired",
                 "switchingUser",
+                "systemUser",
                 "underDisplayFingerprint",
                 "userDoesNotHaveTrust",
             )
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 76e051e..693268d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -178,6 +178,7 @@
 
         @Override
         public void onUserInput() {
+            mKeyguardFaceAuthInteractor.onPrimaryBouncerUserInput();
             mUpdateMonitor.cancelFaceAuth();
         }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index ea04376..10c08bc 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -297,7 +297,7 @@
     private final Context mContext;
     private final UserTracker mUserTracker;
     private final KeyguardUpdateMonitorLogger mLogger;
-    private final boolean mIsPrimaryUser;
+    private final boolean mIsSystemUser;
     private final AuthController mAuthController;
     private final UiEventLogger mUiEventLogger;
     private final Set<Integer> mFaceAcquiredInfoIgnoreList;
@@ -2522,7 +2522,7 @@
         updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE, FACE_AUTH_UPDATED_ON_KEYGUARD_INIT);
 
         TaskStackChangeListeners.getInstance().registerTaskStackListener(mTaskStackListener);
-        mIsPrimaryUser = mUserManager.isPrimaryUser();
+        mIsSystemUser = mUserManager.isSystemUser();
         int user = mUserTracker.getUserId();
         mUserIsUnlocked.put(user, mUserManager.isUserUnlocked(user));
         mLogoutEnabled = mDevicePolicyManager.isLogoutEnabled();
@@ -2968,7 +2968,7 @@
                         || (mKeyguardOccluded && userDoesNotHaveTrust && mKeyguardShowing
                             && (mOccludingAppRequestingFp || isUdfps || mAlternateBouncerShowing));
 
-        // Only listen if this KeyguardUpdateMonitor belongs to the primary user. There is an
+        // Only listen if this KeyguardUpdateMonitor belongs to the system user. There is an
         // instance of KeyguardUpdateMonitor for each user but KeyguardUpdateMonitor is user-aware.
         final boolean biometricEnabledForUser = mBiometricEnabledForUser.get(user);
         final boolean userCanSkipBouncer = getUserCanSkipBouncer(user);
@@ -2977,7 +2977,7 @@
                 !mSwitchingUser
                         && !fingerprintDisabledForUser
                         && (!mKeyguardGoingAway || !mDeviceInteractive)
-                        && mIsPrimaryUser
+                        && mIsSystemUser
                         && biometricEnabledForUser
                         && !isUserInLockdown(user);
         final boolean strongerAuthRequired = !isUnlockingWithFingerprintAllowed();
@@ -3021,11 +3021,11 @@
                     isKeyguardVisible(),
                     mKeyguardOccluded,
                     mOccludingAppRequestingFp,
-                    mIsPrimaryUser,
                     shouldListenSideFpsState,
                     shouldListenForFingerprintAssistant,
                     strongerAuthRequired,
                     mSwitchingUser,
+                    mIsSystemUser,
                     isUdfps,
                     userDoesNotHaveTrust));
 
@@ -3070,7 +3070,7 @@
         final boolean shouldListenForFaceAssistant = shouldListenForFaceAssistant();
         final boolean isUdfpsFingerDown = mAuthController.isUdfpsFingerDown();
         final boolean isPostureAllowedForFaceAuth = doesPostureAllowFaceAuth(mPostureState);
-        // Only listen if this KeyguardUpdateMonitor belongs to the primary user. There is an
+        // Only listen if this KeyguardUpdateMonitor belongs to the system user. There is an
         // instance of KeyguardUpdateMonitor for each user but KeyguardUpdateMonitor is user-aware.
         final boolean shouldListen =
                 (mPrimaryBouncerFullyShown
@@ -3082,7 +3082,7 @@
                         || mAlternateBouncerShowing)
                 && !mSwitchingUser && !faceDisabledForUser && userNotTrustedOrDetectionIsNeeded
                 && !mKeyguardGoingAway && biometricEnabledForUser
-                && faceAuthAllowedOrDetectionIsNeeded && mIsPrimaryUser
+                && faceAuthAllowedOrDetectionIsNeeded && mIsSystemUser
                 && (!mSecureCameraLaunched || mAlternateBouncerShowing)
                 && faceAndFpNotAuthenticated
                 && !mGoingToSleep
@@ -3108,10 +3108,10 @@
                     shouldListenForFaceAssistant,
                     mOccludingAppRequestingFace,
                     isPostureAllowedForFaceAuth,
-                    mIsPrimaryUser,
                     mSecureCameraLaunched,
                     supportsDetect,
                     mSwitchingUser,
+                    mIsSystemUser,
                     isUdfpsFingerDown,
                     userNotTrustedOrDetectionIsNeeded));
 
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationSettingsController.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationSettingsController.java
index b6ee4cb..3349fe5 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationSettingsController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationSettingsController.java
@@ -24,6 +24,7 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.util.Range;
+import android.view.WindowManager;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
@@ -68,14 +69,18 @@
             @NonNull Callback settingsControllerCallback,
             SecureSettings secureSettings,
             WindowMagnificationSettings windowMagnificationSettings) {
-        mContext = context;
+        mContext = context.createWindowContext(
+                context.getDisplay(),
+                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
+                null);
+        mContext.setTheme(com.android.systemui.R.style.Theme_SystemUI);
         mDisplayId = mContext.getDisplayId();
-        mConfiguration = new Configuration(context.getResources().getConfiguration());
+        mConfiguration = new Configuration(mContext.getResources().getConfiguration());
         mSettingsControllerCallback = settingsControllerCallback;
         if (windowMagnificationSettings != null) {
             mWindowMagnificationSettings = windowMagnificationSettings;
         } else {
-            mWindowMagnificationSettings = new WindowMagnificationSettings(context,
+            mWindowMagnificationSettings = new WindowMagnificationSettings(mContext,
                     mWindowMagnificationSettingsCallback,
                     sfVsyncFrameProvider, secureSettings);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
index 71c5f24..6e8275f 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
@@ -559,7 +559,7 @@
         final LayoutParams params = new LayoutParams(
                 LayoutParams.WRAP_CONTENT,
                 LayoutParams.WRAP_CONTENT,
-                LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY,
+                LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
                 LayoutParams.FLAG_NOT_FOCUSABLE,
                 PixelFormat.TRANSPARENT);
         params.gravity = Gravity.TOP | Gravity.START;
diff --git a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
index 98a3e4b..11ef749 100644
--- a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
@@ -34,7 +34,6 @@
 import com.android.systemui.R;
 import com.android.systemui.animation.Interpolators;
 import com.android.systemui.shared.recents.utilities.Utilities;
-import com.android.systemui.surfaceeffects.ripple.RippleAnimationConfig;
 import com.android.systemui.surfaceeffects.ripple.RippleShader;
 import com.android.systemui.surfaceeffects.ripple.RippleShader.RippleShape;
 import com.android.systemui.surfaceeffects.ripple.RippleView;
@@ -177,7 +176,7 @@
             mRippleView.setBlur(6.5f, 2.5f);
         } else {
             mRippleView.setDuration(CIRCLE_RIPPLE_ANIMATION_DURATION);
-            mRippleView.setColor(color, RippleAnimationConfig.RIPPLE_DEFAULT_ALPHA);
+            mRippleView.setColor(color, RippleShader.RIPPLE_DEFAULT_ALPHA);
         }
 
         OnAttachStateChangeListener listener = new OnAttachStateChangeListener() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index e0af5ce..7a2013e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1957,11 +1957,12 @@
         if (mShowing && mKeyguardStateController.isShowing()) {
             if (mPM.isInteractive() && !mHiding) {
                 // It's already showing, and we're not trying to show it while the screen is off.
-                // We can simply reset all of the views.
+                // We can simply reset all of the views, but don't hide the bouncer in case the user
+                // is currently interacting with it.
                 if (DEBUG) Log.d(TAG, "doKeyguard: not showing (instead, resetting) because it is "
                         + "already showing, we're interactive, and we were not previously hiding. "
                         + "It should be safe to short-circuit here.");
-                resetStateLocked();
+                resetStateLocked(/* hideBouncer= */ false);
                 return;
             } else {
                 // We are trying to show the keyguard while the screen is off or while we were in
@@ -2035,8 +2036,12 @@
      * @see #handleReset
      */
     private void resetStateLocked() {
+        resetStateLocked(/* hideBouncer= */ true);
+    }
+
+    private void resetStateLocked(boolean hideBouncer) {
         if (DEBUG) Log.e(TAG, "resetStateLocked");
-        Message msg = mHandler.obtainMessage(RESET);
+        Message msg = mHandler.obtainMessage(RESET, hideBouncer ? 1 : 0, 0);
         mHandler.sendMessage(msg);
     }
 
@@ -2226,7 +2231,7 @@
                     handleHide();
                     break;
                 case RESET:
-                    handleReset();
+                    handleReset(msg.arg1 != 0);
                     break;
                 case VERIFY_UNLOCK:
                     Trace.beginSection("KeyguardViewMediator#handleMessage VERIFY_UNLOCK");
@@ -3008,10 +3013,10 @@
      * Handle message sent by {@link #resetStateLocked}
      * @see #RESET
      */
-    private void handleReset() {
+    private void handleReset(boolean hideBouncer) {
         synchronized (KeyguardViewMediator.this) {
             if (DEBUG) Log.d(TAG, "handleReset");
-            mKeyguardViewControllerLazy.get().reset(true /* hideBouncerWhenShowing */);
+            mKeyguardViewControllerLazy.get().reset(hideBouncer);
         }
 
         scheduleNonStrongBiometricIdleTimeout();
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
index 05ab01b..5f2178df 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
@@ -225,10 +225,17 @@
     }
 
     private fun observeFaceAuthResettingConditions() {
-        // Clear auth status when keyguard is going away or when the user is switching.
-        merge(keyguardRepository.isKeyguardGoingAway, userRepository.userSwitchingInProgress)
-            .onEach { goingAwayOrUserSwitchingInProgress ->
-                if (goingAwayOrUserSwitchingInProgress) {
+        // Clear auth status when keyguard is going away or when the user is switching or device
+        // starts going to sleep.
+        merge(
+                keyguardRepository.wakefulness.map {
+                    WakefulnessModel.isSleepingOrStartingToSleep(it)
+                },
+                keyguardRepository.isKeyguardGoingAway,
+                userRepository.userSwitchingInProgress
+            )
+            .onEach { anyOfThemIsTrue ->
+                if (anyOfThemIsTrue) {
                     _isAuthenticated.value = false
                     retryCount = 0
                     halErrorRetryJob?.cancel()
@@ -248,8 +255,8 @@
                     "nonStrongBiometricIsNotAllowed",
                     faceDetectLog
                 ),
-                // We don't want to run face detect if it's not possible to authenticate with FP
-                // from the bouncer. UDFPS is the only fp sensor type that won't support this.
+                // We don't want to run face detect if fingerprint can be used to unlock the device
+                // but it's not possible to authenticate with FP from the bouncer (UDFPS)
                 logAndObserve(
                     and(isUdfps(), deviceEntryFingerprintAuthRepository.isRunning).isFalse(),
                     "udfpsAuthIsNotPossibleAnymore",
@@ -306,7 +313,7 @@
                 logAndObserve(
                     combine(
                         keyguardInteractor.isSecureCameraActive,
-                        alternateBouncerInteractor.isVisible,
+                        alternateBouncerInteractor.isVisible
                     ) { a, b ->
                         !a || b
                     },
@@ -334,12 +341,12 @@
                 logAndObserve(isLockedOut.isFalse(), "isNotInLockOutState", faceAuthLog),
                 logAndObserve(
                     deviceEntryFingerprintAuthRepository.isLockedOut.isFalse(),
-                    "fpLockedOut",
+                    "fpIsNotLockedOut",
                     faceAuthLog
                 ),
                 logAndObserve(
                     trustRepository.isCurrentUserTrusted.isFalse(),
-                    "currentUserTrusted",
+                    "currentUserIsNotTrusted",
                     faceAuthLog
                 ),
                 logAndObserve(
@@ -347,11 +354,6 @@
                     "nonStrongBiometricIsAllowed",
                     faceAuthLog
                 ),
-                logAndObserve(
-                    userRepository.selectedUserInfo.map { it.isPrimary },
-                    "userIsPrimaryUser",
-                    faceAuthLog
-                ),
             )
             .reduce(::and)
             .distinctUntilChanged()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt
index 06ae11fe8..74ef7a5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt
@@ -59,6 +59,7 @@
     fun onQsExpansionStared()
     fun onNotificationPanelClicked()
     fun onSwipeUpOnBouncer()
+    fun onPrimaryBouncerUserInput()
 }
 
 /**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt
index cad40aa..5005b6c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt
@@ -59,4 +59,5 @@
     override fun onNotificationPanelClicked() {}
 
     override fun onSwipeUpOnBouncer() {}
+    override fun onPrimaryBouncerUserInput() {}
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt
index 20ebb71..6b515da 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt
@@ -151,6 +151,10 @@
         return featureFlags.isEnabled(Flags.FACE_AUTH_REFACTOR)
     }
 
+    override fun onPrimaryBouncerUserInput() {
+        repository.cancel()
+    }
+
     /** Provide the status of face authentication */
     override val authenticationStatus = repository.authenticationStatus
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt
index 5770f3e..ddce516 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt
@@ -47,6 +47,7 @@
             duration = TO_LOCKSCREEN_DURATION,
             onStep = { value -> -translatePx + value * translatePx },
             interpolator = EMPHASIZED_DECELERATE,
+            onCancel = { 0f },
         )
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index 7edb378..077ee02 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -136,6 +136,14 @@
         return factory.create("NotifRemoteInputLog", 50 /* maxSize */, false /* systrace */);
     }
 
+    /** Provides a logging buffer for all logs related to unseen notifications. */
+    @Provides
+    @SysUISingleton
+    @UnseenNotificationLog
+    public static LogBuffer provideUnseenNotificationLogBuffer(LogBufferFactory factory) {
+        return factory.create("UnseenNotifLog", 20 /* maxSize */, false /* systrace */);
+    }
+
     /** Provides a logging buffer for all logs related to the data layer of notifications. */
     @Provides
     @SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/UnseenNotificationLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/UnseenNotificationLog.java
new file mode 100644
index 0000000..5c2321b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/UnseenNotificationLog.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.log.dagger;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.android.systemui.plugins.log.LogBuffer;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+/** A {@link LogBuffer} for unseen notification related messages. */
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface UnseenNotificationLog {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 9e204e4..11c8c50 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -2809,6 +2809,7 @@
     @Override
     public void setBouncerShowing(boolean bouncerShowing) {
         mBouncerShowing = bouncerShowing;
+        mNotificationStackScrollLayoutController.updateShowEmptyShadeView();
         updateVisibility();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
index 4cbbefe..2fa070c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
@@ -21,8 +21,10 @@
 import android.os.UserHandle
 import android.provider.Settings
 import androidx.annotation.VisibleForTesting
+import com.android.systemui.Dumpable
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dump.DumpManager
 import com.android.systemui.keyguard.data.repository.KeyguardRepository
 import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -42,8 +44,14 @@
 import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider
 import com.android.systemui.statusbar.policy.HeadsUpManager
 import com.android.systemui.statusbar.policy.headsUpEvents
+import com.android.systemui.util.asIndenting
+import com.android.systemui.util.indentIfPossible
 import com.android.systemui.util.settings.SecureSettings
 import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
+import java.io.PrintWriter
+import javax.inject.Inject
+import kotlin.time.Duration
+import kotlin.time.Duration.Companion.seconds
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -57,13 +65,11 @@
 import kotlinx.coroutines.flow.first
 import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.flow.onStart
 import kotlinx.coroutines.flow.transformLatest
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.yield
-import javax.inject.Inject
-import kotlin.time.Duration
-import kotlin.time.Duration.Companion.seconds
 
 /**
  * Filters low priority and privacy-sensitive notifications from the lockscreen, and hides section
@@ -74,17 +80,19 @@
 @Inject
 constructor(
     @Background private val bgDispatcher: CoroutineDispatcher,
+    private val dumpManager: DumpManager,
     private val headsUpManager: HeadsUpManager,
     private val keyguardNotificationVisibilityProvider: KeyguardNotificationVisibilityProvider,
     private val keyguardRepository: KeyguardRepository,
     private val keyguardTransitionRepository: KeyguardTransitionRepository,
+    private val logger: KeyguardCoordinatorLogger,
     private val notifPipelineFlags: NotifPipelineFlags,
     @Application private val scope: CoroutineScope,
     private val sectionHeaderVisibilityProvider: SectionHeaderVisibilityProvider,
     private val secureSettings: SecureSettings,
     private val seenNotifsProvider: SeenNotificationsProviderImpl,
     private val statusBarStateController: StatusBarStateController,
-) : Coordinator {
+) : Coordinator, Dumpable {
 
     private val unseenNotifications = mutableSetOf<NotificationEntry>()
     private var unseenFilterEnabled = false
@@ -103,6 +111,7 @@
         pipeline.addCollectionListener(collectionListener)
         scope.launch { trackUnseenNotificationsWhileUnlocked() }
         scope.launch { invalidateWhenUnseenSettingChanges() }
+        dumpManager.registerDumpable(this)
     }
 
     private suspend fun trackUnseenNotificationsWhileUnlocked() {
@@ -122,14 +131,16 @@
                         // If the screen is turning off, stop tracking, but if that transition is
                         // cancelled, then start again.
                         emitAll(
-                            keyguardTransitionRepository.transitions
-                                .map { step -> !step.isScreenTurningOff }
+                            keyguardTransitionRepository.transitions.map { step ->
+                                !step.isScreenTurningOff
+                            }
                         )
                     }
                 }
                 // Prevent double emit of `false` caused by transition to AOD, followed by keyguard
                 // showing
                 .distinctUntilChanged()
+                .onEach { trackingUnseen -> logger.logTrackingUnseen(trackingUnseen) }
 
         // Use collectLatest so that trackUnseenNotifications() is cancelled when the keyguard is
         // showing again
@@ -140,9 +151,11 @@
                 // set when unlocked
                 awaitTimeSpentNotDozing(SEEN_TIMEOUT)
                 clearUnseenOnBeginTracking = true
+                logger.logSeenOnLockscreen()
             } else {
                 if (clearUnseenOnBeginTracking) {
                     clearUnseenOnBeginTracking = false
+                    logger.logAllMarkedSeenOnUnlock()
                     unseenNotifications.clear()
                 }
                 unseenNotifFilter.invalidateList("keyguard no longer showing")
@@ -166,6 +179,8 @@
             .first()
     }
 
+    // Track "unseen" notifications, marking them as seen when either shade is expanded or the
+    // notification becomes heads up.
     private suspend fun trackUnseenNotifications() {
         coroutineScope {
             launch { clearUnseenNotificationsWhenShadeIsExpanded() }
@@ -179,6 +194,7 @@
             // keyguard transition and not the user expanding the shade
             yield()
             if (isExpanded) {
+                logger.logShadeExpanded()
                 unseenNotifications.clear()
             }
         }
@@ -190,6 +206,7 @@
             .forEach { unseenNotifications.remove(it) }
         headsUpManager.headsUpEvents.collect { (entry, isHun) ->
             if (isHun) {
+                logger.logUnseenHun(entry.key)
                 unseenNotifications.remove(entry)
             }
         }
@@ -231,6 +248,7 @@
                 if (
                     keyguardRepository.isKeyguardShowing() || !statusBarStateController.isExpanded
                 ) {
+                    logger.logUnseenAdded(entry.key)
                     unseenNotifications.add(entry)
                 }
             }
@@ -239,12 +257,15 @@
                 if (
                     keyguardRepository.isKeyguardShowing() || !statusBarStateController.isExpanded
                 ) {
+                    logger.logUnseenUpdated(entry.key)
                     unseenNotifications.add(entry)
                 }
             }
 
             override fun onEntryRemoved(entry: NotificationEntry, reason: Int) {
-                unseenNotifications.remove(entry)
+                if (unseenNotifications.remove(entry)) {
+                    logger.logUnseenRemoved(entry.key)
+                }
             }
         }
 
@@ -272,6 +293,7 @@
                 }.also { hasFiltered -> hasFilteredAnyNotifs = hasFilteredAnyNotifs || hasFiltered }
 
             override fun onCleanup() {
+                logger.logProviderHasFilteredOutSeenNotifs(hasFilteredAnyNotifs)
                 seenNotifsProvider.hasFilteredOutSeenNotifications = hasFilteredAnyNotifs
                 hasFilteredAnyNotifs = false
             }
@@ -306,11 +328,25 @@
         sectionHeaderVisibilityProvider.sectionHeadersVisible = showSections
     }
 
+    override fun dump(pw: PrintWriter, args: Array<out String>) =
+        with(pw.asIndenting()) {
+            println(
+                "seenNotifsProvider.hasFilteredOutSeenNotifications=" +
+                    seenNotifsProvider.hasFilteredOutSeenNotifications
+            )
+            println("unseen notifications:")
+            indentIfPossible {
+                for (notification in unseenNotifications) {
+                    println(notification.key)
+                }
+            }
+        }
+
     companion object {
         private const val TAG = "KeyguardCoordinator"
         private val SEEN_TIMEOUT = 5.seconds
     }
 }
 
-private val TransitionStep.isScreenTurningOff: Boolean get() =
-    transitionState == TransitionState.STARTED && to != KeyguardState.GONE
\ No newline at end of file
+private val TransitionStep.isScreenTurningOff: Boolean
+    get() = transitionState == TransitionState.STARTED && to != KeyguardState.GONE
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorLogger.kt
new file mode 100644
index 0000000..6503a64
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorLogger.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.coordinator
+
+import com.android.systemui.log.dagger.UnseenNotificationLog
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
+import javax.inject.Inject
+
+private const val TAG = "KeyguardCoordinator"
+
+class KeyguardCoordinatorLogger
+@Inject
+constructor(
+    @UnseenNotificationLog private val buffer: LogBuffer,
+) {
+    fun logSeenOnLockscreen() =
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            "Notifications on lockscreen will be marked as seen when unlocked."
+        )
+
+    fun logTrackingUnseen(trackingUnseen: Boolean) =
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            messageInitializer = { bool1 = trackingUnseen },
+            messagePrinter = { "${if (bool1) "Start" else "Stop"} tracking unseen notifications." },
+        )
+
+    fun logAllMarkedSeenOnUnlock() =
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            "Notifications have been marked as seen now that device is unlocked."
+        )
+
+    fun logShadeExpanded() =
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            "Notifications have been marked as seen due to shade expansion."
+        )
+
+    fun logUnseenAdded(key: String) =
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            messageInitializer = { str1 = key },
+            messagePrinter = { "Unseen notif added: $str1" },
+        )
+
+    fun logUnseenUpdated(key: String) =
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            messageInitializer = { str1 = key },
+            messagePrinter = { "Unseen notif updated: $str1" },
+        )
+
+    fun logUnseenRemoved(key: String) =
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            messageInitializer = { str1 = key },
+            messagePrinter = { "Unseen notif removed: $str1" },
+        )
+
+    fun logProviderHasFilteredOutSeenNotifs(hasFilteredAnyNotifs: Boolean) =
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            messageInitializer = { bool1 = hasFilteredAnyNotifs },
+            messagePrinter = { "UI showing unseen filter treatment: $bool1" },
+        )
+
+    fun logUnseenHun(key: String) =
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            messageInitializer = { str1 = key },
+            messagePrinter = { "Unseen notif has become heads up: $str1" },
+        )
+}
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 e2f93ce..4177263 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
@@ -1235,7 +1235,8 @@
                 // Hide empty shade view when in transition to Keyguard.
                 // That avoids "No Notifications" to blink when transitioning to AOD.
                 // For more details, see: b/228790482
-                && !isInTransitionToKeyguard();
+                && !isInTransitionToKeyguard()
+                && !mCentralSurfaces.isBouncerShowing();
 
         mView.updateEmptyShadeView(shouldShow, mZenModeController.areNotificationsHiddenInShade());
 
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index ed40eed..2962c14 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -291,7 +291,7 @@
         when(mSessionTracker.getSessionId(SESSION_KEYGUARD)).thenReturn(mKeyguardInstanceId);
 
         when(mUserManager.isUserUnlocked(anyInt())).thenReturn(true);
-        when(mUserManager.isPrimaryUser()).thenReturn(true);
+        currentUserIsSystem();
         when(mStrongAuthTracker.getStub()).thenReturn(mock(IStrongAuthTracker.Stub.class));
         when(mStrongAuthTracker
                 .isUnlockingWithBiometricAllowed(anyBoolean() /* isClass3Biometric */))
@@ -960,7 +960,7 @@
     public void requestFaceAuth_whenFaceAuthWasStarted_returnsTrue() throws RemoteException {
         // This satisfies all the preconditions to run face auth.
         keyguardNotGoingAway();
-        currentUserIsPrimary();
+        currentUserIsSystem();
         currentUserDoesNotHaveTrust();
         biometricsNotDisabledThroughDevicePolicyManager();
         biometricsEnabledForCurrentUser();
@@ -1467,7 +1467,7 @@
 
         // Preconditions for sfps auth to run
         keyguardNotGoingAway();
-        currentUserIsPrimary();
+        currentUserIsSystem();
         currentUserDoesNotHaveTrust();
         biometricsNotDisabledThroughDevicePolicyManager();
         biometricsEnabledForCurrentUser();
@@ -1503,7 +1503,7 @@
 
         // GIVEN Preconditions for sfps auth to run
         keyguardNotGoingAway();
-        currentUserIsPrimary();
+        currentUserIsSystem();
         currentUserDoesNotHaveTrust();
         biometricsNotDisabledThroughDevicePolicyManager();
         biometricsEnabledForCurrentUser();
@@ -1532,7 +1532,7 @@
 
         // GIVEN Preconditions for sfps auth to run
         keyguardNotGoingAway();
-        currentUserIsPrimary();
+        currentUserIsSystem();
         currentUserDoesNotHaveTrust();
         biometricsNotDisabledThroughDevicePolicyManager();
         biometricsEnabledForCurrentUser();
@@ -1684,7 +1684,7 @@
         // Face auth should run when the following is true.
         keyguardNotGoingAway();
         occludingAppRequestsFaceAuth();
-        currentUserIsPrimary();
+        currentUserIsSystem();
         primaryAuthNotRequiredByStrongAuthTracker();
         biometricsEnabledForCurrentUser();
         currentUserDoesNotHaveTrust();
@@ -1705,7 +1705,7 @@
         // Face auth should run when the following is true.
         bouncerFullyVisibleAndNotGoingToSleep();
         keyguardNotGoingAway();
-        currentUserIsPrimary();
+        currentUserIsSystem();
         primaryAuthNotRequiredByStrongAuthTracker();
         biometricsEnabledForCurrentUser();
         currentUserDoesNotHaveTrust();
@@ -1728,7 +1728,7 @@
         // Face auth should run when the following is true.
         bouncerFullyVisibleAndNotGoingToSleep();
         keyguardNotGoingAway();
-        currentUserIsPrimary();
+        currentUserIsSystem();
         primaryAuthNotRequiredByStrongAuthTracker();
         biometricsEnabledForCurrentUser();
         currentUserDoesNotHaveTrust();
@@ -1749,7 +1749,7 @@
     public void testShouldListenForFace_whenUserIsNotPrimary_returnsFalse() throws RemoteException {
         cleanupKeyguardUpdateMonitor();
         // This disables face auth
-        when(mUserManager.isPrimaryUser()).thenReturn(false);
+        when(mUserManager.isSystemUser()).thenReturn(false);
         mKeyguardUpdateMonitor =
                 new TestableKeyguardUpdateMonitor(mContext);
 
@@ -1773,7 +1773,7 @@
         // Face auth should run when the following is true.
         keyguardNotGoingAway();
         bouncerFullyVisibleAndNotGoingToSleep();
-        currentUserIsPrimary();
+        currentUserIsSystem();
         biometricsEnabledForCurrentUser();
         currentUserDoesNotHaveTrust();
         biometricsNotDisabledThroughDevicePolicyManager();
@@ -1791,7 +1791,7 @@
             throws RemoteException {
         keyguardNotGoingAway();
         bouncerFullyVisibleAndNotGoingToSleep();
-        currentUserIsPrimary();
+        currentUserIsSystem();
         currentUserDoesNotHaveTrust();
         biometricsNotDisabledThroughDevicePolicyManager();
         biometricsEnabledForCurrentUser();
@@ -1813,7 +1813,7 @@
         // Face auth should run when the following is true.
         keyguardNotGoingAway();
         bouncerFullyVisibleAndNotGoingToSleep();
-        currentUserIsPrimary();
+        currentUserIsSystem();
         currentUserDoesNotHaveTrust();
         biometricsNotDisabledThroughDevicePolicyManager();
         biometricsEnabledForCurrentUser();
@@ -1833,7 +1833,7 @@
             throws RemoteException {
         keyguardNotGoingAway();
         bouncerFullyVisibleAndNotGoingToSleep();
-        currentUserIsPrimary();
+        currentUserIsSystem();
         currentUserDoesNotHaveTrust();
         biometricsNotDisabledThroughDevicePolicyManager();
         biometricsEnabledForCurrentUser();
@@ -1854,7 +1854,7 @@
         // Face auth should run when the following is true.
         keyguardNotGoingAway();
         bouncerFullyVisibleAndNotGoingToSleep();
-        currentUserIsPrimary();
+        currentUserIsSystem();
         currentUserDoesNotHaveTrust();
         biometricsNotDisabledThroughDevicePolicyManager();
         biometricsEnabledForCurrentUser();
@@ -1876,7 +1876,7 @@
             throws RemoteException {
         // Face auth should run when the following is true.
         keyguardNotGoingAway();
-        currentUserIsPrimary();
+        currentUserIsSystem();
         currentUserDoesNotHaveTrust();
         biometricsNotDisabledThroughDevicePolicyManager();
         biometricsEnabledForCurrentUser();
@@ -1896,7 +1896,7 @@
             throws RemoteException {
         // Face auth should run when the following is true.
         keyguardNotGoingAway();
-        currentUserIsPrimary();
+        currentUserIsSystem();
         currentUserDoesNotHaveTrust();
         biometricsNotDisabledThroughDevicePolicyManager();
         biometricsEnabledForCurrentUser();
@@ -1915,7 +1915,7 @@
     public void testShouldListenForFace_whenKeyguardIsAwake_returnsTrue() throws RemoteException {
         // Preconditions for face auth to run
         keyguardNotGoingAway();
-        currentUserIsPrimary();
+        currentUserIsSystem();
         currentUserDoesNotHaveTrust();
         biometricsNotDisabledThroughDevicePolicyManager();
         biometricsEnabledForCurrentUser();
@@ -1940,7 +1940,7 @@
     public void testShouldListenForFace_whenUdfpsFingerDown_returnsTrue() throws RemoteException {
         // Preconditions for face auth to run
         keyguardNotGoingAway();
-        currentUserIsPrimary();
+        currentUserIsSystem();
         currentUserDoesNotHaveTrust();
         biometricsNotDisabledThroughDevicePolicyManager();
         biometricsEnabledForCurrentUser();
@@ -1959,7 +1959,7 @@
             throws RemoteException {
         // Preconditions for face auth to run
         keyguardNotGoingAway();
-        currentUserIsPrimary();
+        currentUserIsSystem();
         currentUserDoesNotHaveTrust();
         biometricsNotDisabledThroughDevicePolicyManager();
         biometricsEnabledForCurrentUser();
@@ -1977,7 +1977,7 @@
             throws RemoteException {
         // Preconditions for face auth to run
         keyguardNotGoingAway();
-        currentUserIsPrimary();
+        currentUserIsSystem();
         currentUserDoesNotHaveTrust();
         biometricsNotDisabledThroughDevicePolicyManager();
         biometricsEnabledForCurrentUser();
@@ -2002,7 +2002,7 @@
             throws RemoteException {
         // Preconditions for face auth to run
         keyguardNotGoingAway();
-        currentUserIsPrimary();
+        currentUserIsSystem();
         currentUserDoesNotHaveTrust();
         biometricsNotDisabledThroughDevicePolicyManager();
         biometricsEnabledForCurrentUser();
@@ -2324,7 +2324,7 @@
             throws RemoteException {
         keyguardNotGoingAway();
         bouncerFullyVisibleAndNotGoingToSleep();
-        currentUserIsPrimary();
+        currentUserIsSystem();
         currentUserDoesNotHaveTrust();
         biometricsNotDisabledThroughDevicePolicyManager();
         biometricsEnabledForCurrentUser();
@@ -2455,7 +2455,7 @@
         mKeyguardUpdateMonitor.mConfigFaceAuthSupportedPosture = DEVICE_POSTURE_CLOSED;
         keyguardNotGoingAway();
         bouncerFullyVisibleAndNotGoingToSleep();
-        currentUserIsPrimary();
+        currentUserIsSystem();
         currentUserDoesNotHaveTrust();
         biometricsNotDisabledThroughDevicePolicyManager();
         biometricsEnabledForCurrentUser();
@@ -2479,7 +2479,7 @@
         mKeyguardUpdateMonitor.mConfigFaceAuthSupportedPosture = DEVICE_POSTURE_UNKNOWN;
         keyguardNotGoingAway();
         bouncerFullyVisibleAndNotGoingToSleep();
-        currentUserIsPrimary();
+        currentUserIsSystem();
         currentUserDoesNotHaveTrust();
         biometricsNotDisabledThroughDevicePolicyManager();
         biometricsEnabledForCurrentUser();
@@ -2877,8 +2877,8 @@
                         new FaceManager.AuthenticationResult(null, null, mCurrentUserId, false));
     }
 
-    private void currentUserIsPrimary() {
-        when(mUserManager.isPrimaryUser()).thenReturn(true);
+    private void currentUserIsSystem() {
+        when(mUserManager.isSystemUser()).thenReturn(true);
     }
 
     private void biometricsNotDisabledThroughDevicePolicyManager() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 0de9608..8f58140 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -502,7 +502,7 @@
         TestableLooper.get(this).processAllMessages();
 
         assertTrue(mViewMediator.isShowingAndNotOccluded());
-        verify(mStatusBarKeyguardViewManager).reset(anyBoolean());
+        verify(mStatusBarKeyguardViewManager).reset(false);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
index a76d03b..fa40fc4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
@@ -72,7 +72,6 @@
 import java.io.PrintWriter
 import java.io.StringWriter
 import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.launch
 import kotlinx.coroutines.test.StandardTestDispatcher
 import kotlinx.coroutines.test.TestDispatcher
 import kotlinx.coroutines.test.TestScope
@@ -542,14 +541,6 @@
         }
 
     @Test
-    fun authenticateDoesNotRunWhenCurrentUserIsNotPrimary() =
-        testScope.runTest {
-            testGatingCheckForFaceAuth {
-                launch { fakeUserRepository.setSelectedUserInfo(secondaryUser) }
-            }
-        }
-
-    @Test
     fun authenticateDoesNotRunWhenSecureCameraIsActive() =
         testScope.runTest {
             testGatingCheckForFaceAuth {
@@ -653,6 +644,58 @@
         }
 
     @Test
+    fun isAuthenticatedIsResetToFalseWhenDeviceStartsGoingToSleep() =
+        testScope.runTest {
+            initCollectors()
+            allPreconditionsToRunFaceAuthAreTrue()
+
+            triggerFaceAuth(false)
+
+            authenticationCallback.value.onAuthenticationSucceeded(
+                mock(FaceManager.AuthenticationResult::class.java)
+            )
+
+            assertThat(authenticated()).isTrue()
+
+            keyguardRepository.setWakefulnessModel(
+                WakefulnessModel(
+                    WakefulnessState.STARTING_TO_SLEEP,
+                    isWakingUpOrAwake = false,
+                    lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                    lastSleepReason = WakeSleepReason.POWER_BUTTON
+                )
+            )
+
+            assertThat(authenticated()).isFalse()
+        }
+
+    @Test
+    fun isAuthenticatedIsResetToFalseWhenDeviceGoesToSleep() =
+        testScope.runTest {
+            initCollectors()
+            allPreconditionsToRunFaceAuthAreTrue()
+
+            triggerFaceAuth(false)
+
+            authenticationCallback.value.onAuthenticationSucceeded(
+                mock(FaceManager.AuthenticationResult::class.java)
+            )
+
+            assertThat(authenticated()).isTrue()
+
+            keyguardRepository.setWakefulnessModel(
+                WakefulnessModel(
+                    WakefulnessState.ASLEEP,
+                    isWakingUpOrAwake = false,
+                    lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                    lastSleepReason = WakeSleepReason.POWER_BUTTON
+                )
+            )
+
+            assertThat(authenticated()).isFalse()
+        }
+
+    @Test
     fun isAuthenticatedIsResetToFalseWhenUserIsSwitching() =
         testScope.runTest {
             initCollectors()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
index 3d1d2f4..5da1a84 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
@@ -279,6 +279,23 @@
         }
 
     @Test
+    fun faceAuthIsCancelledWhenUserInputOnPrimaryBouncer() =
+        testScope.runTest {
+            underTest.start()
+
+            underTest.onSwipeUpOnBouncer()
+
+            runCurrent()
+            assertThat(faceAuthRepository.isAuthRunning.value).isTrue()
+
+            underTest.onPrimaryBouncerUserInput()
+
+            runCurrent()
+
+            assertThat(faceAuthRepository.isAuthRunning.value).isFalse()
+        }
+
+    @Test
     fun faceAuthIsRequestedWhenSwipeUpOnBouncer() =
         testScope.runTest {
             underTest.start()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt
index 0c4e845..efa5f0c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt
@@ -92,6 +92,21 @@
             job.cancel()
         }
 
+    @Test
+    fun lockscreenTranslationYResettedAfterJobCancelled() =
+        runTest(UnconfinedTestDispatcher()) {
+            val values = mutableListOf<Float>()
+
+            val pixels = 100
+            val job =
+                underTest.lockscreenTranslationY(pixels).onEach { values.add(it) }.launchIn(this)
+            repository.sendTransitionStep(step(0.5f, TransitionState.CANCELED))
+
+            assertThat(values.last()).isEqualTo(0f)
+
+            job.cancel()
+        }
+
     private fun step(
         value: Float,
         state: TransitionState = TransitionState.RUNNING
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
index 8f07f8d..c3f5123 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
@@ -24,6 +24,7 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.advanceTimeBy
+import com.android.systemui.dump.DumpManager
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -380,10 +381,12 @@
         val keyguardCoordinator =
             KeyguardCoordinator(
                 testDispatcher,
+                mock<DumpManager>(),
                 headsUpManager,
                 keyguardNotifVisibilityProvider,
                 keyguardRepository,
                 keyguardTransitionRepository,
+                mock<KeyguardCoordinatorLogger>(),
                 notifPipelineFlags,
                 testScope.backgroundScope,
                 sectionHeaderVisibilityProvider,
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 0bdb0c8..0d973d9 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1443,17 +1443,19 @@
             return;
         }
         if (!mVisibleBgUserIds.get(userId)) {
-            Slogf.wtf(LOG_TAG, "Cannot change current user to %d as it's not visible "
-                    + "(mVisibleUsers=%s)", userId, mVisibleBgUserIds);
+            Slogf.wtf(LOG_TAG, "changeCurrentUserForTestAutomationIfNeededLocked(): cannot change "
+                    + "current user to %d as it's not visible (mVisibleUsers=%s)",
+                    userId, mVisibleBgUserIds);
             return;
         }
         if (mCurrentUserId == userId) {
-            Slogf.w(LOG_TAG, "NOT changing current user for test automation purposes as it is "
-                    + "already %d", mCurrentUserId);
+            Slogf.d(LOG_TAG, "changeCurrentUserForTestAutomationIfNeededLocked(): NOT changing "
+                    + "current user for test automation purposes as it is already %d",
+                    mCurrentUserId);
             return;
         }
-        Slogf.i(LOG_TAG, "Changing current user from %d to %d for test automation purposes",
-                mCurrentUserId, userId);
+        Slogf.i(LOG_TAG, "changeCurrentUserForTestAutomationIfNeededLocked(): changing current user"
+                + " from %d to %d for test automation purposes", mCurrentUserId, userId);
         mRealCurrentUserId = mCurrentUserId;
         switchUser(userId);
     }
@@ -1466,7 +1468,13 @@
                     + "because device doesn't support visible background users");
             return;
         }
-        Slogf.i(LOG_TAG, "Restoring current user to %d after using %d for test automation purposes",
+        if (mRealCurrentUserId == UserHandle.USER_CURRENT) {
+            Slogf.d(LOG_TAG, "restoreCurrentUserForTestAutomationIfNeededLocked(): ignoring "
+                    + "because mRealCurrentUserId is already USER_CURRENT");
+            return;
+        }
+        Slogf.i(LOG_TAG, "restoreCurrentUserForTestAutomationIfNeededLocked(): restoring current "
+                + "user to %d after using %d for test automation purposes",
                 mRealCurrentUserId, mCurrentUserId);
         int currentUserId = mRealCurrentUserId;
         mRealCurrentUserId = UserHandle.USER_CURRENT;
diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
index b042c30..ff72476 100644
--- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
+++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
@@ -397,7 +397,7 @@
                             setUpPipes();
                             mAgent = mBackupManagerService.bindToAgentSynchronous(mTargetApp,
                                     FullBackup.KEY_VALUE_DATA_TOKEN.equals(info.domain)
-                                            ? ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL
+                                            ? ApplicationThreadConstants.BACKUP_MODE_RESTORE
                                             : ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL,
                                     mBackupEligibilityRules.getBackupDestination());
                             mAgentPackage = pkg;
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index 1656b6f..77990af 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -677,7 +677,7 @@
         // Good to go!  Set up and bind the agent...
         mAgent = backupManagerService.bindToAgentSynchronous(
                 mCurrentPackage.applicationInfo,
-                ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL,
+                ApplicationThreadConstants.BACKUP_MODE_RESTORE,
                 mBackupEligibilityRules.getBackupDestination());
         if (mAgent == null) {
             Slog.w(TAG, "Can't find backup agent for " + packageName);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 81dc346..1f80aec 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -4603,8 +4603,7 @@
             boolean isRestrictedBackupMode = false;
             if (backupTarget != null && backupTarget.appInfo.packageName.equals(processName)) {
                 isRestrictedBackupMode = backupTarget.appInfo.uid >= FIRST_APPLICATION_UID
-                        && ((backupTarget.backupMode == BackupRecord.RESTORE)
-                                || (backupTarget.backupMode == BackupRecord.RESTORE_FULL)
+                        && ((backupTarget.backupMode == BackupRecord.RESTORE_FULL)
                                 || (backupTarget.backupMode == BackupRecord.BACKUP_FULL));
             }
 
@@ -13394,7 +13393,8 @@
 
             BackupRecord r = new BackupRecord(app, backupMode, targetUserId, backupDestination);
             ComponentName hostingName =
-                    (backupMode == ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL)
+                    (backupMode == ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL
+                            || backupMode == ApplicationThreadConstants.BACKUP_MODE_RESTORE)
                             ? new ComponentName(app.packageName, app.backupAgentName)
                             : new ComponentName("android", "FullBackupAgent");
 
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index a3163e0..02c4770 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -2284,8 +2284,8 @@
                 synchronized (VolumeStreamState.class) {
                     mStreamStates[AudioSystem.STREAM_DTMF]
                             .setAllIndexes(mStreamStates[dtmfStreamAlias], caller);
-                    mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].mVolumeIndexSettingName =
-                            System.VOLUME_SETTINGS_INT[a11yStreamAlias];
+                    mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].setSettingName(
+                            System.VOLUME_SETTINGS_INT[a11yStreamAlias]);
                     mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].setAllIndexes(
                             mStreamStates[a11yStreamAlias], caller);
                 }
@@ -7700,7 +7700,7 @@
         private int mPublicStreamType = AudioSystem.STREAM_MUSIC;
         private AudioAttributes mAudioAttributes = AudioProductStrategy.getDefaultAttributes();
         private boolean mIsMuted = false;
-        private final String mSettingName;
+        private String mSettingName;
 
         // No API in AudioSystem to get a device from strategy or from attributes.
         // Need a valid public stream type to use current API getDeviceForStream
@@ -8029,15 +8029,19 @@
         }
 
         private void persistVolumeGroup(int device) {
-            if (mUseFixedVolume) {
+            // No need to persist the index if the volume group is backed up
+            // by a public stream type as this is redundant
+            if (mUseFixedVolume || mHasValidStreamType) {
                 return;
             }
             if (DEBUG_VOL) {
                 Log.v(TAG, "persistVolumeGroup: storing index " + getIndex(device) + " for group "
                         + mAudioVolumeGroup.name()
                         + ", device " + AudioSystem.getOutputDeviceName(device)
-                        + " and User=" + getCurrentUserId());
+                        + " and User=" + getCurrentUserId()
+                        + " mSettingName: " + mSettingName);
             }
+
             boolean success = mSettings.putSystemIntForUser(mContentResolver,
                     getSettingNameForDevice(device),
                     getIndex(device),
@@ -8100,6 +8104,14 @@
             return mSettingName + "_" + AudioSystem.getOutputDeviceName(device);
         }
 
+        void setSettingName(String settingName) {
+            mSettingName = settingName;
+        }
+
+        String getSettingName() {
+            return mSettingName;
+        }
+
         private void dump(PrintWriter pw) {
             pw.println("- VOLUME GROUP " + mAudioVolumeGroup.name() + ":");
             pw.print("   Muted: ");
@@ -8242,6 +8254,9 @@
          */
         public void setVolumeGroupState(VolumeGroupState volumeGroupState) {
             mVolumeGroupState = volumeGroupState;
+            if (mVolumeGroupState != null) {
+                mVolumeGroupState.setSettingName(mVolumeIndexSettingName);
+            }
         }
         /**
          * Update the minimum index that can be used without MODIFY_AUDIO_SETTINGS permission
@@ -8315,6 +8330,17 @@
             return (mVolumeIndexSettingName != null && !mVolumeIndexSettingName.isEmpty());
         }
 
+        void setSettingName(String settingName) {
+            mVolumeIndexSettingName = settingName;
+            if (mVolumeGroupState != null) {
+                mVolumeGroupState.setSettingName(mVolumeIndexSettingName);
+            }
+        }
+
+        String getSettingName() {
+            return mVolumeIndexSettingName;
+        }
+
         public void readSettings() {
             synchronized (mSettingsLock) {
                 synchronized (VolumeStreamState.class) {
@@ -8989,7 +9015,7 @@
             if (streamState.hasValidSettingsName()) {
                 mSettings.putSystemIntForUser(mContentResolver,
                         streamState.getSettingNameForDevice(device),
-                        (streamState.getIndex(device) + 5)/ 10,
+                        (streamState.getIndex(device) + 5) / 10,
                         UserHandle.USER_CURRENT);
             }
         }
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 85b4034..5d92c7f 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -119,7 +119,6 @@
 import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.text.TextUtils;
-import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.EventLog;
 import android.util.IntArray;
@@ -298,11 +297,10 @@
             mDisplayWindowPolicyControllers = new SparseArray<>();
 
     /**
-     *  Map of every internal primary display device {@link HighBrightnessModeMetadata}s indexed by
-     *  {@link DisplayDevice#mUniqueId}.
+     * Provides {@link HighBrightnessModeMetadata}s for {@link DisplayDevice}s.
      */
-    public final ArrayMap<String, HighBrightnessModeMetadata> mHighBrightnessModeMetadataMap =
-            new ArrayMap<>();
+    private final HighBrightnessModeMetadataMapper mHighBrightnessModeMetadataMapper =
+            new HighBrightnessModeMetadataMapper();
 
     // List of all currently registered display adapters.
     private final ArrayList<DisplayAdapter> mDisplayAdapters = new ArrayList<DisplayAdapter>();
@@ -1823,19 +1821,14 @@
 
         DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(displayId);
         if (dpc != null) {
-            final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
-            if (device == null) {
-                Slog.wtf(TAG, "Display Device is null in DisplayManagerService for display: "
-                        + display.getDisplayIdLocked());
-                return;
-            }
-
             final int leadDisplayId = display.getLeadDisplayIdLocked();
             updateDisplayPowerControllerLeaderLocked(dpc, leadDisplayId);
 
-            final String uniqueId = device.getUniqueId();
-            HighBrightnessModeMetadata hbmMetadata = mHighBrightnessModeMetadataMap.get(uniqueId);
-            dpc.onDisplayChanged(hbmMetadata, leadDisplayId);
+            HighBrightnessModeMetadata hbmMetadata =
+                    mHighBrightnessModeMetadataMapper.getHighBrightnessModeMetadataLocked(display);
+            if (hbmMetadata != null) {
+                dpc.onDisplayChanged(hbmMetadata, leadDisplayId);
+            }
         }
     }
 
@@ -1922,19 +1915,14 @@
         final int displayId = display.getDisplayIdLocked();
         final DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(displayId);
         if (dpc != null) {
-            final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
-            if (device == null) {
-                Slog.wtf(TAG, "Display Device is null in DisplayManagerService for display: "
-                        + display.getDisplayIdLocked());
-                return;
-            }
-
             final int leadDisplayId = display.getLeadDisplayIdLocked();
             updateDisplayPowerControllerLeaderLocked(dpc, leadDisplayId);
 
-            final String uniqueId = device.getUniqueId();
-            HighBrightnessModeMetadata hbmMetadata = mHighBrightnessModeMetadataMap.get(uniqueId);
-            dpc.onDisplayChanged(hbmMetadata, leadDisplayId);
+            HighBrightnessModeMetadata hbmMetadata =
+                    mHighBrightnessModeMetadataMapper.getHighBrightnessModeMetadataLocked(display);
+            if (hbmMetadata != null) {
+                dpc.onDisplayChanged(hbmMetadata, leadDisplayId);
+            }
         }
     }
 
@@ -3073,26 +3061,6 @@
         mLogicalDisplayMapper.forEachLocked(this::addDisplayPowerControllerLocked);
     }
 
-    private HighBrightnessModeMetadata getHighBrightnessModeMetadata(LogicalDisplay display) {
-        final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
-        if (device == null) {
-            Slog.wtf(TAG, "Display Device is null in DisplayPowerController for display: "
-                    + display.getDisplayIdLocked());
-            return null;
-        }
-
-        final String uniqueId = device.getUniqueId();
-
-        if (mHighBrightnessModeMetadataMap.containsKey(uniqueId)) {
-            return mHighBrightnessModeMetadataMap.get(uniqueId);
-        }
-
-        // HBM Time info not present. Create a new one for this physical display.
-        HighBrightnessModeMetadata hbmInfo = new HighBrightnessModeMetadata();
-        mHighBrightnessModeMetadataMap.put(uniqueId, hbmInfo);
-        return hbmInfo;
-    }
-
     @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG)
     private void addDisplayPowerControllerLocked(LogicalDisplay display) {
         if (mPowerHandler == null) {
@@ -3113,7 +3081,13 @@
         // We also need to pass a mapping of the HighBrightnessModeTimeInfoMap to
         // displayPowerController, so the hbm info can be correctly associated
         // with the corresponding displaydevice.
-        HighBrightnessModeMetadata hbmMetadata = getHighBrightnessModeMetadata(display);
+        HighBrightnessModeMetadata hbmMetadata =
+                mHighBrightnessModeMetadataMapper.getHighBrightnessModeMetadataLocked(display);
+        if (hbmMetadata == null) {
+            Slog.wtf(TAG, "High Brightness Mode Metadata is null in DisplayManagerService for "
+                    + "display: " + display.getDisplayIdLocked());
+            return;
+        }
         if (DeviceConfig.getBoolean("display_manager",
                 "use_newly_structured_display_power_controller", true)) {
             displayPowerController = new DisplayPowerController2(
diff --git a/services/core/java/com/android/server/display/HighBrightnessModeMetadataMapper.java b/services/core/java/com/android/server/display/HighBrightnessModeMetadataMapper.java
new file mode 100644
index 0000000..76702d3
--- /dev/null
+++ b/services/core/java/com/android/server/display/HighBrightnessModeMetadataMapper.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+import android.util.ArrayMap;
+import android.util.Slog;
+
+/**
+ * Provides {@link HighBrightnessModeMetadata}s for {@link DisplayDevice}s. This class should only
+ * be accessed from the display thread.
+ */
+class HighBrightnessModeMetadataMapper {
+
+    private static final String TAG = "HighBrightnessModeMetadataMapper";
+
+    /**
+     *  Map of every internal primary display device {@link HighBrightnessModeMetadata}s indexed by
+     *  {@link DisplayDevice#mUniqueId}.
+     */
+    private final ArrayMap<String, HighBrightnessModeMetadata> mHighBrightnessModeMetadataMap =
+            new ArrayMap<>();
+
+    HighBrightnessModeMetadata getHighBrightnessModeMetadataLocked(LogicalDisplay display) {
+        final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
+        if (device == null) {
+            Slog.wtf(TAG, "Display Device is null in DisplayPowerController for display: "
+                    + display.getDisplayIdLocked());
+            return null;
+        }
+
+        final String uniqueId = device.getUniqueId();
+
+        if (mHighBrightnessModeMetadataMap.containsKey(uniqueId)) {
+            return mHighBrightnessModeMetadataMap.get(uniqueId);
+        }
+
+        // HBM Time info not present. Create a new one for this physical display.
+        HighBrightnessModeMetadata hbmInfo = new HighBrightnessModeMetadata();
+        mHighBrightnessModeMetadataMap.put(uniqueId, hbmInfo);
+        return hbmInfo;
+    }
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 9eedc4e..f47c4b2 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -682,7 +682,6 @@
     @ServiceThreadOnly
     private void launchDeviceDiscovery() {
         assertRunOnServiceThread();
-        clearDeviceInfoList();
         DeviceDiscoveryAction action = new DeviceDiscoveryAction(this,
                 new DeviceDiscoveryCallback() {
                     @Override
@@ -691,13 +690,6 @@
                             mService.getHdmiCecNetwork().addCecDevice(info);
                         }
 
-                        // Since we removed all devices when it starts and
-                        // device discovery action does not poll local devices,
-                        // we should put device info of local device manually here
-                        for (HdmiCecLocalDevice device : mService.getAllCecLocalDevices()) {
-                            mService.getHdmiCecNetwork().addCecDevice(device.getDeviceInfo());
-                        }
-
                         mSelectRequestBuffer.process();
                         resetSelectRequestBuffer();
 
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 805ff66..75fe63a 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -1267,6 +1267,7 @@
         // It's now safe to flush existing local devices from mCecController since they were
         // already moved to 'localDevices'.
         clearCecLocalDevices();
+        mHdmiCecNetwork.clearDeviceList();
         allocateLogicalAddress(localDevices, initiatedBy);
     }
 
@@ -1303,6 +1304,7 @@
                                         HdmiControlManager.POWER_STATUS_ON, getCecVersion());
                                 localDevice.setDeviceInfo(deviceInfo);
                                 mHdmiCecNetwork.addLocalDevice(deviceType, localDevice);
+                                mHdmiCecNetwork.addCecDevice(localDevice.getDeviceInfo());
                                 mCecController.addLogicalAddress(logicalAddress);
                                 allocatedDevices.add(localDevice);
                             }
diff --git a/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java b/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
index 0ae1e80..a1b67e1 100644
--- a/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
+++ b/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
@@ -18,14 +18,19 @@
 
 import static android.view.inputmethod.ImeTracker.DEBUG_IME_VISIBILITY;
 
+import static com.android.internal.inputmethod.SoftInputShowHideReason.REMOVE_IME_SCREENSHOT_FROM_IMMS;
+import static com.android.internal.inputmethod.SoftInputShowHideReason.SHOW_IME_SCREENSHOT_FROM_IMMS;
 import static com.android.server.EventLogTags.IMF_HIDE_IME;
 import static com.android.server.EventLogTags.IMF_SHOW_IME;
 import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME;
 import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME_EXPLICIT;
 import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME_NOT_ALWAYS;
+import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_REMOVE_IME_SNAPSHOT;
 import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_SHOW_IME;
 import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_SHOW_IME_IMPLICIT;
+import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_SHOW_IME_SNAPSHOT;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.IBinder;
 import android.os.ResultReceiver;
@@ -38,6 +43,7 @@
 import com.android.internal.inputmethod.InputMethodDebug;
 import com.android.internal.inputmethod.SoftInputShowHideReason;
 import com.android.server.LocalServices;
+import com.android.server.wm.ImeTargetVisibilityPolicy;
 import com.android.server.wm.WindowManagerInternal;
 
 import java.util.Objects;
@@ -56,10 +62,14 @@
 
     private final WindowManagerInternal mWindowManagerInternal;
 
+    @NonNull
+    private final ImeTargetVisibilityPolicy mImeTargetVisibilityPolicy;
+
 
     DefaultImeVisibilityApplier(InputMethodManagerService service) {
         mService = service;
         mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
+        mImeTargetVisibilityPolicy = LocalServices.getService(ImeTargetVisibilityPolicy.class);
     }
 
     @GuardedBy("ImfLock.class")
@@ -162,8 +172,37 @@
                 mService.showCurrentInputLocked(windowToken, statsToken,
                         InputMethodManager.SHOW_IMPLICIT, null, reason);
                 break;
+            case STATE_SHOW_IME_SNAPSHOT:
+                showImeScreenshot(windowToken, mService.getDisplayIdToShowImeLocked(), null);
+                break;
+            case STATE_REMOVE_IME_SNAPSHOT:
+                removeImeScreenshot(mService.getDisplayIdToShowImeLocked());
+                break;
             default:
                 throw new IllegalArgumentException("Invalid IME visibility state: " + state);
         }
     }
+
+    @GuardedBy("ImfLock.class")
+    @Override
+    public boolean showImeScreenshot(@NonNull IBinder imeTarget, int displayId,
+            @Nullable ImeTracker.Token statsToken) {
+        if (mImeTargetVisibilityPolicy.showImeScreenshot(imeTarget, displayId)) {
+            mService.onShowHideSoftInputRequested(false /* show */, imeTarget,
+                    SHOW_IME_SCREENSHOT_FROM_IMMS, statsToken);
+            return true;
+        }
+        return false;
+    }
+
+    @GuardedBy("ImfLock.class")
+    @Override
+    public boolean removeImeScreenshot(int displayId) {
+        if (mImeTargetVisibilityPolicy.removeImeScreenshot(displayId)) {
+            mService.onShowHideSoftInputRequested(false /* show */, mService.mCurFocusedWindow,
+                    REMOVE_IME_SCREENSHOT_FROM_IMMS, null);
+            return true;
+        }
+        return false;
+    }
 }
diff --git a/services/core/java/com/android/server/inputmethod/ImeVisibilityApplier.java b/services/core/java/com/android/server/inputmethod/ImeVisibilityApplier.java
index f03e985..27f6a89 100644
--- a/services/core/java/com/android/server/inputmethod/ImeVisibilityApplier.java
+++ b/services/core/java/com/android/server/inputmethod/ImeVisibilityApplier.java
@@ -16,6 +16,7 @@
 
 package com.android.server.inputmethod;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.IBinder;
 import android.os.ResultReceiver;
@@ -76,4 +77,27 @@
         // TODO: add a method in WindowManagerInternal to call DC#updateImeInputAndControlTarget
         //  here to end up updating IME layering after IMMS#attachNewInputLocked called.
     }
+
+    /**
+     * Shows the IME screenshot and attach it to the given IME target window.
+     *
+     * @param windowToken The token of a window to show the IME screenshot.
+     * @param displayId The unique id to identify the display
+     * @param statsToken  A token that tracks the progress of an IME request.
+     * @return {@code true} if success, {@code false} otherwise.
+     */
+    default boolean showImeScreenshot(@NonNull IBinder windowToken, int displayId,
+            @Nullable ImeTracker.Token statsToken) {
+        return false;
+    }
+
+    /**
+     * Removes the IME screenshot on the given display.
+     *
+     * @param displayId The target display of showing IME screenshot.
+     * @return {@code true} if success, {@code false} otherwise.
+     */
+    default boolean removeImeScreenshot(int displayId) {
+        return false;
+    }
 }
diff --git a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
index 61fe654..19d6fa0 100644
--- a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
+++ b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
@@ -29,6 +29,8 @@
 import static android.view.WindowManager.LayoutParams.SoftInputModeFlags;
 
 import static com.android.internal.inputmethod.InputMethodDebug.softInputModeToString;
+import static com.android.internal.inputmethod.SoftInputShowHideReason.REMOVE_IME_SCREENSHOT_FROM_IMMS;
+import static com.android.internal.inputmethod.SoftInputShowHideReason.SHOW_IME_SCREENSHOT_FROM_IMMS;
 import static com.android.server.inputmethod.InputMethodManagerService.computeImeDisplayIdForTarget;
 
 import android.accessibilityservice.AccessibilityService;
@@ -49,6 +51,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.inputmethod.SoftInputShowHideReason;
 import com.android.server.LocalServices;
+import com.android.server.wm.ImeTargetChangeListener;
 import com.android.server.wm.WindowManagerInternal;
 
 import java.io.PrintWriter;
@@ -99,6 +102,18 @@
      */
     private boolean mInputShown;
 
+    /**
+     * Set if we called
+     * {@link com.android.server.wm.ImeTargetVisibilityPolicy#showImeScreenshot(IBinder, int)}.
+     */
+    private boolean mRequestedImeScreenshot;
+
+    /** The window token of the current visible IME layering target overlay. */
+    private IBinder mCurVisibleImeLayeringOverlay;
+
+    /** The window token of the current visible IME input target. */
+    private IBinder mCurVisibleImeInputTarget;
+
     /** Represent the invalid IME visibility state */
     public static final int STATE_INVALID = -1;
 
@@ -122,6 +137,10 @@
     public static final int STATE_HIDE_IME_NOT_ALWAYS = 6;
 
     public static final int STATE_SHOW_IME_IMPLICIT = 7;
+
+    /** State to handle removing an IME preview surface when necessary. */
+    public static final int STATE_REMOVE_IME_SNAPSHOT = 8;
+
     @IntDef({
             STATE_INVALID,
             STATE_HIDE_IME,
@@ -132,6 +151,7 @@
             STATE_HIDE_IME_EXPLICIT,
             STATE_HIDE_IME_NOT_ALWAYS,
             STATE_SHOW_IME_IMPLICIT,
+            STATE_REMOVE_IME_SNAPSHOT,
     })
     @interface VisibilityState {}
 
@@ -172,6 +192,24 @@
         mWindowManagerInternal = wmService;
         mImeDisplayValidator = imeDisplayValidator;
         mPolicy = imePolicy;
+        mWindowManagerInternal.setInputMethodTargetChangeListener(new ImeTargetChangeListener() {
+            @Override
+            public void onImeTargetOverlayVisibilityChanged(IBinder overlayWindowToken,
+                    boolean visible, boolean removed) {
+                mCurVisibleImeLayeringOverlay = (visible && !removed) ? overlayWindowToken : null;
+            }
+
+            @Override
+            public void onImeInputTargetVisibilityChanged(IBinder imeInputTarget,
+                    boolean visibleRequested, boolean removed) {
+                mCurVisibleImeInputTarget = (visibleRequested && !removed) ? imeInputTarget : null;
+                if (mCurVisibleImeInputTarget == null && mCurVisibleImeLayeringOverlay != null) {
+                    mService.onApplyImeVisibilityFromComputer(imeInputTarget,
+                            new ImeVisibilityResult(STATE_HIDE_IME_EXPLICIT,
+                                    SoftInputShowHideReason.HIDE_WHEN_INPUT_TARGET_INVISIBLE));
+                }
+            }
+        });
     }
 
     /**
@@ -453,6 +491,21 @@
         return null;
     }
 
+    @VisibleForTesting
+    ImeVisibilityResult onInteractiveChanged(IBinder windowToken, boolean interactive) {
+        final ImeTargetWindowState state = getWindowStateOrNull(windowToken);
+        if (state != null && state.isRequestedImeVisible() && mInputShown && !interactive) {
+            mRequestedImeScreenshot = true;
+            return new ImeVisibilityResult(STATE_SHOW_IME_SNAPSHOT, SHOW_IME_SCREENSHOT_FROM_IMMS);
+        }
+        if (interactive && mRequestedImeScreenshot) {
+            mRequestedImeScreenshot = false;
+            return new ImeVisibilityResult(STATE_REMOVE_IME_SNAPSHOT,
+                    REMOVE_IME_SCREENSHOT_FROM_IMMS);
+        }
+        return null;
+    }
+
     IBinder getWindowTokenFrom(IBinder requestImeToken) {
         for (IBinder windowToken : mRequestWindowStateMap.keySet()) {
             final ImeTargetWindowState state = mRequestWindowStateMap.get(windowToken);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 2433211..c70d555 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -4847,6 +4847,14 @@
         }
     }
 
+    void onApplyImeVisibilityFromComputer(IBinder windowToken,
+            @NonNull ImeVisibilityResult result) {
+        synchronized (ImfLock.class) {
+            mVisibilityApplier.applyImeVisibility(windowToken, null, result.getState(),
+                    result.getReason());
+        }
+    }
+
     @GuardedBy("ImfLock.class")
     void setEnabledSessionLocked(SessionState session) {
         if (mEnabledSession != session) {
@@ -5083,6 +5091,14 @@
                 return;
             }
             if (mImePlatformCompatUtils.shouldUseSetInteractiveProtocol(getCurMethodUidLocked())) {
+                // Handle IME visibility when interactive changed before finishing the input to
+                // ensure we preserve the last state as possible.
+                final ImeVisibilityResult imeVisRes = mVisibilityStateComputer.onInteractiveChanged(
+                        mCurFocusedWindow, interactive);
+                if (imeVisRes != null) {
+                    mVisibilityApplier.applyImeVisibility(mCurFocusedWindow, null,
+                            imeVisRes.getState(), imeVisRes.getReason());
+                }
                 // Eligible IME processes use new "setInteractive" protocol.
                 mCurClient.mClient.setInteractive(mIsInteractive, mInFullscreenMode);
             } else {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index ebcbfed..07891f3 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -10796,7 +10796,8 @@
         static final String FLAG_SEPARATOR = "\\|";
 
         private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
-        ArrayMap<Pair<ComponentName, Integer>, NotificationListenerFilter>
+        @GuardedBy("mRequestedNotificationListeners")
+        private final ArrayMap<Pair<ComponentName, Integer>, NotificationListenerFilter>
                 mRequestedNotificationListeners = new ArrayMap<>();
         private final boolean mIsHeadlessSystemUserMode;
 
@@ -10914,9 +10915,11 @@
         @Override
         public void onUserRemoved(int user) {
             super.onUserRemoved(user);
-            for (int i = mRequestedNotificationListeners.size() - 1; i >= 0; i--) {
-                if (mRequestedNotificationListeners.keyAt(i).second == user) {
-                    mRequestedNotificationListeners.removeAt(i);
+            synchronized (mRequestedNotificationListeners) {
+                for (int i = mRequestedNotificationListeners.size() - 1; i >= 0; i--) {
+                    if (mRequestedNotificationListeners.keyAt(i).second == user) {
+                        mRequestedNotificationListeners.removeAt(i);
+                    }
                 }
             }
         }
@@ -10925,31 +10928,34 @@
         public void onPackagesChanged(boolean removingPackage, String[] pkgList, int[] uidList) {
             super.onPackagesChanged(removingPackage, pkgList, uidList);
 
-            // Since the default behavior is to allow everything, we don't need to explicitly
-            // handle package add or update. they will be added to the xml file on next boot or
-            // when the user tries to change the settings.
-            if (removingPackage) {
-                for (int i = 0; i < pkgList.length; i++) {
-                    String pkg = pkgList[i];
-                    int userId = UserHandle.getUserId(uidList[i]);
-                    for (int j = mRequestedNotificationListeners.size() - 1; j >= 0; j--) {
-                        Pair<ComponentName, Integer> key = mRequestedNotificationListeners.keyAt(j);
-                        if (key.second == userId && key.first.getPackageName().equals(pkg)) {
-                            mRequestedNotificationListeners.removeAt(j);
+            synchronized (mRequestedNotificationListeners) {
+                // Since the default behavior is to allow everything, we don't need to explicitly
+                // handle package add or update. they will be added to the xml file on next boot or
+                // when the user tries to change the settings.
+                if (removingPackage) {
+                    for (int i = 0; i < pkgList.length; i++) {
+                        String pkg = pkgList[i];
+                        int userId = UserHandle.getUserId(uidList[i]);
+                        for (int j = mRequestedNotificationListeners.size() - 1; j >= 0; j--) {
+                            Pair<ComponentName, Integer> key =
+                                    mRequestedNotificationListeners.keyAt(j);
+                            if (key.second == userId && key.first.getPackageName().equals(pkg)) {
+                                mRequestedNotificationListeners.removeAt(j);
+                            }
                         }
                     }
                 }
-            }
 
-            // clean up anything in the disallowed pkgs list
-            for (int i = 0; i < pkgList.length; i++) {
-                String pkg = pkgList[i];
-                int userId = UserHandle.getUserId(uidList[i]);
-                for (int j = mRequestedNotificationListeners.size() - 1; j >= 0; j--) {
-                    NotificationListenerFilter nlf = mRequestedNotificationListeners.valueAt(j);
+                // clean up anything in the disallowed pkgs list
+                for (int i = 0; i < pkgList.length; i++) {
+                    String pkg = pkgList[i];
+                    for (int j = mRequestedNotificationListeners.size() - 1; j >= 0; j--) {
+                        NotificationListenerFilter nlf =
+                                mRequestedNotificationListeners.valueAt(j);
 
-                    VersionedPackage ai = new VersionedPackage(pkg, uidList[i]);
-                    nlf.removePackage(ai);
+                        VersionedPackage ai = new VersionedPackage(pkg, uidList[i]);
+                        nlf.removePackage(ai);
+                    }
                 }
             }
         }
@@ -10997,7 +11003,9 @@
                     }
                     NotificationListenerFilter nlf =
                             new NotificationListenerFilter(approved, disallowedPkgs);
-                    mRequestedNotificationListeners.put(Pair.create(cn, userId), nlf);
+                    synchronized (mRequestedNotificationListeners) {
+                        mRequestedNotificationListeners.put(Pair.create(cn, userId), nlf);
+                    }
                 }
             }
         }
@@ -11005,72 +11013,81 @@
         @Override
         protected void writeExtraXmlTags(TypedXmlSerializer out) throws IOException {
             out.startTag(null, TAG_REQUESTED_LISTENERS);
-            for (Pair<ComponentName, Integer> listener : mRequestedNotificationListeners.keySet()) {
-                NotificationListenerFilter nlf = mRequestedNotificationListeners.get(listener);
-                out.startTag(null, TAG_REQUESTED_LISTENER);
-                XmlUtils.writeStringAttribute(
-                        out, ATT_COMPONENT, listener.first.flattenToString());
-                XmlUtils.writeIntAttribute(out, ATT_USER_ID, listener.second);
+            synchronized (mRequestedNotificationListeners) {
+                for (Pair<ComponentName, Integer> listener :
+                        mRequestedNotificationListeners.keySet()) {
+                    NotificationListenerFilter nlf = mRequestedNotificationListeners.get(listener);
+                    out.startTag(null, TAG_REQUESTED_LISTENER);
+                    XmlUtils.writeStringAttribute(
+                            out, ATT_COMPONENT, listener.first.flattenToString());
+                    XmlUtils.writeIntAttribute(out, ATT_USER_ID, listener.second);
 
-                out.startTag(null, TAG_APPROVED);
-                XmlUtils.writeIntAttribute(out, ATT_TYPES, nlf.getTypes());
-                out.endTag(null, TAG_APPROVED);
+                    out.startTag(null, TAG_APPROVED);
+                    XmlUtils.writeIntAttribute(out, ATT_TYPES, nlf.getTypes());
+                    out.endTag(null, TAG_APPROVED);
 
-                for (VersionedPackage ai : nlf.getDisallowedPackages()) {
-                    if (!TextUtils.isEmpty(ai.getPackageName())) {
-                        out.startTag(null, TAG_DISALLOWED);
-                        XmlUtils.writeStringAttribute(out, ATT_PKG, ai.getPackageName());
-                        XmlUtils.writeIntAttribute(out, ATT_UID, ai.getVersionCode());
-                        out.endTag(null, TAG_DISALLOWED);
+                    for (VersionedPackage ai : nlf.getDisallowedPackages()) {
+                        if (!TextUtils.isEmpty(ai.getPackageName())) {
+                            out.startTag(null, TAG_DISALLOWED);
+                            XmlUtils.writeStringAttribute(out, ATT_PKG, ai.getPackageName());
+                            XmlUtils.writeIntAttribute(out, ATT_UID, ai.getVersionCode());
+                            out.endTag(null, TAG_DISALLOWED);
+                        }
                     }
-                }
 
-                out.endTag(null, TAG_REQUESTED_LISTENER);
+                    out.endTag(null, TAG_REQUESTED_LISTENER);
+                }
             }
 
             out.endTag(null, TAG_REQUESTED_LISTENERS);
         }
 
-        protected @Nullable NotificationListenerFilter getNotificationListenerFilter(
+        @Nullable protected NotificationListenerFilter getNotificationListenerFilter(
                 Pair<ComponentName, Integer> pair) {
-            return mRequestedNotificationListeners.get(pair);
+            synchronized (mRequestedNotificationListeners) {
+                return mRequestedNotificationListeners.get(pair);
+            }
         }
 
         protected void setNotificationListenerFilter(Pair<ComponentName, Integer> pair,
                 NotificationListenerFilter nlf) {
-            mRequestedNotificationListeners.put(pair, nlf);
+            synchronized (mRequestedNotificationListeners) {
+                mRequestedNotificationListeners.put(pair, nlf);
+            }
         }
 
         @Override
         protected void ensureFilters(ServiceInfo si, int userId) {
-            Pair listener = Pair.create(si.getComponentName(), userId);
-            NotificationListenerFilter existingNlf =
-                    mRequestedNotificationListeners.get(listener);
-            if (si.metaData != null) {
-                if (existingNlf  == null) {
-                    // no stored filters for this listener; see if they provided a default
-                    if (si.metaData.containsKey(META_DATA_DEFAULT_FILTER_TYPES)) {
-                        String typeList =
-                                si.metaData.get(META_DATA_DEFAULT_FILTER_TYPES).toString();
-                        if (typeList != null) {
-                            int types = getTypesFromStringList(typeList);
-                            NotificationListenerFilter nlf =
-                                    new NotificationListenerFilter(types, new ArraySet<>());
-                            mRequestedNotificationListeners.put(listener, nlf);
+            Pair<ComponentName, Integer> listener = Pair.create(si.getComponentName(), userId);
+            synchronized (mRequestedNotificationListeners) {
+                NotificationListenerFilter existingNlf =
+                        mRequestedNotificationListeners.get(listener);
+                if (si.metaData != null) {
+                    if (existingNlf == null) {
+                        // no stored filters for this listener; see if they provided a default
+                        if (si.metaData.containsKey(META_DATA_DEFAULT_FILTER_TYPES)) {
+                            String typeList =
+                                    si.metaData.get(META_DATA_DEFAULT_FILTER_TYPES).toString();
+                            if (typeList != null) {
+                                int types = getTypesFromStringList(typeList);
+                                NotificationListenerFilter nlf =
+                                        new NotificationListenerFilter(types, new ArraySet<>());
+                                mRequestedNotificationListeners.put(listener, nlf);
+                            }
                         }
                     }
-                }
 
-                // also check the types they never want bridged
-                if (si.metaData.containsKey(META_DATA_DISABLED_FILTER_TYPES)) {
-                    int neverBridge = getTypesFromStringList(si.metaData.get(
-                            META_DATA_DISABLED_FILTER_TYPES).toString());
-                    if (neverBridge != 0) {
-                        NotificationListenerFilter nlf =
-                                mRequestedNotificationListeners.getOrDefault(
-                                        listener, new NotificationListenerFilter());
-                        nlf.setTypes(nlf.getTypes() & ~neverBridge);
-                        mRequestedNotificationListeners.put(listener, nlf);
+                    // also check the types they never want bridged
+                    if (si.metaData.containsKey(META_DATA_DISABLED_FILTER_TYPES)) {
+                        int neverBridge = getTypesFromStringList(si.metaData.get(
+                                META_DATA_DISABLED_FILTER_TYPES).toString());
+                        if (neverBridge != 0) {
+                            NotificationListenerFilter nlf =
+                                    mRequestedNotificationListeners.getOrDefault(
+                                            listener, new NotificationListenerFilter());
+                            nlf.setTypes(nlf.getTypes() & ~neverBridge);
+                            mRequestedNotificationListeners.put(listener, nlf);
+                        }
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/pm/VerifyingSession.java b/services/core/java/com/android/server/pm/VerifyingSession.java
index 5015985..7198de2 100644
--- a/services/core/java/com/android/server/pm/VerifyingSession.java
+++ b/services/core/java/com/android/server/pm/VerifyingSession.java
@@ -353,11 +353,10 @@
             PackageInfoLite pkgLite,
             PackageVerificationState verificationState) {
 
-        // TODO: http://b/22976637
-        // Apps installed for "all" users use the device owner to verify the app
+        // Apps installed for "all" users use the current user to verify the app
         UserHandle verifierUser = getUser();
         if (verifierUser == UserHandle.ALL) {
-            verifierUser = UserHandle.SYSTEM;
+            verifierUser = UserHandle.of(mPm.mUserManager.getCurrentUserId());
         }
         final int verifierUserId = verifierUser.getIdentifier();
 
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
index 2d3928c..8f41608 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
@@ -2237,7 +2237,14 @@
         }
         clearAllResourcesAndClientMapping(getClientProfile(clientId));
         mClientProfiles.remove(clientId);
-        mListeners.remove(clientId);
+
+        // it may be called by unregisterClientProfileInternal under test
+        synchronized (mLock) {
+            ResourcesReclaimListenerRecord record = mListeners.remove(clientId);
+            if (record != null) {
+                record.getListener().asBinder().unlinkToDeath(record, 0);
+            }            
+        }
     }
 
     private void clearFrontendAndClientMapping(ClientProfile profile) {
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index a757d90..f71f3b1 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -397,9 +397,21 @@
 
         /** Returns {@code true} if the incoming activity can belong to this transition. */
         boolean canCoalesce(ActivityRecord r) {
-            return mLastLaunchedActivity.mDisplayContent == r.mDisplayContent
-                    && mLastLaunchedActivity.getTask().getBounds().equals(r.getTask().getBounds())
-                    && mLastLaunchedActivity.getWindowingMode() == r.getWindowingMode();
+            if (mLastLaunchedActivity.mDisplayContent != r.mDisplayContent
+                    || mLastLaunchedActivity.getWindowingMode() != r.getWindowingMode()) {
+                return false;
+            }
+            // The current task should be non-null because it is just launched. While the
+            // last task can be cleared when starting activity with FLAG_ACTIVITY_CLEAR_TASK.
+            final Task lastTask = mLastLaunchedActivity.getTask();
+            final Task currentTask = r.getTask();
+            if (lastTask != null && currentTask != null) {
+                if (lastTask == currentTask) {
+                    return true;
+                }
+                return lastTask.getBounds().equals(currentTask.getBounds());
+            }
+            return mLastLaunchedActivity.isUid(r.launchedFromUid);
         }
 
         /** @return {@code true} if the activity matches a launched activity in this transition. */
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 2160ce1..c6a2e0e 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2821,6 +2821,27 @@
         }
     }
 
+    @Override
+    void waitForSyncTransactionCommit(ArraySet<WindowContainer> wcAwaitingCommit) {
+        super.waitForSyncTransactionCommit(wcAwaitingCommit);
+        if (mStartingData != null) {
+            mStartingData.mWaitForSyncTransactionCommit = true;
+        }
+    }
+
+    @Override
+    void onSyncTransactionCommitted(SurfaceControl.Transaction t) {
+        super.onSyncTransactionCommitted(t);
+        if (mStartingData == null) {
+            return;
+        }
+        mStartingData.mWaitForSyncTransactionCommit = false;
+        if (mStartingData.mRemoveAfterTransaction) {
+            mStartingData.mRemoveAfterTransaction = false;
+            removeStartingWindowAnimation(mStartingData.mPrepareRemoveAnimation);
+        }
+    }
+
     void removeStartingWindowAnimation(boolean prepareAnimation) {
         mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_IDLE;
         if (task != null) {
@@ -2843,6 +2864,12 @@
         final WindowState startingWindow = mStartingWindow;
         final boolean animate;
         if (mStartingData != null) {
+            if (mStartingData.mWaitForSyncTransactionCommit
+                    || mTransitionController.inCollectingTransition(startingWindow)) {
+                mStartingData.mRemoveAfterTransaction = true;
+                mStartingData.mPrepareRemoveAnimation = prepareAnimation;
+                return;
+            }
             animate = prepareAnimation && mStartingData.needRevealAnimation()
                     && mStartingWindow.isVisibleByPolicy();
             ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Schedule remove starting %s startingWindow=%s"
@@ -2863,18 +2890,7 @@
                     this);
             return;
         }
-
-        if (animate && mTransitionController.inCollectingTransition(startingWindow)) {
-            // Defer remove starting window after transition start.
-            // The surface of app window could really show after the transition finish.
-            startingWindow.mSyncTransaction.addTransactionCommittedListener(Runnable::run, () -> {
-                synchronized (mAtmService.mGlobalLock) {
-                    surface.remove(true);
-                }
-            });
-        } else {
-            surface.remove(animate);
-        }
+        surface.remove(animate);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java b/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java
index 5f56af7..1208b6ef 100644
--- a/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java
+++ b/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java
@@ -99,13 +99,15 @@
     }
 
     public void forEachConnection(Consumer<T> consumer) {
+        final ArraySet<T> connections;
         synchronized (mActivity) {
             if (mConnections == null || mConnections.isEmpty()) {
                 return;
             }
-            for (int i = mConnections.size() - 1; i >= 0; i--) {
-                consumer.accept(mConnections.valueAt(i));
-            }
+            connections = new ArraySet<>(mConnections);
+        }
+        for (int i = connections.size() - 1; i >= 0; i--) {
+            consumer.accept(connections.valueAt(i));
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index c5e75fa..a27f3e4 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -2926,8 +2926,7 @@
         // If the matching task is already in the adjacent task of the launch target. Adjust to use
         // the adjacent task as its launch target. So the existing task will be launched into the
         // closer one and won't be reparent redundantly.
-        final Task adjacentTargetTask = mTargetRootTask.getAdjacentTaskFragment() != null
-                ? mTargetRootTask.getAdjacentTaskFragment().asTask() : null;
+        final Task adjacentTargetTask = mTargetRootTask.getAdjacentTask();
         if (adjacentTargetTask != null && intentActivity.isDescendantOf(adjacentTargetTask)) {
             mTargetRootTask = adjacentTargetTask;
         }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index abf66bc..f93afe8 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -2008,7 +2008,8 @@
             return;
         }
 
-        if (r.isState(RESUMED) && r == mRootWindowContainer.getTopResumedActivity()) {
+        if ((touchedActivity == null || r == touchedActivity) && r.isState(RESUMED)
+                && r == mRootWindowContainer.getTopResumedActivity()) {
             setLastResumedActivityUncheckLocked(r, "setFocusedTask-alreadyTop");
             return;
         }
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 597c8bf..805bff2 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -1030,12 +1030,11 @@
                     canPromote = false;
                 }
 
-                // If the current window container is task and it have adjacent task, it means
-                // both tasks will open or close app toghther but we want get their opening or
-                // closing animation target independently so do not promote.
+                // If the current window container is a task with adjacent task set, the both
+                // adjacent tasks will be opened or closed together. To get their opening or
+                // closing animation target independently, skip promoting their animation targets.
                 if (current.asTask() != null
-                        && current.asTask().getAdjacentTaskFragment() != null
-                        && current.asTask().getAdjacentTaskFragment().asTask() != null) {
+                        && current.asTask().getAdjacentTask() != null) {
                     canPromote = false;
                 }
 
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index 11d84ff..0c196d7 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -227,6 +227,7 @@
                     backType = BackNavigationInfo.TYPE_CALLBACK;
                 }
                 infoBuilder.setOnBackInvokedCallback(callbackInfo.getCallback());
+                infoBuilder.setAnimationCallback(callbackInfo.isAnimationCallback());
                 mNavigationMonitor.startMonitor(window, navigationObserver);
             }
 
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index c2bc459..bad64d3 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -656,6 +656,14 @@
      */
     private InputTarget mLastImeInputTarget;
 
+
+    /**
+     * Tracks the windowToken of the input method input target and the corresponding
+     * {@link WindowContainerListener} for monitoring changes (e.g. the requested visibility
+     * change).
+     */
+    private @Nullable Pair<IBinder, WindowContainerListener> mImeTargetTokenListenerPair;
+
     /**
      * This controls the visibility and animation of the input method window.
      */
@@ -4267,7 +4275,38 @@
 
     @VisibleForTesting
     void setImeInputTarget(InputTarget target) {
+        if (mImeTargetTokenListenerPair != null) {
+            // Unregister the listener before changing to the new IME input target.
+            final WindowToken oldToken = mTokenMap.get(mImeTargetTokenListenerPair.first);
+            if (oldToken != null) {
+                oldToken.unregisterWindowContainerListener(mImeTargetTokenListenerPair.second);
+            }
+            mImeTargetTokenListenerPair = null;
+        }
         mImeInputTarget = target;
+        // Notify listeners about IME input target window visibility by the target change.
+        if (target != null) {
+            // TODO(b/276743705): Let InputTarget register the visibility change of the hierarchy.
+            final WindowState targetWin = target.getWindowState();
+            if (targetWin != null) {
+                mImeTargetTokenListenerPair = new Pair<>(targetWin.mToken.token,
+                        new WindowContainerListener() {
+                            @Override
+                            public void onVisibleRequestedChanged(boolean isVisibleRequested) {
+                                // Notify listeners for IME input target window visibility change
+                                // requested by the parent container.
+                                mWmService.dispatchImeInputTargetVisibilityChanged(
+                                        targetWin.mClient.asBinder(), isVisibleRequested,
+                                        targetWin.mActivityRecord != null
+                                                && targetWin.mActivityRecord.finishing);
+                            }
+                        });
+                targetWin.mToken.registerWindowContainerListener(
+                        mImeTargetTokenListenerPair.second);
+                mWmService.dispatchImeInputTargetVisibilityChanged(targetWin.mClient.asBinder(),
+                        targetWin.isVisible() /* visible */, false /* removed */);
+            }
+        }
         if (refreshImeSecureFlag(getPendingTransaction())) {
             mWmService.requestTraversal();
         }
@@ -4433,6 +4472,10 @@
     }
 
     private void attachImeScreenshotOnTarget(WindowState imeTarget) {
+        attachImeScreenshotOnTarget(imeTarget, false);
+    }
+
+    private void attachImeScreenshotOnTarget(WindowState imeTarget, boolean hideImeWindow) {
         final SurfaceControl.Transaction t = getPendingTransaction();
         // Remove the obsoleted IME snapshot first in case the new snapshot happens to
         // override the current one before the transition finish and the surface never be
@@ -4441,6 +4484,11 @@
         mImeScreenshot = new ImeScreenshot(
                 mWmService.mSurfaceControlFactory.apply(null), imeTarget);
         mImeScreenshot.attachAndShow(t);
+        if (mInputMethodWindow != null && hideImeWindow) {
+            // Hide the IME window when deciding to show IME snapshot on demand.
+            // InsetsController will make IME visible again before animating it.
+            mInputMethodWindow.hide(false, false);
+        }
     }
 
     /**
@@ -4458,7 +4506,7 @@
      */
     @VisibleForTesting
     void showImeScreenshot(WindowState imeTarget) {
-        attachImeScreenshotOnTarget(imeTarget);
+        attachImeScreenshotOnTarget(imeTarget, true /* hideImeWindow */);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 339b6ec..747819e9 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -17,7 +17,6 @@
 package com.android.server.wm;
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.view.Display.TYPE_INTERNAL;
 import static android.view.InsetsFrameProvider.SOURCE_ARBITRARY_RECTANGLE;
 import static android.view.InsetsFrameProvider.SOURCE_CONTAINER_BOUNDS;
@@ -2208,16 +2207,15 @@
 
     private int updateSystemBarsLw(WindowState win, int disableFlags) {
         final TaskDisplayArea defaultTaskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea();
-        final boolean multiWindowTaskVisible =
+        final boolean adjacentTasksVisible =
                 defaultTaskDisplayArea.getRootTask(task -> task.isVisible()
-                        && task.getTopLeafTask().getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW)
+                        && task.getTopLeafTask().getAdjacentTask() != null)
                         != null;
         final boolean freeformRootTaskVisible =
                 defaultTaskDisplayArea.isRootTaskVisible(WINDOWING_MODE_FREEFORM);
 
-        // We need to force showing system bars when the multi-window or freeform root task is
-        // visible.
-        mForceShowSystemBars = multiWindowTaskVisible || freeformRootTaskVisible;
+        // We need to force showing system bars when adjacent tasks or freeform roots visible.
+        mForceShowSystemBars = adjacentTasksVisible || freeformRootTaskVisible;
         // We need to force the consumption of the system bars if they are force shown or if they
         // are controlled by a remote insets controller.
         mForceConsumeSystemBars = mForceShowSystemBars
@@ -2238,7 +2236,7 @@
 
         int appearance = APPEARANCE_OPAQUE_NAVIGATION_BARS | APPEARANCE_OPAQUE_STATUS_BARS;
         appearance = configureStatusBarOpacity(appearance);
-        appearance = configureNavBarOpacity(appearance, multiWindowTaskVisible,
+        appearance = configureNavBarOpacity(appearance, adjacentTasksVisible,
                 freeformRootTaskVisible);
 
         // Show immersive mode confirmation if needed.
diff --git a/services/core/java/com/android/server/wm/ImeTargetChangeListener.java b/services/core/java/com/android/server/wm/ImeTargetChangeListener.java
new file mode 100644
index 0000000..8bc445b
--- /dev/null
+++ b/services/core/java/com/android/server/wm/ImeTargetChangeListener.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import android.annotation.NonNull;
+import android.os.IBinder;
+
+/**
+ * Callback the IME targeting window visibility change state for
+ * {@link com.android.server.inputmethod.InputMethodManagerService} to manage the IME surface
+ * visibility and z-ordering.
+ */
+public interface ImeTargetChangeListener {
+    /**
+     * Called when a non-IME-focusable overlay window being the IME layering target (e.g. a
+     * window with {@link android.view.WindowManager.LayoutParams#FLAG_NOT_FOCUSABLE} and
+     * {@link android.view.WindowManager.LayoutParams#FLAG_ALT_FOCUSABLE_IM} flags)
+     * has changed its window visibility.
+     *
+     * @param overlayWindowToken the window token of the overlay window.
+     * @param visible            the visibility of the overlay window, {@code true} means visible
+     *                           and {@code false} otherwise.
+     * @param removed            Whether the IME target overlay window has being removed.
+     */
+    default void onImeTargetOverlayVisibilityChanged(@NonNull IBinder overlayWindowToken,
+            boolean visible, boolean removed) {
+    }
+
+    /**
+     * Called when the visibility of IME input target window has changed.
+     *
+     * @param imeInputTarget   the window token of the IME input target window.
+     * @param visible          the new window visibility made by {@param imeInputTarget}. visible is
+     *                         {@code true} when switching to the new visible IME input target
+     *                         window and started input, or the same input target relayout to
+     *                         visible from invisible. In contrast, visible is {@code false} when
+     *                         closing the input target, or the same input target relayout to
+     *                         invisible from visible.
+     * @param removed          Whether the IME input target window has being removed.
+     */
+    default void onImeInputTargetVisibilityChanged(@NonNull IBinder imeInputTarget, boolean visible,
+            boolean removed) {
+    }
+}
diff --git a/services/core/java/com/android/server/wm/ImeTargetVisibilityPolicy.java b/services/core/java/com/android/server/wm/ImeTargetVisibilityPolicy.java
index 71dd917..1d9f24c 100644
--- a/services/core/java/com/android/server/wm/ImeTargetVisibilityPolicy.java
+++ b/services/core/java/com/android/server/wm/ImeTargetVisibilityPolicy.java
@@ -19,6 +19,7 @@
 
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.IBinder;
 import android.view.WindowManager;
@@ -36,16 +37,15 @@
      * @param displayId A unique id to identify the display.
      * @return {@code true} if success, {@code false} otherwise.
      */
-    public abstract boolean showImeScreenShot(IBinder imeTarget, int displayId);
+    public abstract boolean showImeScreenshot(@NonNull IBinder imeTarget, int displayId);
 
     /**
-     * Updates the IME parent for target window.
+     * Removes the IME screenshot on the given display.
      *
-     * @param imeTarget The target window to update the IME parent.
-     * @param displayId A unique id to identify the display.
+     * @param displayId The target display of showing IME screenshot.
      * @return {@code true} if success, {@code false} otherwise.
      */
-    public abstract boolean updateImeParent(IBinder imeTarget, int displayId);
+    public abstract boolean removeImeScreenshot(int displayId);
 
     /**
      * Called when {@link DisplayContent#computeImeParent()} to check if it's valid to keep
diff --git a/services/core/java/com/android/server/wm/StartingData.java b/services/core/java/com/android/server/wm/StartingData.java
index 300a894..cff86ad 100644
--- a/services/core/java/com/android/server/wm/StartingData.java
+++ b/services/core/java/com/android/server/wm/StartingData.java
@@ -41,6 +41,26 @@
     /** Whether the starting window is drawn. */
     boolean mIsDisplayed;
 
+    /**
+     * For Shell transition.
+     * There will be a transition happen on attached activity, do not remove starting window during
+     * this period, because the transaction to show app window may not apply before remove starting
+     * window.
+     * Note this isn't equal to transition playing, the period should be
+     * Sync finishNow -> Start transaction apply.
+     */
+    boolean mWaitForSyncTransactionCommit;
+
+    /**
+     * For Shell transition.
+     * This starting window should be removed after applying the start transaction of transition,
+     * which ensures the app window has shown.
+     */
+    boolean mRemoveAfterTransaction;
+
+    /** Whether to prepare the removal animation. */
+    boolean mPrepareRemoveAnimation;
+
     protected StartingData(WindowManagerService service, int typeParams) {
         mService = service;
         mTypeParams = typeParams;
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 9363eb5..5c33e64 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -2362,6 +2362,22 @@
         return parentTask == null ? null : parentTask.getCreatedByOrganizerTask();
     }
 
+    /** @return the first adjacent task of this task or its parent. */
+    @Nullable
+    Task getAdjacentTask() {
+        final TaskFragment adjacentTaskFragment = getAdjacentTaskFragment();
+        if (adjacentTaskFragment != null && adjacentTaskFragment.asTask() != null) {
+            return adjacentTaskFragment.asTask();
+        }
+
+        final WindowContainer parent = getParent();
+        if (parent == null || parent.asTask() == null) {
+            return null;
+        }
+
+        return parent.asTask().getAdjacentTask();
+    }
+
     // TODO(task-merge): Figure out what's the right thing to do for places that used it.
     boolean isRootTask() {
         return getRootTask() == this;
@@ -2747,7 +2763,7 @@
             Rect outSurfaceInsets) {
         // If this task has its adjacent task, it means they should animate together. Use display
         // bounds for them could move same as full screen task.
-        if (getAdjacentTaskFragment() != null && getAdjacentTaskFragment().asTask() != null) {
+        if (getAdjacentTask() != null) {
             super.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets);
             return;
         }
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index b0a879e..e80cbb3 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -1081,12 +1081,12 @@
             if (sourceTask != null && sourceTask == candidateTask) {
                 // Do nothing when task that is getting opened is same as the source.
             } else if (sourceTask != null
-                    && mLaunchAdjacentFlagRootTask.getAdjacentTaskFragment() != null
+                    && mLaunchAdjacentFlagRootTask.getAdjacentTask() != null
                     && (sourceTask == mLaunchAdjacentFlagRootTask
                     || sourceTask.isDescendantOf(mLaunchAdjacentFlagRootTask))) {
                 // If the adjacent launch is coming from the same root, launch to
                 // adjacent root instead.
-                return mLaunchAdjacentFlagRootTask.getAdjacentTaskFragment().asTask();
+                return mLaunchAdjacentFlagRootTask.getAdjacentTask();
             } else {
                 return mLaunchAdjacentFlagRootTask;
             }
@@ -1095,10 +1095,8 @@
         for (int i = mLaunchRootTasks.size() - 1; i >= 0; --i) {
             if (mLaunchRootTasks.get(i).contains(windowingMode, activityType)) {
                 final Task launchRootTask = mLaunchRootTasks.get(i).task;
-                final TaskFragment adjacentTaskFragment = launchRootTask != null
-                        ? launchRootTask.getAdjacentTaskFragment() : null;
-                final Task adjacentRootTask =
-                        adjacentTaskFragment != null ? adjacentTaskFragment.asTask() : null;
+                final Task adjacentRootTask = launchRootTask != null
+                        ? launchRootTask.getAdjacentTask() : null;
                 if (sourceTask != null && adjacentRootTask != null
                         && (sourceTask == adjacentRootTask
                         || sourceTask.isDescendantOf(adjacentRootTask))) {
@@ -1116,16 +1114,14 @@
                 // A pinned task relaunching should be handled by its task organizer. Skip fallback
                 // launch target of a pinned task from source task.
                 || candidateTask.getWindowingMode() != WINDOWING_MODE_PINNED)) {
-            Task launchTarget = sourceTask.getCreatedByOrganizerTask();
-            if (launchTarget != null && launchTarget.getAdjacentTaskFragment() != null) {
-                if (candidateTask != null) {
-                    final Task candidateRoot = candidateTask.getCreatedByOrganizerTask();
-                    if (candidateRoot != null && candidateRoot != launchTarget
-                            && launchTarget == candidateRoot.getAdjacentTaskFragment()) {
-                        launchTarget = candidateRoot;
-                    }
+            final Task adjacentTarget = sourceTask.getAdjacentTask();
+            if (adjacentTarget != null) {
+                if (candidateTask != null
+                        && (candidateTask == adjacentTarget
+                        || candidateTask.isDescendantOf(adjacentTarget))) {
+                    return adjacentTarget;
                 }
-                return launchTarget;
+                return sourceTask.getCreatedByOrganizerTask();
             }
         }
 
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 184293e..5626aa7 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -681,6 +681,7 @@
         final StartingWindowRemovalInfo removalInfo = new StartingWindowRemovalInfo();
         removalInfo.taskId = task.mTaskId;
         removalInfo.playRevealAnimation = prepareAnimation
+                && task.getDisplayContent() != null
                 && task.getDisplayInfo().state == Display.STATE_ON;
         final boolean playShiftUpAnimation = !task.inMultiWindowMode();
         final ActivityRecord topActivity = task.topActivityContainsStartingWindow();
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 969afe5..4922523 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -848,6 +848,16 @@
     }
 
     /**
+     * Sets by the {@link com.android.server.inputmethod.InputMethodManagerService} to monitor
+     * the visibility change of the IME targeted windows.
+     *
+     * @see ImeTargetChangeListener#onImeTargetOverlayVisibilityChanged
+     * @see ImeTargetChangeListener#onImeInputTargetVisibilityChanged
+     */
+    public abstract void setInputMethodTargetChangeListener(
+            @NonNull ImeTargetChangeListener listener);
+
+    /**
      * Moves the {@link WindowToken} {@code binder} to the display specified by {@code displayId}.
      */
     public abstract void moveWindowTokenToDisplay(IBinder binder, int displayId);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 99d0ea8..62b3c7c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -723,6 +723,9 @@
 
     boolean mHardKeyboardAvailable;
     WindowManagerInternal.OnHardKeyboardStatusChangeListener mHardKeyboardStatusChangeListener;
+
+    @Nullable ImeTargetChangeListener mImeTargetChangeListener;
+
     SettingsObserver mSettingsObserver;
     final EmbeddedWindowController mEmbeddedWindowController;
     final AnrController mAnrController;
@@ -1807,6 +1810,10 @@
 
             if (imMayMove) {
                 displayContent.computeImeTarget(true /* updateImeTarget */);
+                if (win.isImeOverlayLayeringTarget()) {
+                    dispatchImeTargetOverlayVisibilityChanged(client.asBinder(),
+                            win.isVisibleRequestedOrAdding(), false /* removed */);
+                }
             }
 
             // Don't do layout here, the window must call
@@ -2328,6 +2335,8 @@
                 winAnimator.mSurfaceController.setSecure(win.isSecureLocked());
             }
 
+            final boolean wasVisible = win.isVisible();
+
             win.mRelayoutCalled = true;
             win.mInRelayout = true;
 
@@ -2336,7 +2345,6 @@
                     "Relayout %s: oldVis=%d newVis=%d. %s", win, oldVisibility,
                             viewVisibility, new RuntimeException().fillInStackTrace());
 
-
             win.setDisplayLayoutNeeded();
             win.mGivenInsetsPending = (flags & WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0;
 
@@ -2501,6 +2509,18 @@
             }
             win.mInRelayout = false;
 
+            final boolean winVisibleChanged = win.isVisible() != wasVisible;
+            if (win.isImeOverlayLayeringTarget() && winVisibleChanged) {
+                dispatchImeTargetOverlayVisibilityChanged(client.asBinder(),
+                        win.isVisible(), false /* removed */);
+            }
+            // Notify listeners about IME input target window visibility change.
+            final boolean isImeInputTarget = win.getDisplayContent().getImeInputTarget() == win;
+            if (isImeInputTarget && winVisibleChanged) {
+                dispatchImeInputTargetVisibilityChanged(win.mClient.asBinder(),
+                        win.isVisible() /* visible */, false /* removed */);
+            }
+
             if (outSyncIdBundle != null) {
                 final int maybeSyncSeqId;
                 if (USE_BLAST_SYNC && win.useBLASTSync() && viewVisibility == View.VISIBLE
@@ -3325,6 +3345,30 @@
         });
     }
 
+    void dispatchImeTargetOverlayVisibilityChanged(@NonNull IBinder token, boolean visible,
+            boolean removed) {
+        if (mImeTargetChangeListener != null) {
+            if (DEBUG_INPUT_METHOD) {
+                Slog.d(TAG, "onImeTargetOverlayVisibilityChanged, win=" + mWindowMap.get(token)
+                        + "visible=" + visible + ", removed=" + removed);
+            }
+            mH.post(() -> mImeTargetChangeListener.onImeTargetOverlayVisibilityChanged(token,
+                    visible, removed));
+        }
+    }
+
+    void dispatchImeInputTargetVisibilityChanged(@NonNull IBinder token, boolean visible,
+            boolean removed) {
+        if (mImeTargetChangeListener != null) {
+            if (DEBUG_INPUT_METHOD) {
+                Slog.d(TAG, "onImeInputTargetVisibilityChanged, win=" + mWindowMap.get(token)
+                        + "visible=" + visible + ", removed=" + removed);
+            }
+            mH.post(() -> mImeTargetChangeListener.onImeInputTargetVisibilityChanged(token,
+                    visible, removed));
+        }
+    }
+
     @Override
     public void setSwitchingUser(boolean switching) {
         if (!checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
@@ -8262,13 +8306,19 @@
             }
             return null;
         }
+
+        @Override
+        public void setInputMethodTargetChangeListener(@NonNull ImeTargetChangeListener listener) {
+            synchronized (mGlobalLock) {
+                mImeTargetChangeListener = listener;
+            }
+        }
     }
 
     private final class ImeTargetVisibilityPolicyImpl extends ImeTargetVisibilityPolicy {
 
-        // TODO(b/258048231): Track IME visibility change in bugreport when invocations.
         @Override
-        public boolean showImeScreenShot(@NonNull IBinder imeTarget, int displayId) {
+        public boolean showImeScreenshot(@NonNull IBinder imeTarget, int displayId) {
             synchronized (mGlobalLock) {
                 final WindowState imeTargetWindow = mWindowMap.get(imeTarget);
                 if (imeTargetWindow == null) {
@@ -8284,24 +8334,18 @@
                 return true;
             }
         }
-
-        // TODO(b/258048231): Track IME visibility change in bugreport when invocations.
         @Override
-        public boolean updateImeParent(@NonNull IBinder imeTarget, int displayId) {
+        public boolean removeImeScreenshot(int displayId) {
             synchronized (mGlobalLock) {
-                final WindowState imeTargetWindow = mWindowMap.get(imeTarget);
-                if (imeTargetWindow == null) {
-                    return false;
-                }
                 final DisplayContent dc = mRoot.getDisplayContent(displayId);
                 if (dc == null) {
-                    Slog.w(TAG, "Invalid displayId:" + displayId + ", fail to update ime parent");
+                    Slog.w(TAG, "Invalid displayId:" + displayId
+                            + ", fail to remove ime screenshot");
                     return false;
                 }
-
-                dc.updateImeParent();
-                return true;
+                dc.removeImeSurfaceImmediately();
             }
+            return true;
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 678d4c8..a299592 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -354,6 +354,7 @@
     // overlay window is hidden because the owning app is suspended
     private boolean mHiddenWhileSuspended;
     private boolean mAppOpVisibility = true;
+
     boolean mPermanentlyHidden; // the window should never be shown again
     // This is a non-system overlay window that is currently force hidden.
     private boolean mForceHideNonSystemOverlayWindow;
@@ -2350,6 +2351,10 @@
         }
         super.removeImmediately();
 
+        if (isImeOverlayLayeringTarget()) {
+            mWmService.dispatchImeTargetOverlayVisibilityChanged(mClient.asBinder(),
+                    false /* visible */, true /* removed */);
+        }
         final DisplayContent dc = getDisplayContent();
         if (isImeLayeringTarget()) {
             // Remove the attached IME screenshot surface.
@@ -2360,6 +2365,8 @@
             dc.computeImeTarget(true /* updateImeTarget */);
         }
         if (dc.getImeInputTarget() == this && !inRelaunchingActivity()) {
+            mWmService.dispatchImeInputTargetVisibilityChanged(mClient.asBinder(),
+                    false /* visible */, true /* removed */);
             dc.updateImeInputAndControlTarget(null);
         }
 
@@ -5499,6 +5506,14 @@
         return getDisplayContent().getImeTarget(IME_TARGET_LAYERING) == this;
     }
 
+    /**
+     * Whether the window is non-focusable IME overlay layering target.
+     */
+    boolean isImeOverlayLayeringTarget() {
+        return isImeLayeringTarget()
+                && (mAttrs.flags & (FLAG_ALT_FOCUSABLE_IM | FLAG_NOT_FOCUSABLE)) != 0;
+    }
+
     WindowState getImeLayeringTarget() {
         final InsetsControlTarget target = getDisplayContent().getImeTarget(IME_TARGET_LAYERING);
         return target != null ? target.getWindow() : null;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BundlePolicySerializer.java b/services/devicepolicy/java/com/android/server/devicepolicy/BundlePolicySerializer.java
index ee73f8a..82f9aad 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BundlePolicySerializer.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BundlePolicySerializer.java
@@ -17,50 +17,28 @@
 package com.android.server.devicepolicy;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.app.admin.BundlePolicyValue;
 import android.app.admin.PackagePolicyKey;
 import android.app.admin.PolicyKey;
 import android.os.Bundle;
-import android.os.Environment;
 import android.os.Parcelable;
-import android.util.AtomicFile;
-import android.util.Slog;
-import android.util.Xml;
+import android.util.Log;
 
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.XmlUtils;
 import com.android.modules.utils.TypedXmlPullParser;
 import com.android.modules.utils.TypedXmlSerializer;
 
-import libcore.io.IoUtils;
-
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Objects;
 
-// TODO(b/266704763): clean this up and stop creating separate files for each value, the code here
-//  is copied from UserManagerService, however it doesn't currently handle setting different
-//  restrictions for the same package in different users, it also will not remove the files for
-//  outdated restrictions, this will all get fixed when we save it as part of the policies file
-//  rather than in its own files.
 final class BundlePolicySerializer extends PolicySerializer<Bundle> {
 
     private static final String TAG = "BundlePolicySerializer";
 
-    private static final String ATTR_FILE_NAME = "file-name";
-
-    private static final String RESTRICTIONS_FILE_PREFIX = "AppRestrictions_";
-    private static final String XML_SUFFIX = ".xml";
-
-    private static final String TAG_RESTRICTIONS = "restrictions";
     private static final String TAG_ENTRY = "entry";
     private static final String TAG_VALUE = "value";
     private static final String ATTR_KEY = "key";
@@ -83,62 +61,26 @@
             throw new IllegalArgumentException("policyKey is not of type "
                     + "PackagePolicyKey");
         }
-        String packageName = ((PackagePolicyKey) policyKey).getPackageName();
-        String fileName = packageToRestrictionsFileName(packageName, value);
-        writeApplicationRestrictionsLAr(fileName, value);
-        serializer.attribute(/* namespace= */ null, ATTR_FILE_NAME, fileName);
+        writeBundle(value, serializer);
     }
 
-    @Nullable
     @Override
     BundlePolicyValue readFromXml(TypedXmlPullParser parser) {
-        String fileName = parser.getAttributeValue(/* namespace= */ null, ATTR_FILE_NAME);
-
-        return new BundlePolicyValue(readApplicationRestrictions(fileName));
-    }
-
-    private static String packageToRestrictionsFileName(String packageName, Bundle restrictions) {
-        return RESTRICTIONS_FILE_PREFIX + packageName + Objects.hash(restrictions) + XML_SUFFIX;
-    }
-
-    @GuardedBy("mAppRestrictionsLock")
-    private static Bundle readApplicationRestrictions(String fileName) {
-        AtomicFile restrictionsFile =
-                new AtomicFile(new File(Environment.getDataSystemDirectory(), fileName));
-        return readApplicationRestrictions(restrictionsFile);
-    }
-
-    @VisibleForTesting
-    @GuardedBy("mAppRestrictionsLock")
-    static Bundle readApplicationRestrictions(AtomicFile restrictionsFile) {
-        final Bundle restrictions = new Bundle();
-        final ArrayList<String> values = new ArrayList<>();
-        if (!restrictionsFile.getBaseFile().exists()) {
-            return restrictions;
-        }
-
-        FileInputStream fis = null;
+        Bundle bundle = new Bundle();
+        ArrayList<String> values = new ArrayList<>();
         try {
-            fis = restrictionsFile.openRead();
-            final TypedXmlPullParser parser = Xml.resolvePullParser(fis);
-            XmlUtils.nextElement(parser);
-            if (parser.getEventType() != XmlPullParser.START_TAG) {
-                Slog.e(TAG, "Unable to read restrictions file "
-                        + restrictionsFile.getBaseFile());
-                return restrictions;
+            final int outerDepth = parser.getDepth();
+            while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+                readBundle(bundle, values, parser);
             }
-            while (parser.next() != XmlPullParser.END_DOCUMENT) {
-                readEntry(restrictions, values, parser);
-            }
-        } catch (IOException | XmlPullParserException e) {
-            Slog.w(TAG, "Error parsing " + restrictionsFile.getBaseFile(), e);
-        } finally {
-            IoUtils.closeQuietly(fis);
+        } catch (XmlPullParserException | IOException e) {
+            Log.e(TAG, "Error parsing Bundle policy.", e);
+            return null;
         }
-        return restrictions;
+        return new BundlePolicyValue(bundle);
     }
 
-    private static void readEntry(Bundle restrictions, ArrayList<String> values,
+    private static void readBundle(Bundle restrictions, ArrayList<String> values,
             TypedXmlPullParser parser) throws XmlPullParserException, IOException {
         int type = parser.getEventType();
         if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_ENTRY)) {
@@ -186,37 +128,11 @@
         Bundle childBundle = new Bundle();
         int outerDepth = parser.getDepth();
         while (XmlUtils.nextElementWithin(parser, outerDepth)) {
-            readEntry(childBundle, values, parser);
+            readBundle(childBundle, values, parser);
         }
         return childBundle;
     }
 
-    private static void writeApplicationRestrictionsLAr(String fileName, Bundle restrictions) {
-        AtomicFile restrictionsFile = new AtomicFile(
-                new File(Environment.getDataSystemDirectory(), fileName));
-        writeApplicationRestrictionsLAr(restrictions, restrictionsFile);
-    }
-
-    static void writeApplicationRestrictionsLAr(Bundle restrictions, AtomicFile restrictionsFile) {
-        FileOutputStream fos = null;
-        try {
-            fos = restrictionsFile.startWrite();
-            final TypedXmlSerializer serializer = Xml.resolveSerializer(fos);
-            serializer.startDocument(null, true);
-            serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
-
-            serializer.startTag(null, TAG_RESTRICTIONS);
-            writeBundle(restrictions, serializer);
-            serializer.endTag(null, TAG_RESTRICTIONS);
-
-            serializer.endDocument();
-            restrictionsFile.finishWrite(fos);
-        } catch (Exception e) {
-            restrictionsFile.failWrite(fos);
-            Slog.e(TAG, "Error writing application restrictions list", e);
-        }
-    }
-
     private static void writeBundle(Bundle restrictions, TypedXmlSerializer serializer)
             throws IOException {
         for (String key : restrictions.keySet()) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 18fcafa..7e5d5aa 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -11053,7 +11053,6 @@
         }
 
         if (!isPermissionCheckFlagEnabled() && !isPolicyEngineForFinanceFlagEnabled()) {
-            // TODO: Figure out if something like this needs to be restored for policy engine
             final ComponentName profileOwner = getProfileOwnerAsUser(userId);
             if (profileOwner == null) {
                 return false;
@@ -11640,7 +11639,7 @@
                         caller.getUserId());
             }
             setBackwardsCompatibleAppRestrictions(
-                    packageName, restrictions, caller.getUserHandle());
+                    caller, packageName, restrictions, caller.getUserHandle());
         } else {
             Preconditions.checkCallAuthorization((caller.hasAdminComponent()
                     && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)))
@@ -11661,17 +11660,28 @@
     }
 
     /**
-     * Set app restrictions in user manager to keep backwards compatibility for the old
-     * getApplicationRestrictions API.
+     * Set app restrictions in user manager for DPC callers only to keep backwards compatibility
+     * for the old getApplicationRestrictions API.
      */
     private void setBackwardsCompatibleAppRestrictions(
-            String packageName, Bundle restrictions, UserHandle userHandle) {
-        Bundle restrictionsToApply = restrictions == null || restrictions.isEmpty()
-                ? getAppRestrictionsSetByAnyAdmin(packageName, userHandle)
-                : restrictions;
-        mInjector.binderWithCleanCallingIdentity(() -> {
-            mUserManager.setApplicationRestrictions(packageName, restrictionsToApply, userHandle);
-        });
+            CallerIdentity caller, String packageName, Bundle restrictions, UserHandle userHandle) {
+        if ((caller.hasAdminComponent() && (isProfileOwner(caller) || isDefaultDeviceOwner(caller)))
+                || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_APP_RESTRICTIONS))) {
+            Bundle restrictionsToApply = restrictions == null || restrictions.isEmpty()
+                    ? getAppRestrictionsSetByAnyAdmin(packageName, userHandle)
+                    : restrictions;
+            mInjector.binderWithCleanCallingIdentity(() -> {
+                mUserManager.setApplicationRestrictions(packageName, restrictionsToApply,
+                        userHandle);
+            });
+        } else {
+            // Notify package of changes via an intent - only sent to explicitly registered
+            // receivers. Sending here because For DPCs, this is being sent in UMS.
+            final Intent changeIntent = new Intent(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED);
+            changeIntent.setPackage(packageName);
+            changeIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+            mContext.sendBroadcastAsUser(changeIntent, userHandle);
+        }
     }
 
     private Bundle getAppRestrictionsSetByAnyAdmin(String packageName, UserHandle userHandle) {
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java
index 7d4f87d..a6ada4d 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java
@@ -38,6 +38,7 @@
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.view.Display;
 import android.view.inputmethod.InputMethodManager;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -144,6 +145,26 @@
         }
     }
 
+    @Test
+    public void testShowImeScreenshot() {
+        synchronized (ImfLock.class) {
+            mVisibilityApplier.showImeScreenshot(mWindowToken, Display.DEFAULT_DISPLAY,
+                    null /* statsToken */);
+        }
+
+        verify(mMockImeTargetVisibilityPolicy).showImeScreenshot(eq(mWindowToken),
+                eq(Display.DEFAULT_DISPLAY));
+    }
+
+    @Test
+    public void testRemoveImeScreenshot() {
+        synchronized (ImfLock.class) {
+            mVisibilityApplier.removeImeScreenshot(Display.DEFAULT_DISPLAY);
+        }
+
+        verify(mMockImeTargetVisibilityPolicy).removeImeScreenshot(eq(Display.DEFAULT_DISPLAY));
+    }
+
     private InputBindResult startInputOrWindowGainedFocus(IBinder windowToken, int softInputMode) {
         return mInputMethodManagerService.startInputOrWindowGainedFocus(
                 StartInputReason.WINDOW_FOCUS_GAIN /* startInputReason */,
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java
index 2a256f2..3871e1d 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java
@@ -24,7 +24,15 @@
 import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.internal.inputmethod.SoftInputShowHideReason.HIDE_WHEN_INPUT_TARGET_INVISIBLE;
+import static com.android.internal.inputmethod.SoftInputShowHideReason.REMOVE_IME_SCREENSHOT_FROM_IMMS;
+import static com.android.internal.inputmethod.SoftInputShowHideReason.SHOW_IME_SCREENSHOT_FROM_IMMS;
 import static com.android.server.inputmethod.ImeVisibilityStateComputer.ImeTargetWindowState;
+import static com.android.server.inputmethod.ImeVisibilityStateComputer.ImeVisibilityResult;
+import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME_EXPLICIT;
+import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_REMOVE_IME_SNAPSHOT;
+import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_SHOW_IME_SNAPSHOT;
 import static com.android.server.inputmethod.InputMethodManagerService.FALLBACK_DISPLAY_ID;
 import static com.android.server.inputmethod.InputMethodManagerService.ImeDisplayValidator;
 
@@ -37,11 +45,13 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
+import com.android.server.wm.ImeTargetChangeListener;
 import com.android.server.wm.WindowManagerInternal;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 
 /**
  * Test the behavior of {@link ImeVisibilityStateComputer} and {@link ImeVisibilityApplier} when
@@ -53,6 +63,7 @@
 @RunWith(AndroidJUnit4.class)
 public class ImeVisibilityStateComputerTest extends InputMethodManagerServiceTestBase {
     private ImeVisibilityStateComputer mComputer;
+    private ImeTargetChangeListener mListener;
     private int mImeDisplayPolicy = DISPLAY_IME_POLICY_LOCAL;
 
     @Before
@@ -69,7 +80,11 @@
                 return displayId -> mImeDisplayPolicy;
             }
         };
+        ArgumentCaptor<ImeTargetChangeListener> captor = ArgumentCaptor.forClass(
+                ImeTargetChangeListener.class);
+        verify(mMockWindowManagerInternal).setInputMethodTargetChangeListener(captor.capture());
         mComputer = new ImeVisibilityStateComputer(mInputMethodManagerService, injector);
+        mListener = captor.getValue();
     }
 
     @Test
@@ -196,6 +211,53 @@
                 lastState.isRequestedImeVisible());
     }
 
+    @Test
+    public void testOnInteractiveChanged() {
+        mComputer.getOrCreateWindowState(mWindowToken);
+        // Precondition: ensure IME has shown before hiding request.
+        mComputer.requestImeVisibility(mWindowToken, true);
+        mComputer.setInputShown(true);
+
+        // No need any visibility change When initially shows IME on the device was interactive.
+        ImeVisibilityStateComputer.ImeVisibilityResult result = mComputer.onInteractiveChanged(
+                mWindowToken, true /* interactive */);
+        assertThat(result).isNull();
+
+        // Show the IME screenshot to capture the last IME visible state when the device inactive.
+        result = mComputer.onInteractiveChanged(mWindowToken, false /* interactive */);
+        assertThat(result).isNotNull();
+        assertThat(result.getState()).isEqualTo(STATE_SHOW_IME_SNAPSHOT);
+        assertThat(result.getReason()).isEqualTo(SHOW_IME_SCREENSHOT_FROM_IMMS);
+
+        // Remove the IME screenshot when the device became interactive again.
+        result = mComputer.onInteractiveChanged(mWindowToken, true /* interactive */);
+        assertThat(result).isNotNull();
+        assertThat(result.getState()).isEqualTo(STATE_REMOVE_IME_SNAPSHOT);
+        assertThat(result.getReason()).isEqualTo(REMOVE_IME_SCREENSHOT_FROM_IMMS);
+    }
+
+    @Test
+    public void testOnApplyImeVisibilityFromComputer() {
+        final IBinder testImeTargetOverlay = new Binder();
+        final IBinder testImeInputTarget = new Binder();
+
+        // Simulate a test IME layering target overlay fully occluded the IME input target.
+        mListener.onImeTargetOverlayVisibilityChanged(testImeTargetOverlay, true, false);
+        mListener.onImeInputTargetVisibilityChanged(testImeInputTarget, false, false);
+        final ArgumentCaptor<IBinder> targetCaptor = ArgumentCaptor.forClass(IBinder.class);
+        final ArgumentCaptor<ImeVisibilityResult> resultCaptor = ArgumentCaptor.forClass(
+                ImeVisibilityResult.class);
+        verify(mInputMethodManagerService).onApplyImeVisibilityFromComputer(targetCaptor.capture(),
+                resultCaptor.capture());
+        final IBinder imeInputTarget = targetCaptor.getValue();
+        final ImeVisibilityResult result = resultCaptor.getValue();
+
+        // Verify the computer will callback hiding IME state to IMMS.
+        assertThat(imeInputTarget).isEqualTo(testImeInputTarget);
+        assertThat(result.getState()).isEqualTo(STATE_HIDE_IME_EXPLICIT);
+        assertThat(result.getReason()).isEqualTo(HIDE_WHEN_INPUT_TARGET_INVISIBLE);
+    }
+
     private ImeTargetWindowState initImeTargetWindowState(IBinder windowToken) {
         final ImeTargetWindowState state = new ImeTargetWindowState(SOFT_INPUT_STATE_UNCHANGED,
                 0, true, true, true);
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
index 90691a7..c80ecbf 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
@@ -62,6 +62,7 @@
 import com.android.server.SystemService;
 import com.android.server.input.InputManagerInternal;
 import com.android.server.pm.UserManagerInternal;
+import com.android.server.wm.ImeTargetVisibilityPolicy;
 import com.android.server.wm.WindowManagerInternal;
 
 import org.junit.After;
@@ -113,6 +114,7 @@
     @Mock protected IInputMethod mMockInputMethod;
     @Mock protected IBinder mMockInputMethodBinder;
     @Mock protected IInputManager mMockIInputManager;
+    @Mock protected ImeTargetVisibilityPolicy mMockImeTargetVisibilityPolicy;
 
     protected Context mContext;
     protected MockitoSession mMockingSession;
@@ -166,6 +168,8 @@
                 .when(() -> LocalServices.getService(DisplayManagerInternal.class));
         doReturn(mMockUserManagerInternal)
                 .when(() -> LocalServices.getService(UserManagerInternal.class));
+        doReturn(mMockImeTargetVisibilityPolicy)
+                .when(() -> LocalServices.getService(ImeTargetVisibilityPolicy.class));
         doReturn(mMockIInputMethodManager)
                 .when(() -> ServiceManager.getServiceOrThrow(Context.INPUT_METHOD_SERVICE));
         doReturn(mMockIPlatformCompat)
@@ -218,6 +222,7 @@
                         false);
         mInputMethodManagerService = new InputMethodManagerService(mContext, mServiceThread,
                 mMockInputMethodBindingController);
+        spyOn(mInputMethodManagerService);
 
         // Start a InputMethodManagerService.Lifecycle to publish and manage the lifecycle of
         // InputMethodManagerService, which is closer to the real situation.
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/HighBrightnessModeMetadataMapperTest.java b/services/tests/mockingservicestests/src/com/android/server/display/HighBrightnessModeMetadataMapperTest.java
new file mode 100644
index 0000000..d9fbba5
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/display/HighBrightnessModeMetadataMapperTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class HighBrightnessModeMetadataMapperTest {
+
+    private HighBrightnessModeMetadataMapper mHighBrightnessModeMetadataMapper;
+
+    @Before
+    public void setUp() {
+        mHighBrightnessModeMetadataMapper = new HighBrightnessModeMetadataMapper();
+    }
+
+    @Test
+    public void testGetHighBrightnessModeMetadata() {
+        // Display device is null
+        final LogicalDisplay display = mock(LogicalDisplay.class);
+        when(display.getPrimaryDisplayDeviceLocked()).thenReturn(null);
+        assertNull(mHighBrightnessModeMetadataMapper.getHighBrightnessModeMetadataLocked(display));
+
+        // No HBM metadata stored for this display yet
+        final DisplayDevice device = mock(DisplayDevice.class);
+        when(display.getPrimaryDisplayDeviceLocked()).thenReturn(device);
+        HighBrightnessModeMetadata hbmMetadata =
+                mHighBrightnessModeMetadataMapper.getHighBrightnessModeMetadataLocked(display);
+        assertTrue(hbmMetadata.getHbmEventQueue().isEmpty());
+        assertTrue(hbmMetadata.getRunningStartTimeMillis() < 0);
+
+        // Modify the metadata
+        long startTimeMillis = 100;
+        long endTimeMillis = 200;
+        long setTime = 300;
+        hbmMetadata.addHbmEvent(new HbmEvent(startTimeMillis, endTimeMillis));
+        hbmMetadata.setRunningStartTimeMillis(setTime);
+        hbmMetadata =
+                mHighBrightnessModeMetadataMapper.getHighBrightnessModeMetadataLocked(display);
+        assertEquals(1, hbmMetadata.getHbmEventQueue().size());
+        assertEquals(startTimeMillis,
+                hbmMetadata.getHbmEventQueue().getFirst().getStartTimeMillis());
+        assertEquals(endTimeMillis, hbmMetadata.getHbmEventQueue().getFirst().getEndTimeMillis());
+        assertEquals(setTime, hbmMetadata.getRunningStartTimeMillis());
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
index aca96ad..aad373f 100644
--- a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
@@ -445,14 +445,14 @@
                         + "    <library \n"
                         + "        name=\"foo\"\n"
                         + "        file=\"" + mFooJar + "\"\n"
-                        + "        on-bootclasspath-before=\"Q\"\n"
+                        + "        on-bootclasspath-before=\"A\"\n"
                         + "        on-bootclasspath-since=\"W\"\n"
                         + "     />\n\n"
                         + " </permissions>";
         parseSharedLibraries(contents);
         assertFooIsOnlySharedLibrary();
         SystemConfig.SharedLibraryEntry entry = mSysConfig.getSharedLibraries().get("foo");
-        assertThat(entry.onBootclasspathBefore).isEqualTo("Q");
+        assertThat(entry.onBootclasspathBefore).isEqualTo("A");
         assertThat(entry.onBootclasspathSince).isEqualTo("W");
     }
 
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
index 90d1488..4406d83 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
@@ -71,10 +71,10 @@
 import android.testing.TestableContext;
 import android.util.ArraySet;
 import android.util.Pair;
-import com.android.modules.utils.TypedXmlPullParser;
-import com.android.modules.utils.TypedXmlSerializer;
 import android.util.Xml;
 
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
 import com.android.server.UiServiceTestCase;
 
 import com.google.common.collect.ImmutableList;
@@ -92,6 +92,7 @@
 import java.io.ByteArrayOutputStream;
 import java.util.Arrays;
 import java.util.List;
+import java.util.concurrent.CountDownLatch;
 
 public class NotificationListenersTest extends UiServiceTestCase {
 
@@ -626,6 +627,58 @@
                 .onNotificationChannelGroupModification(anyString(), any(), any(), anyInt());
     }
 
+    @Test
+    public void testNotificationListenerFilter_threadSafety() throws Exception {
+        testThreadSafety(() -> {
+            mListeners.setNotificationListenerFilter(
+                    new Pair<>(new ComponentName("pkg1", "cls1"), 0),
+                    new NotificationListenerFilter());
+            mListeners.setNotificationListenerFilter(
+                    new Pair<>(new ComponentName("pkg2", "cls2"), 10),
+                    new NotificationListenerFilter());
+            mListeners.setNotificationListenerFilter(
+                    new Pair<>(new ComponentName("pkg3", "cls3"), 11),
+                    new NotificationListenerFilter());
+
+            mListeners.onUserRemoved(10);
+            mListeners.onPackagesChanged(true, new String[]{"pkg1", "pkg2"}, new int[]{0, 0});
+        }, 20, 50);
+    }
+
+    /**
+     * Helper method to test the thread safety of some operations.
+     *
+     * <p>Runs the supplied {@code operationToTest}, {@code nRunsPerThread} times,
+     * concurrently using {@code nThreads} threads, and waits for all of them to finish.
+     */
+    private static void testThreadSafety(Runnable operationToTest, int nThreads,
+            int nRunsPerThread) throws InterruptedException {
+        final CountDownLatch startLatch = new CountDownLatch(1);
+        final CountDownLatch doneLatch = new CountDownLatch(nThreads);
+
+        for (int i = 0; i < nThreads; i++) {
+            Runnable threadRunnable = () -> {
+                try {
+                    startLatch.await();
+                    for (int j = 0; j < nRunsPerThread; j++) {
+                        operationToTest.run();
+                    }
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                } finally {
+                    doneLatch.countDown();
+                }
+            };
+            new Thread(threadRunnable, "Test Thread #" + i).start();
+        }
+
+        // Ready set go
+        startLatch.countDown();
+
+        // Wait for all test threads to be done.
+        doneLatch.await();
+    }
+
     private ManagedServices.ManagedServiceInfo getParcelingListener(
             final NotificationChannelGroup toParcel)
             throws RemoteException {
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 9cfdaa7..dd9f3cb 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -5447,6 +5447,29 @@
     }
 
     @Test
+    public void testVisitUris_callStyle() {
+        Icon personIcon = Icon.createWithContentUri("content://media/person");
+        Icon verificationIcon = Icon.createWithContentUri("content://media/verification");
+        Person callingPerson = new Person.Builder().setName("Someone")
+                .setIcon(personIcon)
+                .build();
+        PendingIntent hangUpIntent = PendingIntent.getActivity(mContext, 0, new Intent(),
+                PendingIntent.FLAG_IMMUTABLE);
+        Notification n = new Notification.Builder(mContext, "a")
+                .setStyle(Notification.CallStyle.forOngoingCall(callingPerson, hangUpIntent)
+                        .setVerificationIcon(verificationIcon))
+                .setContentTitle("Calling...")
+                .setSmallIcon(android.R.drawable.sym_def_app_icon)
+                .build();
+
+        Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
+        n.visitUris(visitor);
+
+        verify(visitor, times(1)).accept(eq(personIcon.getUri()));
+        verify(visitor, times(1)).accept(eq(verificationIcon.getUri()));
+    }
+
+    @Test
     public void testVisitUris_audioContentsString() throws Exception {
         final Uri audioContents = Uri.parse("content://com.example/audio");
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index 4e001fe..37c4b37 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -28,6 +28,7 @@
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assert.assertNull;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
@@ -501,6 +502,12 @@
         onActivityLaunched(mTrampolineActivity);
         mActivityMetricsLogger.notifyActivityLaunching(mTopActivity.intent,
                 mTrampolineActivity /* caller */, mTrampolineActivity.getUid());
+
+        // Simulate a corner case that the trampoline activity is removed by CLEAR_TASK.
+        // The 2 launch events can still be coalesced to one by matching the uid.
+        mTrampolineActivity.takeFromHistory();
+        assertNull(mTrampolineActivity.getTask());
+
         notifyActivityLaunched(START_SUCCESS, mTopActivity);
         transitToDrawnAndVerifyOnLaunchFinished(mTopActivity);
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 8f2b470..0033e3e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -2399,7 +2399,10 @@
         holder.addConnection(connection);
         assertTrue(holder.isActivityVisible());
         final int[] count = new int[1];
-        final Consumer<Object> c = conn -> count[0]++;
+        final Consumer<Object> c = conn -> {
+            count[0]++;
+            assertFalse(Thread.holdsLock(activity));
+        };
         holder.forEachConnection(c);
         assertEquals(1, count[0]);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
index 17ae215..6d7f2c1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
@@ -232,11 +232,36 @@
 
         IOnBackInvokedCallback callback = createOnBackInvokedCallback();
         window.setOnBackInvokedCallbackInfo(
-                new OnBackInvokedCallbackInfo(callback, OnBackInvokedDispatcher.PRIORITY_DEFAULT));
+                new OnBackInvokedCallbackInfo(
+                        callback,
+                        OnBackInvokedDispatcher.PRIORITY_DEFAULT,
+                        /* isAnimationCallback = */ false));
 
         BackNavigationInfo backNavigationInfo = startBackNavigation();
         assertWithMessage("BackNavigationInfo").that(backNavigationInfo).isNotNull();
         assertThat(backNavigationInfo.getType()).isEqualTo(BackNavigationInfo.TYPE_CALLBACK);
+        assertThat(backNavigationInfo.isAnimationCallback()).isEqualTo(false);
+        assertThat(backNavigationInfo.getOnBackInvokedCallback()).isEqualTo(callback);
+    }
+
+    @Test
+    public void backInfoWithAnimationCallback() {
+        WindowState window = createWindow(null, WindowManager.LayoutParams.TYPE_WALLPAPER,
+                "Wallpaper");
+        addToWindowMap(window, true);
+        makeWindowVisibleAndDrawn(window);
+
+        IOnBackInvokedCallback callback = createOnBackInvokedCallback();
+        window.setOnBackInvokedCallbackInfo(
+                new OnBackInvokedCallbackInfo(
+                        callback,
+                        OnBackInvokedDispatcher.PRIORITY_DEFAULT,
+                        /* isAnimationCallback = */ true));
+
+        BackNavigationInfo backNavigationInfo = startBackNavigation();
+        assertWithMessage("BackNavigationInfo").that(backNavigationInfo).isNotNull();
+        assertThat(backNavigationInfo.getType()).isEqualTo(BackNavigationInfo.TYPE_CALLBACK);
+        assertThat(backNavigationInfo.isAnimationCallback()).isEqualTo(true);
         assertThat(backNavigationInfo.getOnBackInvokedCallback()).isEqualTo(callback);
     }
 
@@ -364,7 +389,10 @@
 
         IOnBackInvokedCallback callback = createOnBackInvokedCallback();
         window.setOnBackInvokedCallbackInfo(
-                new OnBackInvokedCallbackInfo(callback, OnBackInvokedDispatcher.PRIORITY_DEFAULT));
+                new OnBackInvokedCallbackInfo(
+                        callback,
+                        OnBackInvokedDispatcher.PRIORITY_DEFAULT,
+                        /* isAnimationCallback = */ false));
 
         BackNavigationInfo backNavigationInfo = startBackNavigation();
         assertThat(backNavigationInfo).isNull();
@@ -450,14 +478,20 @@
     private IOnBackInvokedCallback withSystemCallback(Task task) {
         IOnBackInvokedCallback callback = createOnBackInvokedCallback();
         task.getTopMostActivity().getTopChild().setOnBackInvokedCallbackInfo(
-                new OnBackInvokedCallbackInfo(callback, OnBackInvokedDispatcher.PRIORITY_SYSTEM));
+                new OnBackInvokedCallbackInfo(
+                        callback,
+                        OnBackInvokedDispatcher.PRIORITY_SYSTEM,
+                        /* isAnimationCallback = */ false));
         return callback;
     }
 
     private IOnBackInvokedCallback withAppCallback(Task task) {
         IOnBackInvokedCallback callback = createOnBackInvokedCallback();
         task.getTopMostActivity().getTopChild().setOnBackInvokedCallbackInfo(
-                new OnBackInvokedCallbackInfo(callback, OnBackInvokedDispatcher.PRIORITY_DEFAULT));
+                new OnBackInvokedCallbackInfo(
+                        callback,
+                        OnBackInvokedDispatcher.PRIORITY_DEFAULT,
+                        /* isAnimationCallback = */ false));
         return callback;
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
index 2065540..a8fc25f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
@@ -84,12 +84,14 @@
     }
 
     @Test
-    public void testControlsForDispatch_multiWindowTaskVisible() {
+    public void testControlsForDispatch_adjacentTasksVisible() {
         addStatusBar();
         addNavigationBar();
 
-        final WindowState win = createWindow(null, WINDOWING_MODE_MULTI_WINDOW,
-                ACTIVITY_TYPE_STANDARD, TYPE_APPLICATION, mDisplayContent, "app");
+        final Task task1 = createTask(mDisplayContent);
+        final Task task2 = createTask(mDisplayContent);
+        task1.setAdjacentTaskFragment(task2);
+        final WindowState win = createAppWindow(task1, WINDOWING_MODE_MULTI_WINDOW, "app");
         final InsetsSourceControl[] controls = addWindowAndGetControlsForDispatch(win);
 
         // The app must not control any system bars.
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
index 49d8da1..9d597b1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
@@ -586,6 +586,15 @@
         // Making the activity0 be the focused activity and ensure the focused app is updated.
         activity0.moveFocusableActivityToTop("test");
         assertEquals(activity0, mDisplayContent.mFocusedApp);
+
+        // Moving activity1 to top and make both the two activities resumed.
+        activity1.moveFocusableActivityToTop("test");
+        activity0.setState(RESUMED, "test");
+        activity1.setState(RESUMED, "test");
+
+        // Verifies that the focus app can be updated to an Activity in the adjacent TF
+        mAtm.setFocusedTask(task.mTaskId, activity0);
+        assertEquals(activity0, mDisplayContent.mFocusedApp);
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 766e74c..460a603 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -20,6 +20,7 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.InsetsSource.ID_IME;
 import static android.view.Surface.ROTATION_0;
 import static android.view.Surface.ROTATION_270;
@@ -85,17 +86,25 @@
 import android.graphics.Matrix;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.os.Bundle;
 import android.os.IBinder;
 import android.os.InputConfig;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
 import android.util.ArraySet;
+import android.util.MergedConfiguration;
 import android.view.Gravity;
+import android.view.IWindow;
+import android.view.IWindowSessionCallback;
 import android.view.InputWindowHandle;
 import android.view.InsetsSource;
+import android.view.InsetsSourceControl;
 import android.view.InsetsState;
 import android.view.SurfaceControl;
+import android.view.View;
+import android.view.WindowInsets;
 import android.view.WindowManager;
+import android.window.ClientWindowFrames;
 import android.window.ITaskFragmentOrganizer;
 import android.window.TaskFragmentOrganizer;
 
@@ -1280,4 +1289,118 @@
         assertEquals(new ArraySet(Arrays.asList(expectedArea1, expectedArea2)),
                      new ArraySet(unrestrictedKeepClearAreas));
     }
+
+    @Test
+    public void testImeTargetChangeListener_OnImeInputTargetVisibilityChanged() {
+        final TestImeTargetChangeListener listener = new TestImeTargetChangeListener();
+        mWm.mImeTargetChangeListener = listener;
+
+        final WindowState imeTarget = createWindow(null /* parent */, TYPE_BASE_APPLICATION,
+                createActivityRecord(mDisplayContent), "imeTarget");
+
+        imeTarget.mActivityRecord.setVisibleRequested(true);
+        makeWindowVisible(imeTarget);
+        mDisplayContent.setImeInputTarget(imeTarget);
+        waitHandlerIdle(mWm.mH);
+
+        assertThat(listener.mImeTargetToken).isEqualTo(imeTarget.mClient.asBinder());
+        assertThat(listener.mIsRemoved).isFalse();
+        assertThat(listener.mIsVisibleForImeInputTarget).isTrue();
+
+        imeTarget.mActivityRecord.setVisibleRequested(false);
+        waitHandlerIdle(mWm.mH);
+
+        assertThat(listener.mImeTargetToken).isEqualTo(imeTarget.mClient.asBinder());
+        assertThat(listener.mIsRemoved).isFalse();
+        assertThat(listener.mIsVisibleForImeInputTarget).isFalse();
+
+        imeTarget.removeImmediately();
+        assertThat(listener.mImeTargetToken).isEqualTo(imeTarget.mClient.asBinder());
+        assertThat(listener.mIsRemoved).isTrue();
+        assertThat(listener.mIsVisibleForImeInputTarget).isFalse();
+    }
+
+    @SetupWindows(addWindows = {W_INPUT_METHOD})
+    @Test
+    public void testImeTargetChangeListener_OnImeTargetOverlayVisibilityChanged() {
+        final TestImeTargetChangeListener listener = new TestImeTargetChangeListener();
+        mWm.mImeTargetChangeListener = listener;
+
+        // Scenario 1: test addWindow/relayoutWindow to add Ime layering overlay window as visible.
+        final WindowToken windowToken = createTestWindowToken(TYPE_APPLICATION_OVERLAY,
+                mDisplayContent);
+        final IWindow client = new TestIWindow();
+        final Session session = new Session(mWm, new IWindowSessionCallback.Stub() {
+            @Override
+            public void onAnimatorScaleChanged(float v) throws RemoteException {
+
+            }
+        });
+        final ClientWindowFrames outFrames = new ClientWindowFrames();
+        final MergedConfiguration outConfig = new MergedConfiguration();
+        final SurfaceControl outSurfaceControl = new SurfaceControl();
+        final InsetsState outInsetsState = new InsetsState();
+        final InsetsSourceControl.Array outControls = new InsetsSourceControl.Array();
+        final Bundle outBundle = new Bundle();
+        final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
+                TYPE_APPLICATION_OVERLAY);
+        params.setTitle("imeLayeringTargetOverlay");
+        params.token = windowToken.token;
+        params.flags = FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM;
+
+        mWm.addWindow(session, client, params, View.VISIBLE, DEFAULT_DISPLAY,
+                0 /* userUd */, WindowInsets.Type.defaultVisible(), null, new InsetsState(),
+                new InsetsSourceControl.Array(), new Rect(), new float[1]);
+        mWm.relayoutWindow(session, client, params, 100, 200, View.VISIBLE, 0, 0, 0,
+                outFrames, outConfig, outSurfaceControl, outInsetsState, outControls, outBundle);
+        waitHandlerIdle(mWm.mH);
+
+        final WindowState imeLayeringTargetOverlay = mDisplayContent.getWindow(
+                w -> w.mClient.asBinder() == client.asBinder());
+        assertThat(imeLayeringTargetOverlay.isVisible()).isTrue();
+        assertThat(listener.mImeTargetToken).isEqualTo(client.asBinder());
+        assertThat(listener.mIsRemoved).isFalse();
+        assertThat(listener.mIsVisibleForImeTargetOverlay).isTrue();
+
+        // Scenario 2: test relayoutWindow to let the Ime layering target overlay window invisible.
+        mWm.relayoutWindow(session, client, params, 100, 200, View.GONE, 0, 0, 0,
+                outFrames, outConfig, outSurfaceControl, outInsetsState, outControls, outBundle);
+        waitHandlerIdle(mWm.mH);
+
+        assertThat(imeLayeringTargetOverlay.isVisible()).isFalse();
+        assertThat(listener.mImeTargetToken).isEqualTo(client.asBinder());
+        assertThat(listener.mIsRemoved).isFalse();
+        assertThat(listener.mIsVisibleForImeTargetOverlay).isFalse();
+
+        // Scenario 3: test removeWindow to remove the Ime layering target overlay window.
+        mWm.removeWindow(session, client);
+        waitHandlerIdle(mWm.mH);
+
+        assertThat(listener.mImeTargetToken).isEqualTo(client.asBinder());
+        assertThat(listener.mIsRemoved).isTrue();
+        assertThat(listener.mIsVisibleForImeTargetOverlay).isFalse();
+    }
+
+    private static class TestImeTargetChangeListener implements ImeTargetChangeListener {
+        private IBinder mImeTargetToken;
+        private boolean mIsRemoved;
+        private boolean mIsVisibleForImeTargetOverlay;
+        private boolean mIsVisibleForImeInputTarget;
+
+        @Override
+        public void onImeTargetOverlayVisibilityChanged(IBinder overlayWindowToken, boolean visible,
+                boolean removed) {
+            mImeTargetToken = overlayWindowToken;
+            mIsVisibleForImeTargetOverlay = visible;
+            mIsRemoved = removed;
+        }
+
+        @Override
+        public void onImeInputTargetVisibilityChanged(IBinder imeInputTarget,
+                boolean visibleRequested, boolean removed) {
+            mImeTargetToken = imeInputTarget;
+            mIsVisibleForImeInputTarget = visibleRequested;
+            mIsRemoved = removed;
+        }
+    }
 }
diff --git a/telephony/OWNERS b/telephony/OWNERS
index 025869d..3158ad8 100644
--- a/telephony/OWNERS
+++ b/telephony/OWNERS
@@ -11,12 +11,6 @@
 amruthr@google.com
 sasindran@google.com
 
-# Temporarily reduced the owner during refactoring
-per-file SubscriptionManager.java=set noparent
-per-file SubscriptionManager.java=jackyu@google.com,amruthr@google.com
-per-file SubscriptionInfo.java=set noparent
-per-file SubscriptionInfo.java=jackyu@google.com,amruthr@google.com
-
 # Requiring TL ownership for new carrier config keys.
 per-file CarrierConfigManager.java=set noparent
 per-file CarrierConfigManager.java=amruthr@google.com,tgunn@google.com,rgreenwalt@google.com,satk@google.com
diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
index 905a90c..caafce2 100644
--- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -331,8 +331,8 @@
      * Same as {@link #checkCallingOrSelfReadSubscriberIdentifiers(Context, int, String, String,
      * String)} except this allows an additional parameter reportFailure. Caller may not want to
      * report a failure when this is an internal/intermediate check, for example,
-     * SubscriptionController calls this with an INVALID_SUBID to check if caller has the required
-     * permissions to bypass carrier privilege checks.
+     * SubscriptionManagerService calls this with an INVALID_SUBID to check if caller has the
+     * required permissions to bypass carrier privilege checks.
      * @param reportFailure Indicates if failure should be reported.
      */
     public static boolean checkCallingOrSelfReadSubscriberIdentifiers(Context context, int subId,
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 559faf9..64e4356 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -91,8 +91,7 @@
 import java.util.stream.Collectors;
 
 /**
- * SubscriptionManager is the application interface to SubscriptionController
- * and provides information about the current Telephony Subscriptions.
+ * Subscription manager provides the mobile subscription information.
  */
 @SystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)
 @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
@@ -119,13 +118,12 @@
     public static final int DEFAULT_SUBSCRIPTION_ID = Integer.MAX_VALUE;
 
     /**
-     * Indicates the caller wants the default phone id.
-     * Used in SubscriptionController and Phone but do we really need it???
+     * Indicates the default phone id.
      * @hide
      */
     public static final int DEFAULT_PHONE_INDEX = Integer.MAX_VALUE;
 
-    /** Indicates the caller wants the default slot id. NOT used remove? */
+    /** Indicates the default slot index. */
     /** @hide */
     public static final int DEFAULT_SIM_SLOT_INDEX = Integer.MAX_VALUE;
 
@@ -141,29 +139,10 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public static final Uri CONTENT_URI = SimInfo.CONTENT_URI;
 
-    private static final String CACHE_KEY_DEFAULT_SUB_ID_PROPERTY =
-            "cache_key.telephony.get_default_sub_id";
-
-    private static final String CACHE_KEY_DEFAULT_DATA_SUB_ID_PROPERTY =
-            "cache_key.telephony.get_default_data_sub_id";
-
-    private static final String CACHE_KEY_DEFAULT_SMS_SUB_ID_PROPERTY =
-            "cache_key.telephony.get_default_sms_sub_id";
-
-    private static final String CACHE_KEY_ACTIVE_DATA_SUB_ID_PROPERTY =
-            "cache_key.telephony.get_active_data_sub_id";
-
-    private static final String CACHE_KEY_SLOT_INDEX_PROPERTY =
-            "cache_key.telephony.get_slot_index";
-
     /** The IPC cache key shared by all subscription manager service cacheable properties. */
     private static final String CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY =
             "cache_key.telephony.subscription_manager_service";
 
-    /** The temporarily cache key to indicate whether subscription manager service is enabled. */
-    private static final String CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_ENABLED_PROPERTY =
-            "cache_key.telephony.subscription_manager_service_enabled";
-
     /** @hide */
     public static final String GET_SIM_SPECIFIC_SETTINGS_METHOD_NAME = "getSimSpecificSettings";
 
@@ -273,83 +252,41 @@
         }
     }
 
-    private static VoidPropertyInvalidatedCache<Integer> sDefaultSubIdCache =
-            new VoidPropertyInvalidatedCache<>(ISub::getDefaultSubId,
-                    CACHE_KEY_DEFAULT_SUB_ID_PROPERTY,
-                    INVALID_SUBSCRIPTION_ID);
-
     private static VoidPropertyInvalidatedCache<Integer> sGetDefaultSubIdCache =
             new VoidPropertyInvalidatedCache<>(ISub::getDefaultSubId,
                     CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY,
                     INVALID_SUBSCRIPTION_ID);
 
-    private static VoidPropertyInvalidatedCache<Integer> sDefaultDataSubIdCache =
-            new VoidPropertyInvalidatedCache<>(ISub::getDefaultDataSubId,
-                    CACHE_KEY_DEFAULT_DATA_SUB_ID_PROPERTY,
-                    INVALID_SUBSCRIPTION_ID);
-
     private static VoidPropertyInvalidatedCache<Integer> sGetDefaultDataSubIdCache =
             new VoidPropertyInvalidatedCache<>(ISub::getDefaultDataSubId,
                     CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY,
                     INVALID_SUBSCRIPTION_ID);
 
-    private static VoidPropertyInvalidatedCache<Integer> sDefaultSmsSubIdCache =
-            new VoidPropertyInvalidatedCache<>(ISub::getDefaultSmsSubId,
-                    CACHE_KEY_DEFAULT_SMS_SUB_ID_PROPERTY,
-                    INVALID_SUBSCRIPTION_ID);
-
     private static VoidPropertyInvalidatedCache<Integer> sGetDefaultSmsSubIdCache =
             new VoidPropertyInvalidatedCache<>(ISub::getDefaultSmsSubId,
                     CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY,
                     INVALID_SUBSCRIPTION_ID);
 
-    private static VoidPropertyInvalidatedCache<Integer> sActiveDataSubIdCache =
-            new VoidPropertyInvalidatedCache<>(ISub::getActiveDataSubscriptionId,
-                    CACHE_KEY_ACTIVE_DATA_SUB_ID_PROPERTY,
-                    INVALID_SUBSCRIPTION_ID);
-
     private static VoidPropertyInvalidatedCache<Integer> sGetActiveDataSubscriptionIdCache =
             new VoidPropertyInvalidatedCache<>(ISub::getActiveDataSubscriptionId,
                     CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY,
                     INVALID_SUBSCRIPTION_ID);
 
-    private static IntegerPropertyInvalidatedCache<Integer> sSlotIndexCache =
-            new IntegerPropertyInvalidatedCache<>(ISub::getSlotIndex,
-                    CACHE_KEY_SLOT_INDEX_PROPERTY,
-                    INVALID_SIM_SLOT_INDEX);
-
     private static IntegerPropertyInvalidatedCache<Integer> sGetSlotIndexCache =
             new IntegerPropertyInvalidatedCache<>(ISub::getSlotIndex,
                     CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY,
                     INVALID_SIM_SLOT_INDEX);
 
-    private static IntegerPropertyInvalidatedCache<Integer> sSubIdCache =
-            new IntegerPropertyInvalidatedCache<>(ISub::getSubId,
-                    CACHE_KEY_SLOT_INDEX_PROPERTY,
-                    INVALID_SUBSCRIPTION_ID);
-
     private static IntegerPropertyInvalidatedCache<Integer> sGetSubIdCache =
             new IntegerPropertyInvalidatedCache<>(ISub::getSubId,
                     CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY,
                     INVALID_SUBSCRIPTION_ID);
 
-    /** Cache depends on getDefaultSubId, so we use the defaultSubId cache key */
-    private static IntegerPropertyInvalidatedCache<Integer> sPhoneIdCache =
-            new IntegerPropertyInvalidatedCache<>(ISub::getPhoneId,
-                    CACHE_KEY_DEFAULT_SUB_ID_PROPERTY,
-                    INVALID_PHONE_INDEX);
-
     private static IntegerPropertyInvalidatedCache<Integer> sGetPhoneIdCache =
             new IntegerPropertyInvalidatedCache<>(ISub::getPhoneId,
                     CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY,
                     INVALID_PHONE_INDEX);
 
-    //TODO: Removed before U AOSP public release.
-    private static VoidPropertyInvalidatedCache<Boolean> sIsSubscriptionManagerServiceEnabled =
-            new VoidPropertyInvalidatedCache<>(ISub::isSubscriptionManagerServiceEnabled,
-                    CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_ENABLED_PROPERTY,
-                    false);
-
     /**
      * Generates a content {@link Uri} used to receive updates on simInfo change
      * on the given subscriptionId
@@ -1455,17 +1392,6 @@
         mContext = context;
     }
 
-    /**
-     * @return {@code true} if the new subscription manager service is used. This is temporary and
-     * will be removed before Android 14 release.
-     *
-     * @hide
-     */
-    //TODO: Removed before U AOSP public release.
-    public static boolean isSubscriptionManagerServiceEnabled() {
-        return sIsSubscriptionManagerServiceEnabled.query(null);
-    }
-
     private NetworkPolicyManager getNetworkPolicyManager() {
         return (NetworkPolicyManager) mContext
                 .getSystemService(Context.NETWORK_POLICY_SERVICE);
@@ -1520,7 +1446,7 @@
                     + " listener=" + listener);
         }
         // We use the TelephonyRegistry as it runs in the system and thus is always
-        // available. Where as SubscriptionController could crash and not be available
+        // available.
         TelephonyRegistryManager telephonyRegistryManager = (TelephonyRegistryManager)
                 mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE);
         if (telephonyRegistryManager != null) {
@@ -1550,7 +1476,7 @@
                     + " listener=" + listener);
         }
         // We use the TelephonyRegistry as it runs in the system and thus is always
-        // available where as SubscriptionController could crash and not be available
+        // available.
         TelephonyRegistryManager telephonyRegistryManager = (TelephonyRegistryManager)
                 mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE);
         if (telephonyRegistryManager != null) {
@@ -1608,7 +1534,7 @@
         }
 
         // We use the TelephonyRegistry as it runs in the system and thus is always
-        // available where as SubscriptionController could crash and not be available
+        // available.
         TelephonyRegistryManager telephonyRegistryManager = (TelephonyRegistryManager)
                 mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE);
         if (telephonyRegistryManager != null) {
@@ -2149,9 +2075,9 @@
                 Log.e(LOG_TAG, "[removeSubscriptionInfoRecord]- ISub service is null");
                 return;
             }
-            int result = iSub.removeSubInfo(uniqueId, subscriptionType);
-            if (result < 0) {
-                Log.e(LOG_TAG, "Removal of subscription didn't succeed: error = " + result);
+            boolean result = iSub.removeSubInfo(uniqueId, subscriptionType);
+            if (!result) {
+                Log.e(LOG_TAG, "Removal of subscription didn't succeed");
             } else {
                 logd("successfully removed subscription");
             }
@@ -2236,8 +2162,7 @@
      * subscriptionId doesn't have an associated slot index.
      */
     public static int getSlotIndex(int subscriptionId) {
-        if (isSubscriptionManagerServiceEnabled()) return sGetSlotIndexCache.query(subscriptionId);
-        return sSlotIndexCache.query(subscriptionId);
+        return sGetSlotIndexCache.query(subscriptionId);
     }
 
     /**
@@ -2294,15 +2219,13 @@
             return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
         }
 
-        if (isSubscriptionManagerServiceEnabled()) return sGetSubIdCache.query(slotIndex);
-        return sSubIdCache.query(slotIndex);
+        return sGetSubIdCache.query(slotIndex);
     }
 
     /** @hide */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public static int getPhoneId(int subId) {
-        if (isSubscriptionManagerServiceEnabled()) return sGetPhoneIdCache.query(subId);
-        return sPhoneIdCache.query(subId);
+        return sGetPhoneIdCache.query(subId);
     }
 
     private static void logd(String msg) {
@@ -2323,8 +2246,7 @@
      * @return the "system" default subscription id.
      */
     public static int getDefaultSubscriptionId() {
-        if (isSubscriptionManagerServiceEnabled()) return sGetDefaultSubIdCache.query(null);
-        return sDefaultSubIdCache.query(null);
+        return sGetDefaultSubIdCache.query(null);
     }
 
     /**
@@ -2412,8 +2334,7 @@
      * @return the default SMS subscription Id.
      */
     public static int getDefaultSmsSubscriptionId() {
-        if (isSubscriptionManagerServiceEnabled()) return sGetDefaultSmsSubIdCache.query(null);
-        return sDefaultSmsSubIdCache.query(null);
+        return sGetDefaultSmsSubIdCache.query(null);
     }
 
     /**
@@ -2447,8 +2368,7 @@
      * @return the default data subscription Id.
      */
     public static int getDefaultDataSubscriptionId() {
-        if (isSubscriptionManagerServiceEnabled()) return sGetDefaultDataSubIdCache.query(null);
-        return sDefaultDataSubIdCache.query(null);
+        return sGetDefaultDataSubIdCache.query(null);
     }
 
     /**
@@ -3912,10 +3832,7 @@
      * @see TelephonyCallback.ActiveDataSubscriptionIdListener
      */
     public static int getActiveDataSubscriptionId() {
-        if (isSubscriptionManagerServiceEnabled()) {
-            return sGetActiveDataSubscriptionIdCache.query(null);
-        }
-        return sActiveDataSubIdCache.query(null);
+        return sGetActiveDataSubscriptionIdCache.query(null);
     }
 
     /**
@@ -3934,61 +3851,16 @@
     }
 
     /** @hide */
-    public static void invalidateDefaultSubIdCaches() {
-        PropertyInvalidatedCache.invalidateCache(CACHE_KEY_DEFAULT_SUB_ID_PROPERTY);
-    }
-
-    /** @hide */
-    public static void invalidateDefaultDataSubIdCaches() {
-        PropertyInvalidatedCache.invalidateCache(CACHE_KEY_DEFAULT_DATA_SUB_ID_PROPERTY);
-    }
-
-    /** @hide */
-    public static void invalidateDefaultSmsSubIdCaches() {
-        PropertyInvalidatedCache.invalidateCache(CACHE_KEY_DEFAULT_SMS_SUB_ID_PROPERTY);
-    }
-
-    /** @hide */
-    public static void invalidateActiveDataSubIdCaches() {
-        if (isSubscriptionManagerServiceEnabled()) {
-            PropertyInvalidatedCache.invalidateCache(
-                    CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY);
-        } else {
-            PropertyInvalidatedCache.invalidateCache(CACHE_KEY_ACTIVE_DATA_SUB_ID_PROPERTY);
-        }
-    }
-
-    /** @hide */
-    public static void invalidateSlotIndexCaches() {
-        PropertyInvalidatedCache.invalidateCache(CACHE_KEY_SLOT_INDEX_PROPERTY);
-    }
-
-    /** @hide */
     public static void invalidateSubscriptionManagerServiceCaches() {
         PropertyInvalidatedCache.invalidateCache(CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY);
     }
 
-    /** @hide */
-    //TODO: Removed before U AOSP public release.
-    public static void invalidateSubscriptionManagerServiceEnabledCaches() {
-        PropertyInvalidatedCache.invalidateCache(
-                CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_ENABLED_PROPERTY);
-    }
-
     /**
      * Allows a test process to disable client-side caching operations.
      *
      * @hide
      */
     public static void disableCaching() {
-        sDefaultSubIdCache.disableLocal();
-        sDefaultDataSubIdCache.disableLocal();
-        sActiveDataSubIdCache.disableLocal();
-        sDefaultSmsSubIdCache.disableLocal();
-        sSlotIndexCache.disableLocal();
-        sSubIdCache.disableLocal();
-        sPhoneIdCache.disableLocal();
-
         sGetDefaultSubIdCache.disableLocal();
         sGetDefaultDataSubIdCache.disableLocal();
         sGetActiveDataSubscriptionIdCache.disableLocal();
@@ -3996,8 +3868,6 @@
         sGetSlotIndexCache.disableLocal();
         sGetSubIdCache.disableLocal();
         sGetPhoneIdCache.disableLocal();
-
-        sIsSubscriptionManagerServiceEnabled.disableLocal();
     }
 
     /**
@@ -4005,14 +3875,6 @@
      *
      * @hide */
     public static void clearCaches() {
-        sDefaultSubIdCache.clear();
-        sDefaultDataSubIdCache.clear();
-        sActiveDataSubIdCache.clear();
-        sDefaultSmsSubIdCache.clear();
-        sSlotIndexCache.clear();
-        sSubIdCache.clear();
-        sPhoneIdCache.clear();
-
         sGetDefaultSubIdCache.clear();
         sGetDefaultDataSubIdCache.clear();
         sGetActiveDataSubscriptionIdCache.clear();
@@ -4020,8 +3882,6 @@
         sGetSlotIndexCache.clear();
         sGetSubIdCache.clear();
         sGetPhoneIdCache.clear();
-
-        sIsSubscriptionManagerServiceEnabled.clear();
     }
 
     /**
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index 6a5380d..21a6b44 100644
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -129,9 +129,9 @@
      * @param uniqueId This is the unique identifier for the subscription within the specific
      *                      subscription type.
      * @param subscriptionType the type of subscription to be removed
-     * @return 0 if success, < 0 on error.
+     * @return true if success, false on error.
      */
-    int removeSubInfo(String uniqueId, int subscriptionType);
+    boolean removeSubInfo(String uniqueId, int subscriptionType);
 
     /**
      * Set SIM icon tint color by simInfo index
@@ -260,7 +260,7 @@
 
     int[] getActiveSubIdList(boolean visibleOnly);
 
-    int setSubscriptionProperty(int subId, String propKey, String propValue);
+    void setSubscriptionProperty(int subId, String propKey, String propValue);
 
     String getSubscriptionProperty(int subId, String propKey, String callingPackage,
             String callingFeatureId);
@@ -353,13 +353,6 @@
        */
        List<SubscriptionInfo> getSubscriptionInfoListAssociatedWithUser(in UserHandle userHandle);
 
-       /**
-        * @return {@code true} if using SubscriptionManagerService instead of
-        * SubscriptionController.
-        */
-       //TODO: Removed before U AOSP public release.
-       boolean isSubscriptionManagerServiceEnabled();
-
       /**
        * Called during setup wizard restore flow to attempt to restore the backed up sim-specific
        * configs to device for all existing SIMs in the subscription database
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraOnDoubleClickPowerButton.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraOnDoubleClickPowerButton.kt
index 18e49fe..ae9ca80 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraOnDoubleClickPowerButton.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraOnDoubleClickPowerButton.kt
@@ -102,7 +102,7 @@
 
     @Postsubmit @Test override fun entireScreenCovered() = super.entireScreenCovered()
 
-    @Postsubmit
+    @Ignore("Not applicable to this CUJ. App is full screen at the end")
     @Test
     override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
 
@@ -127,11 +127,11 @@
     @Test
     override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
 
-    @Postsubmit
+    @Ignore("Not applicable to this CUJ. App is full screen at the end")
     @Test
     override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
 
-    @Postsubmit
+    @Ignore("Not applicable to this CUJ. App is full screen at the end")
     @Test
     override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible()
 
@@ -145,7 +145,7 @@
     override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
         super.visibleWindowsShownMoreThanOneConsecutiveEntry()
 
-    @Postsubmit
+    @Ignore("Not applicable to this CUJ. App is full screen at the end")
     @Test
     override fun navBarWindowIsVisibleAtStartAndEnd() {
         super.navBarWindowIsVisibleAtStartAndEnd()
diff --git a/tools/validatekeymaps/Android.bp b/tools/validatekeymaps/Android.bp
index 25373f9..554f64e 100644
--- a/tools/validatekeymaps/Android.bp
+++ b/tools/validatekeymaps/Android.bp
@@ -15,7 +15,7 @@
 
 cc_binary_host {
     name: "validatekeymaps",
-
+    cpp_std: "c++20",
     srcs: ["Main.cpp"],
 
     cflags: [