Merge "New trace sections for shade expansion" into udc-dev
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
index b732da2..19a4766 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
@@ -24,11 +24,9 @@
 
 import android.annotation.NonNull;
 import android.app.ActivityManager;
-import android.app.ActivityTaskManager;
 import android.app.AppGlobals;
 import android.app.IActivityManager;
 import android.app.IStopUserCallback;
-import android.app.WaitResult;
 import android.app.WallpaperManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -69,6 +67,7 @@
 import java.util.ArrayList;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 /**
  * Perf tests for user life cycle events.
@@ -101,7 +100,6 @@
     private static final long TIMEOUT_MAX_TEST_TIME_MS = 24 * 60_000;
 
     private static final int TIMEOUT_IN_SECOND = 30;
-    private static final int CHECK_USER_REMOVED_INTERVAL_MS = 200;
 
     /** Name of users/profiles in the test. Users with this name may be freely removed. */
     private static final String TEST_USER_NAME = "UserLifecycleTests_test_user";
@@ -1261,15 +1259,13 @@
      * <p> This should always be used for profiles since profiles cannot be started in foreground.
      */
     private void startUserInBackgroundAndWaitForUnlock(int userId) {
-        final ProgressWaiter waiter = new ProgressWaiter();
-        boolean success = false;
         try {
-            mIam.startUserInBackgroundWithListener(userId, waiter);
-            success = waiter.waitForFinish(TIMEOUT_IN_SECOND);
-        } catch (RemoteException e) {
-            Log.e(TAG, "startUserInBackgroundAndWaitForUnlock failed", e);
+            attestTrue("Failed to start user " + userId + " in background.",
+                    ShellHelper.runShellCommandWithTimeout("am start-user -w " + userId,
+                            TIMEOUT_IN_SECOND).startsWith("Success:"));
+        } catch (TimeoutException e) {
+            fail("Could not start user " + userId + " in " + TIMEOUT_IN_SECOND + " seconds");
         }
-        attestTrue("Failed to start user " + userId + " in background.", success);
     }
 
     /** Starts the given user in the foreground. */
@@ -1389,14 +1385,20 @@
      * Launches the given package in the given user.
      * Make sure the keyguard has been dismissed prior to calling.
      */
-    private void startApp(int userId, String packageName) throws RemoteException {
-        final Context context = InstrumentationRegistry.getContext();
-        final WaitResult result = ActivityTaskManager.getService().startActivityAndWait(null,
-                context.getPackageName(), context.getAttributionTag(),
-                context.getPackageManager().getLaunchIntentForPackage(packageName), null, null,
-                null, 0, 0, null, null, userId);
-        attestTrue("User " + userId + " failed to start " + packageName,
-                result.result == ActivityManager.START_SUCCESS);
+    private void startApp(int userId, String packageName) {
+        final String failMessage = "User " + userId + " failed to start " + packageName;
+        final String component = InstrumentationRegistry.getContext().getPackageManager()
+                .getLaunchIntentForPackage(packageName).getComponent().flattenToShortString();
+        try {
+            final String result = ShellHelper.runShellCommandWithTimeout(
+                    "am start -W -n " + component + " --user " + userId, TIMEOUT_IN_SECOND);
+            assertTrue(failMessage + ", component=" + component + ", result=" + result,
+                    result.contains("Status: ok")
+                    && !result.contains("Warning:")
+                    && !result.contains("Error:"));
+        } catch (TimeoutException e) {
+            fail(failMessage + " in " + TIMEOUT_IN_SECOND + " seconds");
+        }
     }
 
     private class ProgressWaiter extends IProgressListener.Stub {
@@ -1471,17 +1473,11 @@
     private void removeUser(int userId) throws RemoteException {
         stopUserAfterWaitingForBroadcastIdle(userId, true);
         try {
-            mUm.removeUser(userId);
-            final long startTime = System.currentTimeMillis();
-            final long timeoutInMs = TIMEOUT_IN_SECOND * 1000;
-            while (mUm.getUserInfo(userId) != null &&
-                    System.currentTimeMillis() - startTime < timeoutInMs) {
-                TimeUnit.MILLISECONDS.sleep(CHECK_USER_REMOVED_INTERVAL_MS);
-            }
-        } catch (InterruptedException e) {
-            Thread.currentThread().interrupt();
-        } catch (Exception e) {
-            // Ignore
+            ShellHelper.runShellCommandWithTimeout("pm remove-user -w " + userId,
+                    TIMEOUT_IN_SECOND);
+        } catch (TimeoutException e) {
+            Log.e(TAG, String.format("Could not remove user %d in %d seconds",
+                    userId, TIMEOUT_IN_SECOND), e);
         }
         if (mUm.getUserInfo(userId) != null) {
             mUsersToRemove.add(userId);
@@ -1544,7 +1540,11 @@
     }
 
     private void waitForBroadcastIdle() {
-        ShellHelper.runShellCommand("am wait-for-broadcast-idle");
+        try {
+            ShellHelper.runShellCommandWithTimeout("am wait-for-broadcast-idle", TIMEOUT_IN_SECOND);
+        } catch (TimeoutException e) {
+            Log.e(TAG, "Ending waitForBroadcastIdle because it is taking too long", e);
+        }
     }
 
     private void sleep(long ms) {
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/ShellHelper.java b/apct-tests/perftests/utils/src/android/perftests/utils/ShellHelper.java
index 7b52576..a35899a 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/ShellHelper.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/ShellHelper.java
@@ -24,6 +24,10 @@
 import androidx.test.InstrumentationRegistry;
 
 import java.io.FileInputStream;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * Provides Shell-based utilities such as running a command.
@@ -31,6 +35,43 @@
 public final class ShellHelper {
 
     /**
+     * Runs a Shell command with a timeout, returning a trimmed response.
+     */
+    @NonNull
+    public static String runShellCommandWithTimeout(@NonNull String command, long timeoutInSecond)
+            throws TimeoutException {
+        AtomicReference<Exception> exception = new AtomicReference<>(null);
+        AtomicReference<String> result = new AtomicReference<>(null);
+
+        CountDownLatch latch = new CountDownLatch(1);
+
+        new Thread(() -> {
+            try {
+                result.set(runShellCommandRaw(command));
+            } catch (Exception e) {
+                exception.set(e);
+            } finally {
+                latch.countDown();
+            }
+        }).start();
+
+        try {
+            if (!latch.await(timeoutInSecond, TimeUnit.SECONDS)) {
+                throw new TimeoutException("Command: '" + command + "' could not run in "
+                        + timeoutInSecond + " seconds");
+            }
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+        }
+
+        if (exception.get() != null) {
+            throw new AndroidRuntimeException(exception.get());
+        }
+
+        return result.get();
+    }
+
+    /**
      * Runs a Shell command, returning a trimmed response.
      */
     @NonNull
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java b/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java
index 430a1e2..4d646de 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java
@@ -292,6 +292,10 @@
                 return "permission";
             case EXACT_ALLOW_REASON_POLICY_PERMISSION:
                 return "policy_permission";
+            case EXACT_ALLOW_REASON_LISTENER:
+                return "listener";
+            case EXACT_ALLOW_REASON_PRIORITIZED:
+                return "prioritized";
             case EXACT_ALLOW_REASON_NOT_APPLICABLE:
                 return "N/A";
             default:
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index ae63816..332c53c 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -536,6 +536,12 @@
     field @NonNull public static final android.app.admin.DeviceAdminAuthority DEVICE_ADMIN_AUTHORITY;
   }
 
+  public final class DevicePolicyIdentifiers {
+    field public static final String PERMITTED_INPUT_METHODS_POLICY = "permittedInputMethods";
+    field public static final String PERSONAL_APPS_SUSPENDED_POLICY = "personalAppsSuspended";
+    field public static final String SCREEN_CAPTURE_DISABLED_POLICY = "screenCaptureDisabled";
+  }
+
   public class DevicePolicyManager {
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public void acknowledgeNewUserDisclaimer();
     method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void calculateHasIncompatibleAccounts();
@@ -3783,6 +3789,7 @@
     method @NonNull @RequiresPermission(value=android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional=true) public java.util.List<android.view.inputmethod.InputMethodInfo> getInputMethodListAsUser(int);
     method public boolean hasActiveInputConnection(@Nullable android.view.View);
     method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public boolean hasPendingImeVisibilityRequests();
+    method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public boolean isCurrentRootView(@NonNull android.view.View);
     method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public boolean isInputMethodPickerShown();
     method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public void setStylusWindowIdleTimeoutForTest(long);
     field public static final long CLEAR_SHOW_FORCED_FLAG_WHEN_LEAVING = 214016041L; // 0xcc1a029L
diff --git a/core/java/android/app/admin/DevicePolicyCache.java b/core/java/android/app/admin/DevicePolicyCache.java
index b6e83c8..29f657e 100644
--- a/core/java/android/app/admin/DevicePolicyCache.java
+++ b/core/java/android/app/admin/DevicePolicyCache.java
@@ -19,8 +19,8 @@
 
 import com.android.server.LocalServices;
 
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Collections;
+import java.util.Map;
 
 /**
  * Stores a copy of the set of device policies maintained by {@link DevicePolicyManager} that
@@ -64,10 +64,11 @@
     public abstract boolean canAdminGrantSensorsPermissions();
 
     /**
-     * Returns a list of package names for which all launcher shortcuts should be modified to be
-     * launched in the managed profile and badged accordingly.
+     * Returns a map of package names to package names, for which all launcher shortcuts which
+     * match a key package name should be modified to launch the corresponding value package
+     * name in the managed profile. The overridden shortcut should be badged accordingly.
      */
-    public abstract List<String> getLauncherShortcutOverrides();
+    public abstract Map<String, String> getLauncherShortcutOverrides();
 
     /**
      * Empty implementation.
@@ -95,8 +96,8 @@
             return false;
         }
         @Override
-        public List<String> getLauncherShortcutOverrides() {
-            return new ArrayList<>();
+        public Map<String, String>  getLauncherShortcutOverrides() {
+            return Collections.EMPTY_MAP;
         }
     }
 }
diff --git a/core/java/android/app/admin/DevicePolicyIdentifiers.java b/core/java/android/app/admin/DevicePolicyIdentifiers.java
index 9b0a70d..aeac59b 100644
--- a/core/java/android/app/admin/DevicePolicyIdentifiers.java
+++ b/core/java/android/app/admin/DevicePolicyIdentifiers.java
@@ -17,6 +17,7 @@
 package android.app.admin;
 
 import android.annotation.NonNull;
+import android.annotation.TestApi;
 import android.os.UserManager;
 
 import java.util.Objects;
@@ -118,6 +119,7 @@
      *
      * @hide
      */
+    @TestApi
     public static final String PERMITTED_INPUT_METHODS_POLICY = "permittedInputMethods";
 
     /**
@@ -125,6 +127,7 @@
      *
      * @hide
      */
+    @TestApi
     public static final String PERSONAL_APPS_SUSPENDED_POLICY = "personalAppsSuspended";
 
     /**
@@ -132,6 +135,7 @@
      *
      * @hide
      */
+    @TestApi
     public static final String SCREEN_CAPTURE_DISABLED_POLICY = "screenCaptureDisabled";
 
     /**
diff --git a/core/java/android/view/IRemoteAnimationRunner.aidl b/core/java/android/view/IRemoteAnimationRunner.aidl
index 1981c9d..1f64fb8 100644
--- a/core/java/android/view/IRemoteAnimationRunner.aidl
+++ b/core/java/android/view/IRemoteAnimationRunner.aidl
@@ -46,5 +46,5 @@
      * won't have any effect anymore.
      */
     @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
-    void onAnimationCancelled(boolean isKeyguardOccluded);
+    void onAnimationCancelled();
 }
diff --git a/core/java/android/view/ImeFocusController.java b/core/java/android/view/ImeFocusController.java
index 43828d5..9714896 100644
--- a/core/java/android/view/ImeFocusController.java
+++ b/core/java/android/view/ImeFocusController.java
@@ -86,9 +86,12 @@
     void onPreWindowFocus(boolean hasWindowFocus, WindowManager.LayoutParams windowAttribute) {
         mHasImeFocus = WindowManager.LayoutParams.mayUseInputMethod(windowAttribute.flags);
         if (!hasWindowFocus || !mHasImeFocus || isInLocalFocusMode(windowAttribute)) {
-            return;
+            if (!hasWindowFocus) {
+                getImmDelegate().onWindowLostFocus(mViewRootImpl);
+            }
+        } else {
+            getImmDelegate().onPreWindowGainedFocus(mViewRootImpl);
         }
-        getImmDelegate().onPreWindowGainedFocus(mViewRootImpl);
     }
 
     @UiThread
@@ -163,6 +166,7 @@
         void onPreWindowGainedFocus(ViewRootImpl viewRootImpl);
         void onPostWindowGainedFocus(View viewForWindowFocus,
                 @NonNull WindowManager.LayoutParams windowAttribute);
+        void onWindowLostFocus(@NonNull ViewRootImpl viewRootImpl);
         void onViewFocusChanged(@NonNull View view, boolean hasFocus);
         void onScheduledCheckFocus(@NonNull ViewRootImpl viewRootImpl);
         void onViewDetachedFromWindow(View view, ViewRootImpl viewRootImpl);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index c0ac04c..8f20e2d 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -961,12 +961,20 @@
                 }
 
                 sAnrReported = true;
+                // If we're making an in-process call to ActivityManagerService
+                // and the previous binder call on this thread was oneway, the
+                // calling PID will be 0. Clearing the calling identity fixes
+                // this and ensures ActivityManager gets the correct calling
+                // pid.
+                final long identityToken = Binder.clearCallingIdentity();
                 try {
                     ActivityManager.getService().appNotResponding(reason);
                 } catch (RemoteException e) {
                     // We asked the system to crash us, but the system
                     // already crashed. Unfortunately things may be
                     // out of control.
+                } finally {
+                    Binder.restoreCallingIdentity(identityToken);
                 }
             }
         };
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 82cf073..41ef44e 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -482,13 +482,21 @@
     private View mNextServedView;
 
     /**
-     * This is the root view of the overall window that currently has input
-     * method focus.
+     * The latest {@link ViewRootImpl} that has, or most recently had, input method focus.
+     *
+     * <p>This value will be cleared when it becomes inactive and no longer has window focus.
      */
+    @Nullable
     @GuardedBy("mH")
     ViewRootImpl mCurRootView;
 
     /**
+     * Whether the {@link #mCurRootView} currently has window focus.
+     */
+    @GuardedBy("mH")
+    boolean mCurRootViewWindowFocused;
+
+    /**
      * This is set when we are in the process of connecting, to determine
      * when we have actually finished.
      */
@@ -745,6 +753,7 @@
         public void onPreWindowGainedFocus(ViewRootImpl viewRootImpl) {
             synchronized (mH) {
                 setCurrentRootViewLocked(viewRootImpl);
+                mCurRootViewWindowFocused = true;
             }
         }
 
@@ -822,6 +831,17 @@
         }
 
         @Override
+        public void onWindowLostFocus(@NonNull ViewRootImpl viewRootImpl) {
+            synchronized (mH) {
+                if (mCurRootView == viewRootImpl) {
+                    mCurRootViewWindowFocused = false;
+
+                    clearCurRootViewIfNeeded();
+                }
+            }
+        }
+
+        @Override
         public void onViewFocusChanged(@Nullable View view, boolean hasFocus) {
             onViewFocusChangedInternal(view, hasFocus);
         }
@@ -1114,6 +1134,10 @@
                             // Note that finishComposingText() is allowed to run
                             // even when we are not active.
                             mFallbackInputConnection.finishComposingTextFromImm();
+
+                            if (clearCurRootViewIfNeeded()) {
+                                return;
+                            }
                         }
                         // Check focus again in case that "onWindowFocus" is called before
                         // handling this message.
@@ -1756,8 +1780,7 @@
     }
 
     /**
-     * Return true if the given view is the currently active view for the
-     * input method.
+     * Return {@code true} if the given view is the currently active view for the input method.
      */
     public boolean isActive(View view) {
         // Re-dispatch if there is a context mismatch.
@@ -1773,7 +1796,7 @@
     }
 
     /**
-     * Return true if any view is currently active in the input method.
+     * Return {@code true} if any view is currently active for the input method.
      */
     public boolean isActive() {
         checkFocus();
@@ -1783,6 +1806,20 @@
     }
 
     /**
+     * Returns {@code true} if the given view's {@link ViewRootImpl} is the currently active one
+     * for the {@code InputMethodManager}.
+     *
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD)
+    public boolean isCurrentRootView(@NonNull View attachedView) {
+        synchronized (mH) {
+            return mCurRootView == attachedView.getViewRootImpl();
+        }
+    }
+
+    /**
      * Return {@code true} if the currently served view is accepting full text edits.
      * If {@code false}, it has no input connection, so it can only handle raw key events.
      */
@@ -1908,6 +1945,24 @@
         mImeDispatcher.clear();
     }
 
+    /**
+     * Clears the {@link #mCurRootView} if it's no longer window focused and the connection is
+     * no longer active.
+     *
+     * @return {@code} true iff it was cleared.
+     */
+    @GuardedBy("mH")
+    private boolean clearCurRootViewIfNeeded() {
+        if (!mActive && !mCurRootViewWindowFocused) {
+            finishInputLocked();
+            mDelegate.setCurrentRootViewLocked(null);
+
+            return true;
+        }
+
+        return false;
+    }
+
     public void displayCompletions(View view, CompletionInfo[] completions) {
         // Re-dispatch if there is a context mismatch.
         final InputMethodManager fallbackImm = getFallbackInputMethodManagerIfNecessary(view);
diff --git a/core/java/android/view/inputmethod/TextBoundsInfo.java b/core/java/android/view/inputmethod/TextBoundsInfo.java
index d42d94e..d9f59d6 100644
--- a/core/java/android/view/inputmethod/TextBoundsInfo.java
+++ b/core/java/android/view/inputmethod/TextBoundsInfo.java
@@ -1025,6 +1025,7 @@
             mEnd = -1;
             mCharacterBounds = null;
             mCharacterFlags = null;
+            mCharacterBidiLevels = null;
             mLineSegmentFinder = null;
             mWordSegmentFinder = null;
             mGraphemeSegmentFinder = null;
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 7931d1a..2dbff58 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -724,7 +724,10 @@
         }
 
         getPositionListener().addSubscriber(mCursorAnchorInfoNotifier, true);
-        makeBlink();
+        // Call resumeBlink here instead of makeBlink to ensure that if mBlink is not null the
+        // Blink object is uncancelled.  This ensures when a view is removed and added back the
+        // cursor will resume blinking.
+        resumeBlink();
     }
 
     void onDetachedFromWindow() {
@@ -1094,8 +1097,10 @@
     private void resumeBlink() {
         if (mBlink != null) {
             mBlink.uncancel();
-            makeBlink();
         }
+        // Moving makeBlink outside of the null check block ensures that mBlink object gets
+        // instantiated when the view is added to the window if mBlink is still null.
+        makeBlink();
     }
 
     void adjustInputType(boolean password, boolean passwordInputType,
@@ -2921,6 +2926,9 @@
         if (shouldBlink()) {
             mShowCursor = SystemClock.uptimeMillis();
             if (mBlink == null) mBlink = new Blink();
+            // Call uncancel as mBlink could have previously been cancelled and cursor will not
+            // resume blinking unless uncancelled.
+            mBlink.uncancel();
             mTextView.removeCallbacks(mBlink);
             mTextView.postDelayed(mBlink, BLINK);
         } else {
diff --git a/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java b/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java
index 3a8f427..4f9fc39 100644
--- a/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java
+++ b/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java
@@ -32,6 +32,9 @@
 import android.os.Build;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.telecom.TelecomManager;
+import android.telephony.Annotation;
+import android.telephony.TelephonyManager;
 import android.text.ParcelableSpan;
 import android.text.Spanned;
 import android.text.TextUtils;
@@ -204,6 +207,32 @@
     }
 
     /**
+     * Intercepts the {@link AccessibilityService#GLOBAL_ACTION_KEYCODE_HEADSETHOOK} action
+     * by directly interacting with TelecomManager if a call is incoming or in progress.
+     *
+     * <p>
+     * Provided here in shared utils to be used by both the legacy and modern (SysUI)
+     * system action implementations.
+     * </p>
+     *
+     * @return True if the action was propagated to TelecomManager, otherwise false.
+     */
+    public static boolean interceptHeadsetHookForActiveCall(Context context) {
+        final TelecomManager telecomManager = context.getSystemService(TelecomManager.class);
+        @Annotation.CallState final int callState =
+                telecomManager != null ? telecomManager.getCallState()
+                        : TelephonyManager.CALL_STATE_IDLE;
+        if (callState == TelephonyManager.CALL_STATE_RINGING) {
+            telecomManager.acceptRingingCall();
+            return true;
+        } else if (callState == TelephonyManager.CALL_STATE_OFFHOOK) {
+            telecomManager.endCall();
+            return true;
+        }
+        return false;
+    }
+
+    /**
      * Indicates whether the current user has completed setup via the setup wizard.
      * {@link android.provider.Settings.Secure#USER_SETUP_COMPLETE}
      *
diff --git a/core/java/com/android/internal/widget/NotificationActionListLayout.java b/core/java/com/android/internal/widget/NotificationActionListLayout.java
index 302d2e7..a7a69c9 100644
--- a/core/java/com/android/internal/widget/NotificationActionListLayout.java
+++ b/core/java/com/android/internal/widget/NotificationActionListLayout.java
@@ -50,6 +50,8 @@
     private boolean mEmphasizedMode;
     private int mDefaultPaddingBottom;
     private int mDefaultPaddingTop;
+    private int mEmphasizedPaddingTop;
+    private int mEmphasizedPaddingBottom;
     private int mEmphasizedHeight;
     private int mRegularHeight;
     @DimenRes private int mCollapsibleIndentDimen = R.dimen.notification_actions_padding_start;
@@ -322,13 +324,16 @@
     }
 
     private void updateHeights() {
-        int paddingTop = getResources().getDimensionPixelSize(
-                com.android.internal.R.dimen.notification_content_margin);
+        int inset = getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.button_inset_vertical_material);
+        mEmphasizedPaddingTop = getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.notification_content_margin) - inset;
         // same padding on bottom and at end
-        int paddingBottom = getResources().getDimensionPixelSize(
-                com.android.internal.R.dimen.notification_content_margin_end);
-        mEmphasizedHeight = paddingBottom + paddingTop + getResources().getDimensionPixelSize(
-                com.android.internal.R.dimen.notification_action_emphasized_height);
+        mEmphasizedPaddingBottom = getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.notification_content_margin_end) - inset;
+        mEmphasizedHeight = mEmphasizedPaddingTop + mEmphasizedPaddingBottom
+                + getResources().getDimensionPixelSize(
+                        com.android.internal.R.dimen.notification_action_emphasized_height);
         mRegularHeight = getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.notification_action_list_height);
     }
@@ -356,18 +361,10 @@
         mEmphasizedMode = emphasizedMode;
         int height;
         if (emphasizedMode) {
-            int paddingTop = getResources().getDimensionPixelSize(
-                    com.android.internal.R.dimen.notification_content_margin);
-            // same padding on bottom and at end
-            int paddingBottom = getResources().getDimensionPixelSize(
-                    com.android.internal.R.dimen.notification_content_margin_end);
-            int buttonPaddingInternal = getResources().getDimensionPixelSize(
-                    com.android.internal.R.dimen.button_inset_vertical_material);
             setPaddingRelative(getPaddingStart(),
-                    paddingTop - buttonPaddingInternal,
+                    mEmphasizedPaddingTop,
                     getPaddingEnd(),
-                    paddingBottom - buttonPaddingInternal);
-
+                    mEmphasizedPaddingBottom);
             setMinimumHeight(mEmphasizedHeight);
             height = ViewGroup.LayoutParams.WRAP_CONTENT;
         } else {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 31220b4..fefa79f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -8067,16 +8067,6 @@
             </intent-filter>
         </receiver>
 
-        <!-- Broadcast Receiver listen to sufficient verifier requests from Package Manager
-             when install new SDK, to verifier SDK code during installation time
-             and terminate install if SDK not compatible with privacy sandbox restrictions. -->
-        <receiver android:name="com.android.server.sdksandbox.SdkSandboxVerifierReceiver"
-                 android:exported="false">
-            <intent-filter>
-                <action android:name="android.intent.action.PACKAGE_NEEDS_VERIFICATION"/>
-            </intent-filter>
-        </receiver>
-
         <service android:name="android.hardware.location.GeofenceHardwareService"
             android:permission="android.permission.LOCATION_HARDWARE"
             android:exported="false" />
@@ -8204,6 +8194,10 @@
             android:permission="android.permission.BIND_JOB_SERVICE">
         </service>
 
+        <service android:name="com.android.server.healthconnect.backuprestore.BackupRestore$BackupRestoreJobService"
+            android:permission="android.permission.BIND_JOB_SERVICE">
+        </service>
+
         <service android:name="com.android.server.pm.PackageManagerShellCommandDataLoader"
             android:exported="false">
             <intent-filter>
@@ -8228,6 +8222,8 @@
         <service android:name="com.android.server.companion.datatransfer.contextsync.CallMetadataSyncInCallService"
                  android:permission="android.permission.BIND_INCALL_SERVICE"
                  android:exported="true">
+            <meta-data android:name="android.telecom.INCLUDE_SELF_MANAGED_CALLS"
+                       android:value="true" />
             <intent-filter>
                 <action android:name="android.telecom.InCallService"/>
             </intent-filter>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index c5f7ea6..12dad7e 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -558,6 +558,9 @@
          docked if the dock is configured to enable the accelerometer. -->
     <bool name="config_supportAutoRotation">true</bool>
 
+    <!-- If true, allows rotation resolver service to help resolve screen rotation. -->
+    <bool name="config_allowRotationResolver">true</bool>
+
     <!-- If true, the screen can be rotated via the accelerometer in all 4
          rotations as the default behavior. -->
     <bool name="config_allowAllRotations">false</bool>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index b1b1edf..bc0af12 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -257,8 +257,8 @@
     <!-- The margin of the notification action list at the top -->
     <dimen name="notification_action_list_margin_top">0dp</dimen>
 
-    <!-- The visual height of the emphasized notification action -->
-    <dimen name="notification_action_emphasized_height">36dp</dimen>
+    <!-- The overall height of the emphasized notification action -->
+    <dimen name="notification_action_emphasized_height">48dp</dimen>
 
     <!-- The padding of the actions in non-conversation layout. For conversations, the analogous
          value is calculated in ConversationLayout#updateActionListPadding() -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index ae107fd..bb10f7a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1715,6 +1715,7 @@
   <java-symbol type="integer" name="config_motionPredictionOffsetNanos" />
   <java-symbol type="bool" name="config_showNavigationBar" />
   <java-symbol type="bool" name="config_supportAutoRotation" />
+  <java-symbol type="bool" name="config_allowRotationResolver" />
   <java-symbol type="bool" name="config_dockedStackDividerFreeSnapMode" />
   <java-symbol type="dimen" name="docked_stack_divider_thickness" />
   <java-symbol type="dimen" name="docked_stack_divider_insets" />
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/RadioServiceUserControllerTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/RadioServiceUserControllerTest.java
index 3e9e992..516253b 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/RadioServiceUserControllerTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/RadioServiceUserControllerTest.java
@@ -58,7 +58,7 @@
     }
 
     @Test
-    public void isCurrentUser_forCurrentUser_returnsFalse() {
+    public void isCurrentOrSystemUser_forCurrentUser_returnsFalse() {
         when(mUserHandleMock.getIdentifier()).thenReturn(USER_ID_1);
 
         assertWithMessage("Current user")
@@ -66,7 +66,7 @@
     }
 
     @Test
-    public void isCurrentUser_forNonCurrentUser_returnsFalse() {
+    public void isCurrentOrSystemUser_forNonCurrentUser_returnsFalse() {
         when(mUserHandleMock.getIdentifier()).thenReturn(USER_ID_2);
 
         assertWithMessage("Non-current user")
@@ -74,7 +74,8 @@
     }
 
     @Test
-    public void isCurrentUser_forSystemUser_returnsTrue() {
+    public void isCurrentOrSystemUser_forSystemUser_returnsTrue() {
+        when(mUserHandleMock.getIdentifier()).thenReturn(USER_ID_1);
         when(mUserHandleMock.getIdentifier()).thenReturn(UserHandle.USER_SYSTEM);
 
         assertWithMessage("System user")
@@ -82,10 +83,26 @@
     }
 
     @Test
-    public void isCurrentUser_withActivityManagerFails_returnsFalse() {
-        doThrow(new RuntimeException()).when(() -> ActivityManager.getCurrentUser());
+    public void isCurrentOrSystemUser_withActivityManagerFailure_returnsFalse() {
+        when(mUserHandleMock.getIdentifier()).thenReturn(USER_ID_1);
+        doThrow(new RuntimeException()).when(ActivityManager::getCurrentUser);
 
         assertWithMessage("User when activity manager fails")
                 .that(RadioServiceUserController.isCurrentOrSystemUser()).isFalse();
     }
+
+    @Test
+    public void getCurrentUser() {
+        assertWithMessage("Current user")
+                .that(RadioServiceUserController.getCurrentUser()).isEqualTo(USER_ID_1);
+    }
+
+    @Test
+    public void getCurrentUser_withActivityManagerFailure_returnsUserNull() {
+        when(mUserHandleMock.getIdentifier()).thenReturn(USER_ID_1);
+        doThrow(new RuntimeException()).when(ActivityManager::getCurrentUser);
+
+        assertWithMessage("Current user when activity manager fails")
+                .that(RadioServiceUserController.getCurrentUser()).isEqualTo(UserHandle.USER_NULL);
+    }
 }
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java
index 78b5a4a..f85748c 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java
@@ -47,9 +47,11 @@
 import android.hardware.radio.ProgramSelector;
 import android.hardware.radio.RadioManager;
 import android.hardware.radio.RadioTuner;
+import android.os.Binder;
 import android.os.ParcelableException;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
+import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 
@@ -73,6 +75,8 @@
  */
 public final class TunerSessionTest extends ExtendedRadioMockitoTestCase {
 
+    private static final int USER_ID_1 = 11;
+    private static final int USER_ID_2 = 12;
     private static final VerificationWithTimeout CALLBACK_TIMEOUT =
             timeout(/* millis= */ 200);
     private static final int SIGNAL_QUALITY = 90;
@@ -109,7 +113,10 @@
             SIGNAL_QUALITY);
 
     // Mocks
-    @Mock private IBroadcastRadio mBroadcastRadioMock;
+    @Mock
+    private UserHandle mUserHandleMock;
+    @Mock
+    private IBroadcastRadio mBroadcastRadioMock;
     private android.hardware.radio.ITunerCallback[] mAidlTunerCallbackMocks;
 
     // RadioModule under test
@@ -124,14 +131,18 @@
 
     @Override
     protected void initializeSession(StaticMockitoSessionBuilder builder) {
-        builder.spyStatic(RadioServiceUserController.class).spyStatic(CompatChanges.class);
+        builder.spyStatic(RadioServiceUserController.class).spyStatic(CompatChanges.class)
+                .spyStatic(Binder.class);
     }
 
     @Before
     public void setup() throws Exception {
+        when(mUserHandleMock.getIdentifier()).thenReturn(USER_ID_1);
         doReturn(true).when(() -> CompatChanges.isChangeEnabled(
                 eq(ConversionUtils.RADIO_U_VERSION_REQUIRED), anyInt()));
         doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser());
+        doReturn(USER_ID_1).when(() -> RadioServiceUserController.getCurrentUser());
+        doReturn(mUserHandleMock).when(() -> Binder.getCallingUserHandle());
 
         mRadioModule = new RadioModule(mBroadcastRadioMock,
                 AidlTestUtils.makeDefaultModuleProperties());
@@ -421,6 +432,21 @@
     }
 
     @Test
+    public void tune_forSystemUser() throws Exception {
+        when(mUserHandleMock.getIdentifier()).thenReturn(UserHandle.USER_SYSTEM);
+        doReturn(mUserHandleMock).when(() -> Binder.getCallingUserHandle());
+        doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser());
+        ProgramSelector initialSel = AidlTestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]);
+        RadioManager.ProgramInfo tuneInfo =
+                AidlTestUtils.makeProgramInfo(initialSel, SIGNAL_QUALITY);
+        openAidlClients(/* numClients= */ 1);
+
+        mTunerSessions[0].tune(initialSel);
+
+        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onCurrentProgramInfoChanged(tuneInfo);
+    }
+
+    @Test
     public void tune_withUnknownErrorFromHal_fails() throws Exception {
         openAidlClients(/* numClients= */ 1);
         ProgramSelector sel = AidlTestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]);
@@ -1136,6 +1162,19 @@
     }
 
     @Test
+    public void onCurrentProgramInfoChanged_withNoncurrentUser_doesNotInvokeCallback()
+            throws Exception {
+        openAidlClients(1);
+        doReturn(USER_ID_2).when(() -> RadioServiceUserController.getCurrentUser());
+
+        mHalTunerCallback.onCurrentProgramInfoChanged(AidlTestUtils.makeHalProgramInfo(
+                AidlTestUtils.makeHalFmSelector(/* freq= */ 97300), SIGNAL_QUALITY));
+
+        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0))
+                .onCurrentProgramInfoChanged(any());
+    }
+
+    @Test
     public void onAntennaStateChange_forTunerCallback() throws Exception {
         int numSessions = 3;
         openAidlClients(numSessions);
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java
index 3815008..fac9eaa 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java
@@ -46,8 +46,10 @@
 import android.hardware.radio.ProgramSelector;
 import android.hardware.radio.RadioManager;
 import android.hardware.radio.RadioTuner;
+import android.os.Binder;
 import android.os.ParcelableException;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 
@@ -74,6 +76,8 @@
 @RunWith(MockitoJUnitRunner.class)
 public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase {
 
+    private static final int USER_ID_1 = 11;
+    private static final int USER_ID_2 = 12;
     private static final VerificationWithTimeout CALLBACK_TIMEOUT =
             timeout(/* millis= */ 200);
     private static final int SIGNAL_QUALITY = 1;
@@ -94,18 +98,25 @@
     private ProgramInfo mHalCurrentInfo;
     private TunerSession[] mTunerSessions;
 
-    @Mock private IBroadcastRadio mBroadcastRadioMock;
-    @Mock ITunerSession mHalTunerSessionMock;
+    @Mock
+    private UserHandle mUserHandleMock;
+    @Mock
+    private IBroadcastRadio mBroadcastRadioMock;
+    @Mock
+    ITunerSession mHalTunerSessionMock;
     private android.hardware.radio.ITunerCallback[] mAidlTunerCallbackMocks;
 
     @Override
     protected void initializeSession(StaticMockitoSessionBuilder builder) {
-        builder.spyStatic(RadioServiceUserController.class);
+        builder.spyStatic(RadioServiceUserController.class).spyStatic(Binder.class);
     }
 
     @Before
     public void setup() throws Exception {
+        when(mUserHandleMock.getIdentifier()).thenReturn(USER_ID_1);
+        doReturn(mUserHandleMock).when(() -> Binder.getCallingUserHandle());
         doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser());
+        doReturn(USER_ID_1).when(() -> RadioServiceUserController.getCurrentUser());
 
         mRadioModule = new RadioModule(mBroadcastRadioMock,
                 TestUtils.makeDefaultModuleProperties());
@@ -387,6 +398,20 @@
     }
 
     @Test
+    public void tune_forSystemUser() throws Exception {
+        when(mUserHandleMock.getIdentifier()).thenReturn(UserHandle.USER_SYSTEM);
+        doReturn(mUserHandleMock).when(() -> Binder.getCallingUserHandle());
+        doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser());
+        ProgramSelector initialSel = TestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]);
+        RadioManager.ProgramInfo tuneInfo = TestUtils.makeProgramInfo(initialSel, SIGNAL_QUALITY);
+        openAidlClients(/* numClients= */ 1);
+
+        mTunerSessions[0].tune(initialSel);
+
+        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onCurrentProgramInfoChanged(tuneInfo);
+    }
+
+    @Test
     public void step_withDirectionUp() throws Exception {
         long initFreq = AM_FM_FREQUENCY_LIST[1];
         ProgramSelector initialSel = TestUtils.makeFmSelector(initFreq);
@@ -858,6 +883,19 @@
     }
 
     @Test
+    public void onCurrentProgramInfoChanged_withNoncurrentUser_doesNotInvokeCallback()
+            throws Exception {
+        openAidlClients(1);
+        doReturn(USER_ID_2).when(() -> RadioServiceUserController.getCurrentUser());
+
+        mHalTunerCallback.onCurrentProgramInfoChanged(TestUtils.makeHalProgramInfo(
+                TestUtils.makeHalFmSelector(/* freq= */ 97300), SIGNAL_QUALITY));
+
+        verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0))
+                .onCurrentProgramInfoChanged(any());
+    }
+
+    @Test
     public void onConfigFlagUpdated_forTunerCallback() throws Exception {
         int numSessions = 3;
         openAidlClients(numSessions);
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index fb0f3d4..af81957 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -62,7 +62,6 @@
 import android.view.Display;
 import android.view.View;
 
-import androidx.test.filters.FlakyTest;
 import androidx.test.filters.MediumTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.rule.ActivityTestRule;
@@ -616,7 +615,6 @@
     }
 
     @Test
-    @FlakyTest(bugId = 176134235)
     public void testHandleConfigurationChanged_DoesntOverrideActivityConfig() {
         final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
 
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
index b917ac8..d9b73a8 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
@@ -83,10 +83,7 @@
     }
 
     @Override
-    public void onAnimationCancelled(boolean isKeyguardOccluded) {
-        if (TaskFragmentAnimationController.DEBUG) {
-            Log.v(TAG, "onAnimationCancelled: isKeyguardOccluded=" + isKeyguardOccluded);
-        }
+    public void onAnimationCancelled() {
         mHandler.post(this::cancelAnimation);
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityAnimation.java
index 22c9015..edefe9e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityAnimation.java
@@ -404,7 +404,7 @@
         }
 
         @Override
-        public void onAnimationCancelled(boolean isKeyguardOccluded) {
+        public void onAnimationCancelled() {
             finishAnimation();
         }
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomizeActivityAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomizeActivityAnimation.java
index f0c5d8b2..2d6ec75 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomizeActivityAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomizeActivityAnimation.java
@@ -323,7 +323,7 @@
         }
 
         @Override
-        public void onAnimationCancelled(boolean isKeyguardOccluded) {
+        public void onAnimationCancelled() {
             finishAnimation();
         }
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 2afe8ee..b9ff5f0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -282,6 +282,11 @@
     /** Whether the expanded view has been hidden, because we are dragging out a bubble. */
     private boolean mExpandedViewTemporarilyHidden = false;
 
+    /**
+     * Whether the last bubble is being removed when expanded, which impacts the collapse animation.
+     */
+    private boolean mRemovingLastBubbleWhileExpanded = false;
+
     /** Animator for animating the expanded view's alpha (including the TaskView inside it). */
     private final ValueAnimator mExpandedViewAlphaAnimator = ValueAnimator.ofFloat(0f, 1f);
 
@@ -765,7 +770,7 @@
 
                 // Update scrim
                 if (!mScrimAnimating) {
-                    showScrim(true);
+                    showScrim(true, null /* runnable */);
                 }
             }
         }
@@ -880,6 +885,7 @@
 
         final Runnable onBubbleAnimatedOut = () -> {
             if (getBubbleCount() == 0) {
+                mExpandedViewTemporarilyHidden = false;
                 mBubbleController.onAllBubblesAnimatedOut();
             }
         };
@@ -1773,6 +1779,20 @@
         if (DEBUG_BUBBLE_STACK_VIEW) {
             Log.d(TAG, "removeBubble: " + bubble);
         }
+        if (isExpanded() && getBubbleCount() == 1) {
+            mRemovingLastBubbleWhileExpanded = true;
+            // We're expanded while the last bubble is being removed. Let the scrim animate away
+            // and then remove our views (removing the icon view triggers the removal of the
+            // bubble window so do that at the end of the animation so we see the scrim animate).
+            showScrim(false, () -> {
+                mRemovingLastBubbleWhileExpanded = false;
+                bubble.cleanupExpandedView();
+                mBubbleContainer.removeView(bubble.getIconView());
+                bubble.cleanupViews(); // cleans up the icon view
+                updateExpandedView(); // resets state for no expanded bubble
+            });
+            return;
+        }
         // Remove it from the views
         for (int i = 0; i < getBubbleCount(); i++) {
             View v = mBubbleContainer.getChildAt(i);
@@ -2143,7 +2163,7 @@
         mExpandedViewAlphaAnimator.start();
     }
 
-    private void showScrim(boolean show) {
+    private void showScrim(boolean show, Runnable after) {
         AnimatorListenerAdapter listener = new AnimatorListenerAdapter() {
             @Override
             public void onAnimationStart(Animator animation) {
@@ -2153,6 +2173,9 @@
             @Override
             public void onAnimationEnd(Animator animation) {
                 mScrimAnimating = false;
+                if (after != null) {
+                    after.run();
+                }
             }
         };
         if (show) {
@@ -2179,7 +2202,7 @@
         }
         beforeExpandedViewAnimation();
 
-        showScrim(true);
+        showScrim(true, null /* runnable */);
         updateZOrder();
         updateBadges(false /* setBadgeForCollapsedStack */);
         mBubbleContainer.setActiveController(mExpandedAnimationController);
@@ -2303,7 +2326,10 @@
         mIsExpanded = false;
         mIsExpansionAnimating = true;
 
-        showScrim(false);
+        if (!mRemovingLastBubbleWhileExpanded) {
+            // When we remove the last bubble it animates the scrim.
+            showScrim(false, null /* runnable */);
+        }
 
         mBubbleContainer.cancelAllAnimations();
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 2f25511..6432459 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -460,7 +460,7 @@
                 }
             }
             @Override
-            public void onAnimationCancelled(boolean isKeyguardOccluded) {
+            public void onAnimationCancelled() {
                 final WindowContainerTransaction evictWct = new WindowContainerTransaction();
                 mStageCoordinator.prepareEvictInvisibleChildTasks(evictWct);
                 mSyncQueue.queue(evictWct);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 49e8227..4c903f5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -483,7 +483,7 @@
                 }
             }
             @Override
-            public void onAnimationCancelled(boolean isKeyguardOccluded) {
+            public void onAnimationCancelled() {
                 if (isEnteringSplit) {
                     mMainExecutor.execute(() -> exitSplitScreen(
                             mSideStage.getChildCount() == 0 ? mMainStage : mSideStage,
@@ -869,7 +869,7 @@
                         onRemoteAnimationFinished(apps);
                         t.apply();
                         try {
-                            adapter.getRunner().onAnimationCancelled(mKeyguardShowing);
+                            adapter.getRunner().onAnimationCancelled();
                         } catch (RemoteException e) {
                             Slog.e(TAG, "Error starting remote animation", e);
                         }
@@ -1013,11 +1013,11 @@
             }
 
             @Override
-            public void onAnimationCancelled(boolean isKeyguardOccluded) {
+            public void onAnimationCancelled() {
                 onRemoteAnimationFinishedOrCancelled(evictWct);
                 setDividerVisibility(true, null);
                 try {
-                    adapter.getRunner().onAnimationCancelled(isKeyguardOccluded);
+                    adapter.getRunner().onAnimationCancelled();
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Error starting remote animation", e);
                 }
@@ -1038,7 +1038,7 @@
                         onRemoteAnimationFinished(apps);
                         t.apply();
                         try {
-                            adapter.getRunner().onAnimationCancelled(mKeyguardShowing);
+                            adapter.getRunner().onAnimationCancelled();
                         } catch (RemoteException e) {
                             Slog.e(TAG, "Error starting remote animation", e);
                         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/LegacyTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/LegacyTransitions.java
index 61e92f3..61e11e8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/LegacyTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/LegacyTransitions.java
@@ -107,7 +107,7 @@
             }
 
             @Override
-            public void onAnimationCancelled(boolean isKeyguardOccluded) throws RemoteException {
+            public void onAnimationCancelled() throws RemoteException {
                 mCancelled = true;
                 mApps = mWallpapers = mNonApps = null;
                 checkApply();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
index 5b7231c..ef2a511 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
@@ -94,9 +94,11 @@
             @NonNull SurfaceControl.Transaction startTransaction,
             @NonNull SurfaceControl.Transaction finishTransaction,
             @NonNull Transitions.TransitionFinishCallback finishCallback) {
-        if (!Transitions.SHELL_TRANSITIONS_ROTATION && TransitionUtil.hasDisplayChange(info)) {
+        if (!Transitions.SHELL_TRANSITIONS_ROTATION && TransitionUtil.hasDisplayChange(info)
+                && !TransitionUtil.alwaysReportToKeyguard(info)) {
             // Note that if the remote doesn't have permission ACCESS_SURFACE_FLINGER, some
             // operations of the start transaction may be ignored.
+            mRequestedRemotes.remove(transition);
             return false;
         }
         RemoteTransition pendingRemote = mRequestedRemotes.get(transition);
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 5c8791e..a4057b1 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
@@ -650,7 +650,7 @@
                     active.mToken, info, active.mStartT, active.mFinishT);
         }
 
-        if (info.getRootCount() == 0 && !alwaysReportToKeyguard(info)) {
+        if (info.getRootCount() == 0 && !TransitionUtil.alwaysReportToKeyguard(info)) {
             // No root-leashes implies that the transition is empty/no-op, so just do
             // housekeeping and return.
             ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "No transition roots in %s so"
@@ -699,23 +699,6 @@
         return true;
     }
 
-    /**
-     * Some transitions we always need to report to keyguard even if they are empty.
-     * TODO (b/274954192): Remove this once keyguard dispatching moves to Shell.
-     */
-    private static boolean alwaysReportToKeyguard(TransitionInfo info) {
-        // occlusion status of activities can change while screen is off so there will be no
-        // visibility change but we still need keyguardservice to be notified.
-        if (info.getType() == TRANSIT_KEYGUARD_UNOCCLUDE) return true;
-
-        // It's possible for some activities to stop with bad timing (esp. since we can't yet
-        // queue activity transitions initiated by apps) that results in an empty transition for
-        // keyguard going-away. In general, we should should always report Keyguard-going-away.
-        if ((info.getFlags() & TRANSIT_FLAG_KEYGUARD_GOING_AWAY) != 0) return true;
-
-        return false;
-    }
-
     private boolean areTracksIdle() {
         for (int i = 0; i < mTracks.size(); ++i) {
             if (!mTracks.get(i).isIdle()) return false;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java
index ce10291..c5cd2d9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java
@@ -24,7 +24,9 @@
 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
 import static android.view.WindowManager.TRANSIT_CHANGE;
 import static android.view.WindowManager.TRANSIT_CLOSE;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
 import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
+import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
 import static android.view.WindowManager.TRANSIT_OPEN;
 import static android.view.WindowManager.TRANSIT_TO_BACK;
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
@@ -77,6 +79,23 @@
         return false;
     }
 
+    /**
+     * Some transitions we always need to report to keyguard even if they are empty.
+     * TODO (b/274954192): Remove this once keyguard dispatching moves to Shell.
+     */
+    public static boolean alwaysReportToKeyguard(TransitionInfo info) {
+        // occlusion status of activities can change while screen is off so there will be no
+        // visibility change but we still need keyguardservice to be notified.
+        if (info.getType() == TRANSIT_KEYGUARD_UNOCCLUDE) return true;
+
+        // It's possible for some activities to stop with bad timing (esp. since we can't yet
+        // queue activity transitions initiated by apps) that results in an empty transition for
+        // keyguard going-away. In general, we should should always report Keyguard-going-away.
+        if ((info.getFlags() & TRANSIT_FLAG_KEYGUARD_GOING_AWAY) != 0) return true;
+
+        return false;
+    }
+
     /** Returns `true` if `change` is a wallpaper. */
     public static boolean isWallpaper(TransitionInfo.Change change) {
         return (change.getTaskInfo() == null)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index f9fdd83..836efe0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -23,6 +23,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
+import android.content.res.TypedArray;
 import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Region;
@@ -95,7 +96,7 @@
     private int mWindowingPillHeight;
     private int mMoreActionsPillHeight;
     private int mShadowRadius;
-    private int mCornerRadius;
+    private int mMenuCornerRadius;
 
     DesktopModeWindowDecoration(
             Context context,
@@ -182,6 +183,11 @@
         mRelayoutParams.mShadowRadiusId = shadowRadiusID;
         mRelayoutParams.mApplyStartTransactionOnDraw = applyStartTransactionOnDraw;
 
+        final TypedArray ta = mContext.obtainStyledAttributes(
+                new int[]{android.R.attr.dialogCornerRadius});
+        mRelayoutParams.mCornerRadius = ta.getDimensionPixelSize(0, 0);
+        ta.recycle();
+
         relayout(mRelayoutParams, startT, finishT, wct, oldRootView, mResult);
         // After this line, mTaskInfo is up-to-date and should be used instead of taskInfo
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
index e772fc2..ac5ff20 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
@@ -16,6 +16,8 @@
 
 package com.android.wm.shell.windowdecor;
 
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+
 import android.app.ActivityManager.RunningTaskInfo;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -256,13 +258,17 @@
         mTmpColor[0] = (float) Color.red(backgroundColorInt) / 255.f;
         mTmpColor[1] = (float) Color.green(backgroundColorInt) / 255.f;
         mTmpColor[2] = (float) Color.blue(backgroundColorInt) / 255.f;
-        Point taskPosition = mTaskInfo.positionInParent;
+        final Point taskPosition = mTaskInfo.positionInParent;
         startT.setWindowCrop(mTaskSurface, outResult.mWidth, outResult.mHeight)
                 .setShadowRadius(mTaskSurface, shadowRadius)
                 .setColor(mTaskSurface, mTmpColor)
                 .show(mTaskSurface);
         finishT.setPosition(mTaskSurface, taskPosition.x, taskPosition.y)
                 .setWindowCrop(mTaskSurface, outResult.mWidth, outResult.mHeight);
+        if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
+            startT.setCornerRadius(mTaskSurface, params.mCornerRadius);
+            finishT.setCornerRadius(mTaskSurface, params.mCornerRadius);
+        }
 
         if (mCaptionWindowManager == null) {
             // Put caption under a container surface because ViewRootImpl sets the destination frame
@@ -414,6 +420,8 @@
         int mCaptionWidthId;
         int mShadowRadiusId;
 
+        int mCornerRadius;
+
         int mCaptionX;
         int mCaptionY;
 
@@ -425,6 +433,8 @@
             mCaptionWidthId = Resources.ID_NULL;
             mShadowRadiusId = Resources.ID_NULL;
 
+            mCornerRadius = 0;
+
             mCaptionX = 0;
             mCaptionY = 0;
 
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt
index c5ee7b7..86edc25 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt
@@ -18,7 +18,7 @@
 
 import android.app.Instrumentation
 import android.platform.test.annotations.Presubmit
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.junit.FlickerBuilderProvider
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
index 45024f3..798cc95 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
@@ -20,9 +20,9 @@
 
 import android.tools.common.Rotation
 import android.tools.common.datatypes.Region
-import android.tools.common.datatypes.component.IComponentMatcher
 import android.tools.common.flicker.subject.layers.LayerTraceEntrySubject
 import android.tools.common.flicker.subject.layers.LayersTraceSubject
+import android.tools.common.traces.component.IComponentMatcher
 import android.tools.device.flicker.legacy.FlickerTest
 import android.tools.device.helpers.WindowUtils
 
@@ -218,11 +218,11 @@
     assertLayers {
         if (landscapePosLeft) {
             splitAppLayerBoundsSnapToDivider(
-                    component,
-                    landscapePosLeft,
-                    portraitPosTop,
-                    scenario.endRotation
-                )
+                component,
+                landscapePosLeft,
+                portraitPosTop,
+                scenario.endRotation
+            )
         } else {
             splitAppLayerBoundsSnapToDivider(
                     component,
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt
index 983640a..3bc1e2a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt
@@ -18,7 +18,7 @@
 
 package com.android.wm.shell.flicker
 
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 
 const val SYSTEM_UI_PACKAGE_NAME = "com.android.systemui"
 const val LAUNCHER_UI_PACKAGE_NAME = "com.google.android.apps.nexuslauncher"
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
index d01a0ee..11c5951 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
@@ -20,11 +20,11 @@
 import android.system.helpers.CommandsHelper
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
-import com.android.wm.shell.flicker.BaseTest
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.helpers.LetterboxAppHelper
 import android.tools.device.flicker.legacy.FlickerTestFactory
 import android.tools.device.flicker.legacy.IFlickerTestData
+import com.android.server.wm.flicker.helpers.LetterboxAppHelper
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.wm.shell.flicker.BaseTest
 import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
 import com.android.wm.shell.flicker.appWindowIsVisibleAtStart
 import org.junit.Assume
@@ -104,8 +104,8 @@
         /**
          * Creates the test configurations.
          *
-         * See [FlickerTestFactory.rotationTests] for configuring screen orientation and
-         * navigation modes.
+         * See [FlickerTestFactory.rotationTests] for configuring screen orientation and navigation
+         * modes.
          */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
index c57100e..f212a4e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
@@ -17,11 +17,11 @@
 package com.android.wm.shell.flicker.appcompat
 
 import android.platform.test.annotations.Postsubmit
-import androidx.test.filters.RequiresDevice
+import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import androidx.test.filters.RequiresDevice
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
@@ -35,13 +35,13 @@
  * ```
  *     Rotate non resizable portrait only app to opposite orientation to trigger size compat mode
  * ```
+ *
  * Notes:
  * ```
  *     Some default assertions (e.g., nav bar, status bar and screen covered)
  *     are inherited [BaseTest]
  * ```
  */
-
 @RequiresDevice
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@@ -86,4 +86,4 @@
                 .isInvisible(ComponentNameMatcher.ROTATION)
         }
     }
-}
\ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
index f111a8d..8e75439 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
@@ -17,11 +17,11 @@
 package com.android.wm.shell.flicker.appcompat
 
 import android.platform.test.annotations.Postsubmit
-import androidx.test.filters.RequiresDevice
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.helpers.WindowUtils
+import androidx.test.filters.RequiresDevice
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
@@ -36,13 +36,13 @@
  *     Rotate app to opposite orientation to trigger size compat mode
  *     Press restart button and wait for letterboxed app to resize
  * ```
+ *
  * Notes:
  * ```
  *     Some default assertions (e.g., nav bar, status bar and screen covered)
  *     are inherited [BaseTest]
  * ```
  */
-
 @RequiresDevice
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@@ -56,9 +56,7 @@
             teardown { letterboxApp.exit(wmHelper) }
         }
 
-    @Postsubmit
-    @Test
-    fun appVisibleAtStartAndEnd() = assertLetterboxAppVisibleAtStartAndEnd()
+    @Postsubmit @Test fun appVisibleAtStartAndEnd() = assertLetterboxAppVisibleAtStartAndEnd()
 
     @Postsubmit
     @Test
@@ -83,4 +81,4 @@
         val displayBounds = WindowUtils.getDisplayBounds(flicker.scenario.endRotation)
         flicker.assertLayersEnd { visibleRegion(letterboxApp).coversAtMost(displayBounds) }
     }
-}
\ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt
index 18a3aa7..889e177 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.Postsubmit
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
@@ -149,9 +149,7 @@
     @Ignore("Not applicable to this CUJ. Taskbar is not shown on lock screen")
     override fun taskBarWindowIsAlwaysVisible() {}
 
-    /**
-     * Checks that the [ComponentNameMatcher.TASK_BAR] is visible at the end of the transition
-     */
+    /** Checks that the [ComponentNameMatcher.TASK_BAR] is visible at the end of the transition */
     @Postsubmit
     @Test
     fun taskBarLayerIsVisibleAtEnd() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt
index 59918fb..e6544c9 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt
@@ -17,7 +17,7 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipTransition.kt
index 36c6f7c..2417c45 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ClosePipTransition.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.Presubmit
 import android.tools.common.Rotation
-import android.tools.common.datatypes.component.ComponentNameMatcher.Companion.LAUNCHER
+import android.tools.common.traces.component.ComponentNameMatcher.Companion.LAUNCHER
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
 import android.tools.device.flicker.legacy.FlickerTestFactory
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
index db18edb..4b461370 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
@@ -21,7 +21,7 @@
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import android.tools.common.Rotation
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTransition.kt
index 51f0136..bfd5778 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTransition.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.Presubmit
 import android.tools.common.Rotation
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
 import android.tools.device.flicker.legacy.FlickerTestFactory
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt
index 2001f48..5ac9829 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.Presubmit
 import android.tools.common.Rotation
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.legacy.FlickerTest
 import android.tools.device.flicker.legacy.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
index 6deba1b..bbb1c6c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.Presubmit
 import android.tools.common.Rotation
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt
index a626713..6b061bbb 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.Presubmit
 import android.tools.common.Rotation
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
index b30f308..eb1245b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
@@ -20,7 +20,7 @@
 import android.content.Intent
 import android.platform.test.annotations.Presubmit
 import android.tools.common.Rotation
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
 import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
index 0c9c161..d53eac0 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
@@ -19,8 +19,8 @@
 import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.IwTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.datatypes.component.ComponentNameMatcher
-import android.tools.common.datatypes.component.EdgeExtensionComponentMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.common.traces.component.EdgeExtensionComponentMatcher
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenUtils.kt
index 625987a..1063dfd 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenUtils.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenUtils.kt
@@ -19,9 +19,9 @@
 import android.app.Instrumentation
 import android.graphics.Point
 import android.os.SystemClock
-import android.tools.common.datatypes.component.ComponentNameMatcher
-import android.tools.common.datatypes.component.IComponentMatcher
-import android.tools.common.datatypes.component.IComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.common.traces.component.IComponentMatcher
+import android.tools.common.traces.component.IComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
 import android.tools.device.traces.parsers.WindowManagerStateHelper
 import android.tools.device.traces.parsers.toFlickerComponent
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
index fc4bfd97..5a2326b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
@@ -16,6 +16,8 @@
 
 package com.android.wm.shell.windowdecor;
 
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+
 import static com.android.wm.shell.MockSurfaceControlHelper.createMockSurfaceControlBuilder;
 import static com.android.wm.shell.MockSurfaceControlHelper.createMockSurfaceControlTransaction;
 
@@ -86,6 +88,7 @@
 public class WindowDecorationTests extends ShellTestCase {
     private static final Rect TASK_BOUNDS = new Rect(100, 300, 400, 400);
     private static final Point TASK_POSITION_IN_PARENT = new Point(40, 60);
+    private static final int CORNER_RADIUS = 20;
 
     private final WindowDecoration.RelayoutResult<TestView> mRelayoutResult =
             new WindowDecoration.RelayoutResult<>();
@@ -130,6 +133,7 @@
         mCaptionMenuShadowRadiusId = R.dimen.test_caption_menu_shadow_radius;
         mCaptionMenuCornerRadiusId = R.dimen.test_caption_menu_corner_radius;
         mRelayoutParams.mShadowRadiusId = R.dimen.test_window_decor_shadow_radius;
+        mRelayoutParams.mCornerRadius = CORNER_RADIUS;
 
         doReturn(mMockSurfaceControlViewHost).when(mMockSurfaceControlViewHostFactory)
                 .create(any(), any(), any());
@@ -209,6 +213,7 @@
                 .setBounds(TASK_BOUNDS)
                 .setPositionInParent(TASK_POSITION_IN_PARENT.x, TASK_POSITION_IN_PARENT.y)
                 .setVisible(true)
+                .setWindowingMode(WINDOWING_MODE_FREEFORM)
                 .build();
         taskInfo.isFocused = true;
         // Density is 2. Shadow radius is 10px. Caption height is 64px.
@@ -249,6 +254,8 @@
                 .setPosition(taskSurface, TASK_POSITION_IN_PARENT.x, TASK_POSITION_IN_PARENT.y);
         verify(mMockSurfaceControlFinishT)
                 .setWindowCrop(taskSurface, 300, 100);
+        verify(mMockSurfaceControlStartT).setCornerRadius(taskSurface, CORNER_RADIUS);
+        verify(mMockSurfaceControlFinishT).setCornerRadius(taskSurface, CORNER_RADIUS);
         verify(mMockSurfaceControlStartT)
                 .show(taskSurface);
         verify(mMockSurfaceControlStartT)
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 193544e..88b9643 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -934,13 +934,25 @@
                     }
                 }
                 levelCaps = createFromProfileLevel(mMime, profile, maxLevel);
-                // remove profile from this format otherwise levelCaps.isFormatSupported will
-                // get into this same conditon and loop forever.
-                Map<String, Object> mapWithoutProfile = new HashMap<>(map);
-                mapWithoutProfile.remove(MediaFormat.KEY_PROFILE);
-                MediaFormat formatWithoutProfile = new MediaFormat(mapWithoutProfile);
-                if (levelCaps != null && !levelCaps.isFormatSupported(formatWithoutProfile)) {
-                    return false;
+                // We must remove the profile from this format otherwise levelCaps.isFormatSupported
+                // will get into this same condition and loop forever. Furthermore, since levelCaps
+                // does not contain features and bitrate specific keys, keep only keys relevant for
+                // a level check.
+                Map<String, Object> levelCriticalFormatMap = new HashMap<>(map);
+                final Set<String> criticalKeys =
+                    isVideo() ? VideoCapabilities.VIDEO_LEVEL_CRITICAL_FORMAT_KEYS :
+                    isAudio() ? AudioCapabilities.AUDIO_LEVEL_CRITICAL_FORMAT_KEYS :
+                    null;
+
+                // critical keys will always contain KEY_MIME, but should also contain others to be
+                // meaningful
+                if (criticalKeys != null && criticalKeys.size() > 1 && levelCaps != null) {
+                    levelCriticalFormatMap.keySet().retainAll(criticalKeys);
+
+                    MediaFormat levelCriticalFormat = new MediaFormat(levelCriticalFormatMap);
+                    if (!levelCaps.isFormatSupported(levelCriticalFormat)) {
+                        return false;
+                    }
                 }
             }
             if (mAudioCaps != null && !mAudioCaps.supportsFormat(format)) {
@@ -1633,6 +1645,16 @@
             }
         }
 
+        /* package private */
+        // must not contain KEY_PROFILE
+        static final Set<String> AUDIO_LEVEL_CRITICAL_FORMAT_KEYS = Set.of(
+                // We don't set level-specific limits for audio codecs today. Key candidates would
+                // be sample rate, bit rate or channel count.
+                // MediaFormat.KEY_SAMPLE_RATE,
+                // MediaFormat.KEY_CHANNEL_COUNT,
+                // MediaFormat.KEY_BIT_RATE,
+                MediaFormat.KEY_MIME);
+
         /** @hide */
         public boolean supportsFormat(MediaFormat format) {
             Map<String, Object> map = format.getMap();
@@ -2357,6 +2379,15 @@
             return ok;
         }
 
+        /* package private */
+        // must not contain KEY_PROFILE
+        static final Set<String> VIDEO_LEVEL_CRITICAL_FORMAT_KEYS = Set.of(
+                MediaFormat.KEY_WIDTH,
+                MediaFormat.KEY_HEIGHT,
+                MediaFormat.KEY_FRAME_RATE,
+                MediaFormat.KEY_BIT_RATE,
+                MediaFormat.KEY_MIME);
+
         /**
          * @hide
          * @throws java.lang.ClassCastException */
diff --git a/media/java/android/media/soundtrigger/SoundTriggerManager.java b/media/java/android/media/soundtrigger/SoundTriggerManager.java
index b6d70af..78352871 100644
--- a/media/java/android/media/soundtrigger/SoundTriggerManager.java
+++ b/media/java/android/media/soundtrigger/SoundTriggerManager.java
@@ -54,7 +54,6 @@
 
 import com.android.internal.app.ISoundTriggerService;
 import com.android.internal.app.ISoundTriggerSession;
-import com.android.internal.util.Preconditions;
 
 import java.util.HashMap;
 import java.util.List;
@@ -67,6 +66,8 @@
  * models. Usage of this class is restricted to system or signature applications only. This allows
  * OEMs to write apps that can manage non-voice based sound trigger models.
  *
+ * If no ST module is available, {@link getModuleProperties()} will return {@code null}, and all
+ * other methods will throw {@link IllegalStateException}.
  * @hide
  */
 @SystemApi
@@ -82,7 +83,7 @@
 
     // Stores a mapping from the sound model UUID to the SoundTriggerInstance created by
     // the createSoundTriggerDetector() call.
-    private final HashMap<UUID, SoundTriggerDetector> mReceiverInstanceMap;
+    private final HashMap<UUID, SoundTriggerDetector> mReceiverInstanceMap = new HashMap<>();
 
     /**
      * @hide
@@ -121,7 +122,6 @@
         }
         mContext = context;
         mSoundTriggerService = soundTriggerService;
-        mReceiverInstanceMap = new HashMap<UUID, SoundTriggerDetector>();
     }
 
     /**
@@ -160,7 +160,7 @@
                 .findFirst()
                 .orElse(null);
         if (moduleProps == null) {
-            throw new IllegalStateException("Fake ST HAL should always be available");
+            throw new AssertionError("Fake ST HAL should always be available");
         }
         return moduleProps;
     }
@@ -183,7 +183,6 @@
         }
         mContext = Objects.requireNonNull(context);
         mSoundTriggerService = Objects.requireNonNull(soundTriggerService);
-        mReceiverInstanceMap = new HashMap<UUID, SoundTriggerDetector>();
     }
 
     /**
@@ -241,7 +240,8 @@
         }
         try {
             GenericSoundModel model =
-                    mSoundTriggerSession.getSoundModel(new ParcelUuid(soundModelId));
+                    mSoundTriggerSession.getSoundModel(
+                            new ParcelUuid(Objects.requireNonNull(soundModelId)));
             if (model == null) {
                 return null;
             }
@@ -265,7 +265,8 @@
         }
 
         try {
-            mSoundTriggerSession.deleteSoundModel(new ParcelUuid(soundModelId));
+            mSoundTriggerSession.deleteSoundModel(
+                    new ParcelUuid(Objects.requireNonNull(soundModelId)));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -291,8 +292,8 @@
     @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
     public SoundTriggerDetector createSoundTriggerDetector(UUID soundModelId,
             @NonNull SoundTriggerDetector.Callback callback, @Nullable Handler handler) {
-        if (soundModelId == null || mSoundTriggerSession == null) {
-            return null;
+        if (mSoundTriggerSession == null) {
+            throw new IllegalStateException("No underlying SoundTriggerModule available");
         }
 
         SoundTriggerDetector oldInstance = mReceiverInstanceMap.get(soundModelId);
@@ -301,7 +302,8 @@
         }
         try {
             SoundTriggerDetector newInstance = new SoundTriggerDetector(mSoundTriggerSession,
-                    mSoundTriggerSession.getSoundModel(new ParcelUuid(soundModelId)),
+                    mSoundTriggerSession.getSoundModel(
+                        new ParcelUuid(Objects.requireNonNull(soundModelId))),
                     callback, handler);
             mReceiverInstanceMap.put(soundModelId, newInstance);
             return newInstance;
@@ -469,8 +471,8 @@
     @UnsupportedAppUsage
     @TestApi
     public int loadSoundModel(@NonNull SoundModel soundModel) {
-        if (soundModel == null || mSoundTriggerSession == null) {
-            return STATUS_ERROR;
+        if (mSoundTriggerSession == null) {
+            throw new IllegalStateException("No underlying SoundTriggerModule available");
         }
 
         try {
@@ -513,11 +515,11 @@
     @UnsupportedAppUsage
     public int startRecognition(@NonNull UUID soundModelId, @Nullable Bundle params,
         @NonNull ComponentName detectionService, @NonNull RecognitionConfig config) {
-        Preconditions.checkNotNull(soundModelId);
-        Preconditions.checkNotNull(detectionService);
-        Preconditions.checkNotNull(config);
+        Objects.requireNonNull(soundModelId);
+        Objects.requireNonNull(detectionService);
+        Objects.requireNonNull(config);
         if (mSoundTriggerSession == null) {
-            return STATUS_ERROR;
+            throw new IllegalStateException("No underlying SoundTriggerModule available");
         }
         try {
             return mSoundTriggerSession.startRecognitionForService(new ParcelUuid(soundModelId),
@@ -534,11 +536,12 @@
     @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public int stopRecognition(UUID soundModelId) {
-        if (soundModelId == null || mSoundTriggerSession == null) {
-            return STATUS_ERROR;
+        if (mSoundTriggerSession == null) {
+            throw new IllegalStateException("No underlying SoundTriggerModule available");
         }
         try {
-            return mSoundTriggerSession.stopRecognitionForService(new ParcelUuid(soundModelId));
+            return mSoundTriggerSession.stopRecognitionForService(
+                    new ParcelUuid(Objects.requireNonNull(soundModelId)));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -551,12 +554,12 @@
     @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public int unloadSoundModel(UUID soundModelId) {
-        if (soundModelId == null || mSoundTriggerSession == null) {
-            return STATUS_ERROR;
+        if (mSoundTriggerSession == null) {
+            throw new IllegalStateException("No underlying SoundTriggerModule available");
         }
         try {
             return mSoundTriggerSession.unloadSoundModel(
-                    new ParcelUuid(soundModelId));
+                    new ParcelUuid(Objects.requireNonNull(soundModelId)));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -604,7 +607,10 @@
     @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
     @UnsupportedAppUsage
     public int getModelState(UUID soundModelId) {
-        if (soundModelId == null || mSoundTriggerSession == null) {
+        if (mSoundTriggerSession == null) {
+            throw new IllegalStateException("No underlying SoundTriggerModule available");
+        }
+        if (soundModelId == null) {
             return STATUS_ERROR;
         }
         try {
@@ -652,11 +658,12 @@
     public int setParameter(@Nullable UUID soundModelId,
             @ModelParams int modelParam, int value) {
         if (mSoundTriggerSession == null) {
-            return SoundTrigger.STATUS_INVALID_OPERATION;
+            throw new IllegalStateException("No underlying SoundTriggerModule available");
         }
 
         try {
-            return mSoundTriggerSession.setParameter(new ParcelUuid(soundModelId), modelParam,
+            return mSoundTriggerSession.setParameter(
+                    new ParcelUuid(Objects.requireNonNull(soundModelId)), modelParam,
                     value);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -679,11 +686,11 @@
     public int getParameter(@NonNull UUID soundModelId,
             @ModelParams int modelParam) {
         if (mSoundTriggerSession == null) {
-            throw new IllegalArgumentException("Sound model is not loaded: "
-                            + soundModelId.toString());
+            throw new IllegalStateException("No underlying SoundTriggerModule available");
         }
         try {
-            return mSoundTriggerSession.getParameter(new ParcelUuid(soundModelId), modelParam);
+            return mSoundTriggerSession.getParameter(
+                    new ParcelUuid(Objects.requireNonNull(soundModelId)), modelParam);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -703,10 +710,11 @@
     public ModelParamRange queryParameter(@Nullable UUID soundModelId,
             @ModelParams int modelParam) {
         if (mSoundTriggerSession == null) {
-            return null;
+            throw new IllegalStateException("No underlying SoundTriggerModule available");
         }
         try {
-            return mSoundTriggerSession.queryParameter(new ParcelUuid(soundModelId), modelParam);
+            return mSoundTriggerSession.queryParameter(
+                    new ParcelUuid(Objects.requireNonNull(soundModelId)), modelParam);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 9552200..44aff64 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -385,6 +385,10 @@
 
     process_media_player_call( env, thiz, mp->prepare(), "java/io/IOException", "Prepare failed." );
 
+    if (env->ExceptionCheck()) {
+        return UNKNOWN_ERROR;
+    }
+
     // update the piid
     Parcel *request = parcelForJavaObject(env, piidParcel);
     auto reply = std::make_unique<Parcel>();
@@ -407,6 +411,10 @@
 
     process_media_player_call( env, thiz, mp->prepareAsync(), "java/io/IOException", "Prepare Async failed." );
 
+    if (env->ExceptionCheck()) {
+        return UNKNOWN_ERROR;
+    }
+
     // update the piid
     Parcel *request = parcelForJavaObject(env, piidParcel);
     auto reply = std::make_unique<Parcel>();
diff --git a/packages/CredentialManager/res/values/strings.xml b/packages/CredentialManager/res/values/strings.xml
index 905e0ca..a3b2752 100644
--- a/packages/CredentialManager/res/values/strings.xml
+++ b/packages/CredentialManager/res/values/strings.xml
@@ -114,13 +114,13 @@
   <!-- Strings for the get flow. -->
   <!-- This appears as the title of the modal bottom sheet asking for user confirmation to use the single previously saved passkey to sign in to the app. [CHAR LIMIT=200] -->
   <string name="get_dialog_title_use_passkey_for">Use your saved passkey for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g>?</string>
-  <!-- This appears as the title of the dialog asking for user confirmation to use the single previously saved credential to sign in to the app. [CHAR LIMIT=200] -->
-  <string name="get_dialog_title_use_sign_in_for">Use your saved sign-in for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g>?</string>
-  <!-- This appears as the title of the dialog asking for user to make a choice from various previously saved credentials to sign in to the app. [CHAR LIMIT=200] -->
-  <string name="get_dialog_title_choose_sign_in_for">Choose a saved sign-in for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g></string>
-  <!-- This appears as the title of the dialog asking for user to make a choice from various previously saved credentials to sign in to the app. [CHAR LIMIT=200] -->
+  <!-- This appears as the title of the dialog asking for user confirmation to use the single user credential (previously saved or to be created) to sign in to the app. [CHAR LIMIT=200] -->
+  <string name="get_dialog_title_use_sign_in_for">Use your sign-in for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g>?</string>
+  <!-- This appears as the title of the dialog asking for user to make a choice from various available user credentials (previously saved or to be created) to sign in to the app. [CHAR LIMIT=200] -->
+  <string name="get_dialog_title_choose_sign_in_for">Choose a sign-in for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g></string>
+  <!-- This appears as the title of the dialog asking for user to make a choice from options of available user information (e.g. driver's license, vaccination status) to pass to the app. [CHAR LIMIT=200] -->
   <string name="get_dialog_title_choose_option_for">Choose an option for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g>?</string>
-  <!-- This appears as the title of the dialog asking user to use a previously saved credentials to sign in to the app. [CHAR LIMIT=200] -->
+  <!-- This appears as the title of the dialog asking user to send a piece of user information (e.g. driver's license, vaccination status) to the app. [CHAR LIMIT=200] -->
   <string name="get_dialog_title_use_info_on">Use this info on <xliff:g id="app_name" example="YouTube">%1$s</xliff:g>?</string>
   <!-- This is a label for a button that links the user to different sign-in methods . [CHAR LIMIT=80] -->
   <string name="get_dialog_use_saved_passkey_for">Sign in another way</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
index 45c0d78..adaf4a1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
@@ -14,7 +14,9 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 
+import android.annotation.SuppressLint;
 import android.content.Context;
 import android.content.Intent;
 import android.net.ConnectivityManager;
@@ -26,6 +28,8 @@
 import android.net.NetworkRequest;
 import android.net.NetworkScoreManager;
 import android.net.ScoredNetwork;
+import android.net.TransportInfo;
+import android.net.vcn.VcnTransportInfo;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiNetworkScoreCache;
@@ -34,8 +38,9 @@
 import android.os.Looper;
 import android.provider.Settings;
 
+import androidx.annotation.Nullable;
+
 import com.android.settingslib.R;
-import com.android.settingslib.Utils;
 
 import java.io.PrintWriter;
 import java.text.SimpleDateFormat;
@@ -46,6 +51,7 @@
 /**
  * Track status of Wi-Fi for the Sys UI.
  */
+@SuppressLint("MissingPermission")
 public class WifiStatusTracker {
     private static final int HISTORY_SIZE = 32;
     private static final SimpleDateFormat SSDF = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
@@ -66,8 +72,9 @@
     private final NetworkRequest mNetworkRequest = new NetworkRequest.Builder()
             .clearCapabilities()
             .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
-            .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
-            .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR).build();
+            .addTransportType(TRANSPORT_WIFI)
+            .addTransportType(TRANSPORT_CELLULAR)
+            .build();
     private final NetworkCallback mNetworkCallback =
             new NetworkCallback(NetworkCallback.FLAG_INCLUDE_LOCATION_INFO) {
         // Note: onCapabilitiesChanged is guaranteed to be called "immediately" after onAvailable
@@ -75,18 +82,10 @@
         @Override
         public void onCapabilitiesChanged(
                 Network network, NetworkCapabilities networkCapabilities) {
-            boolean isVcnOverWifi = false;
-            boolean isWifi = false;
-            WifiInfo wifiInfo = null;
-            if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
-                wifiInfo = Utils.tryGetWifiInfoForVcn(networkCapabilities);
-                isVcnOverWifi = (wifiInfo != null);
-            } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
-                wifiInfo = (WifiInfo) networkCapabilities.getTransportInfo();
-                isWifi = true;
-            }
+            WifiInfo wifiInfo = getMainOrUnderlyingWifiInfo(networkCapabilities);
+            boolean isWifi = connectionIsWifi(networkCapabilities, wifiInfo);
             // As long as it is a WiFi network, we will log it in the dumpsys for debugging.
-            if (isVcnOverWifi || isWifi) {
+            if (isWifi) {
                 String log = new StringBuilder()
                         .append(SSDF.format(System.currentTimeMillis())).append(",")
                         .append("onCapabilitiesChanged: ")
@@ -303,17 +302,8 @@
             return;
         }
         NetworkCapabilities networkCapabilities;
-        isDefaultNetwork = false;
-        if (mDefaultNetworkCapabilities != null) {
-            boolean isWifi = mDefaultNetworkCapabilities.hasTransport(
-                    NetworkCapabilities.TRANSPORT_WIFI);
-            boolean isVcnOverWifi = mDefaultNetworkCapabilities.hasTransport(
-                    NetworkCapabilities.TRANSPORT_CELLULAR)
-                            && (Utils.tryGetWifiInfoForVcn(mDefaultNetworkCapabilities) != null);
-            if (isWifi || isVcnOverWifi) {
-                isDefaultNetwork = true;
-            }
-        }
+        isDefaultNetwork = mDefaultNetworkCapabilities != null
+                && connectionIsWifi(mDefaultNetworkCapabilities);
         if (isDefaultNetwork) {
             // Wifi is connected and the default network.
             networkCapabilities = mDefaultNetworkCapabilities;
@@ -352,6 +342,70 @@
                 ? null : AccessPoint.getSpeedLabel(mContext, scoredNetwork, rssi);
     }
 
+    @Nullable
+    private WifiInfo getMainOrUnderlyingWifiInfo(NetworkCapabilities networkCapabilities) {
+        WifiInfo mainWifiInfo = getMainWifiInfo(networkCapabilities);
+        if (mainWifiInfo != null) {
+            return mainWifiInfo;
+        }
+
+        // Only CELLULAR networks may have underlying wifi information that's relevant to SysUI,
+        // so skip the underlying network check if it's not CELLULAR.
+        if (!networkCapabilities.hasTransport(TRANSPORT_CELLULAR)) {
+            return mainWifiInfo;
+        }
+
+        List<Network> underlyingNetworks = networkCapabilities.getUnderlyingNetworks();
+        if (underlyingNetworks == null) {
+            return null;
+        }
+
+        // Some connections, like VPN connections, may have underlying networks that are
+        // eventually traced to a wifi or carrier merged connection. So, check those underlying
+        // networks for possible wifi information as well. See b/225902574.
+        for (Network underlyingNetwork : underlyingNetworks) {
+            NetworkCapabilities underlyingNetworkCapabilities =
+                    mConnectivityManager.getNetworkCapabilities(underlyingNetwork);
+            WifiInfo underlyingWifiInfo = getMainWifiInfo(underlyingNetworkCapabilities);
+            if (underlyingWifiInfo != null) {
+                return underlyingWifiInfo;
+            }
+        }
+
+        return null;
+    }
+
+    @Nullable
+    private WifiInfo getMainWifiInfo(NetworkCapabilities networkCapabilities) {
+        boolean canHaveWifiInfo = networkCapabilities.hasTransport(TRANSPORT_WIFI)
+                || networkCapabilities.hasTransport(TRANSPORT_CELLULAR);
+        if (!canHaveWifiInfo) {
+            return null;
+        }
+
+        TransportInfo transportInfo = networkCapabilities.getTransportInfo();
+        if (transportInfo instanceof VcnTransportInfo) {
+            // This VcnTransportInfo logic is copied from
+            // [com.android.settingslib.Utils.tryGetWifiInfoForVcn]. It's copied instead of
+            // re-used because it makes the logic here clearer.
+            return ((VcnTransportInfo) transportInfo).getWifiInfo();
+        } else if (transportInfo instanceof WifiInfo) {
+            return (WifiInfo) transportInfo;
+        } else {
+            return null;
+        }
+    }
+
+    private boolean connectionIsWifi(NetworkCapabilities networkCapabilities) {
+        return connectionIsWifi(
+                networkCapabilities,
+                getMainOrUnderlyingWifiInfo(networkCapabilities));
+    }
+
+    private boolean connectionIsWifi(NetworkCapabilities networkCapabilities, WifiInfo wifiInfo) {
+        return wifiInfo != null || networkCapabilities.hasTransport(TRANSPORT_WIFI);
+    }
+
     /** Refresh the status label on Locale changed. */
     public void refreshLocale() {
         updateStatusLabel();
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiStatusTrackerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiStatusTrackerTest.java
index dc7e313d..6e975cf 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiStatusTrackerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiStatusTrackerTest.java
@@ -40,6 +40,8 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 
+import java.util.Arrays;
+
 @RunWith(RobolectricTestRunner.class)
 public class WifiStatusTrackerTest {
     @Mock Context mContext;
@@ -48,13 +50,32 @@
     @Mock ConnectivityManager mConnectivityManager;
     @Mock Runnable mCallback;
 
+    private WifiStatusTracker mWifiStatusTracker;
+
     private final ArgumentCaptor<ConnectivityManager.NetworkCallback>
             mNetworkCallbackCaptor =
             ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
 
+    private final ArgumentCaptor<ConnectivityManager.NetworkCallback>
+            mDefaultNetworkCallbackCaptor =
+            ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
+
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
+
+        mWifiStatusTracker = new WifiStatusTracker(
+                mContext,
+                mWifiManager,
+                mNetworkScoreManager,
+                mConnectivityManager,
+                mCallback);
+        mWifiStatusTracker.setListening(true);
+
+        verify(mConnectivityManager)
+                .registerNetworkCallback(any(), mNetworkCallbackCaptor.capture(), any());
+        verify(mConnectivityManager)
+                .registerDefaultNetworkCallback(mDefaultNetworkCallbackCaptor.capture(), any());
     }
 
     /**
@@ -62,13 +83,6 @@
      */
     @Test
     public void testWifiInfoClearedOnPrimaryNetworkLost() {
-        WifiStatusTracker wifiStatusTracker = new WifiStatusTracker(mContext, mWifiManager,
-                mNetworkScoreManager, mConnectivityManager, mCallback);
-        wifiStatusTracker.setListening(true);
-
-        verify(mConnectivityManager)
-                .registerNetworkCallback(any(), mNetworkCallbackCaptor.capture(), any());
-
         // Trigger a validation callback for the primary Wifi network.
         WifiInfo primaryWifiInfo = Mockito.mock(WifiInfo.class);
         when(primaryWifiInfo.makeCopy(anyLong())).thenReturn(primaryWifiInfo);
@@ -86,8 +100,8 @@
         mNetworkCallbackCaptor.getValue().onCapabilitiesChanged(primaryNetwork, primaryCap);
 
         // Verify primary wifi info is the one being used.
-        assertThat(wifiStatusTracker.connected).isTrue();
-        assertThat(wifiStatusTracker.rssi).isEqualTo(primaryRssi);
+        assertThat(mWifiStatusTracker.connected).isTrue();
+        assertThat(mWifiStatusTracker.rssi).isEqualTo(primaryRssi);
 
         // Trigger a validation callback for the non-primary Wifi network.
         WifiInfo nonPrimaryWifiInfo = Mockito.mock(WifiInfo.class);
@@ -106,20 +120,189 @@
         mNetworkCallbackCaptor.getValue().onCapabilitiesChanged(nonPrimaryNetwork, nonPrimaryCap);
 
         // Verify primary wifi info is still the one being used.
-        assertThat(wifiStatusTracker.connected).isTrue();
-        assertThat(wifiStatusTracker.rssi).isEqualTo(primaryRssi);
+        assertThat(mWifiStatusTracker.connected).isTrue();
+        assertThat(mWifiStatusTracker.rssi).isEqualTo(primaryRssi);
 
         // Lose the non-primary network.
         mNetworkCallbackCaptor.getValue().onLost(nonPrimaryNetwork);
 
         // Verify primary wifi info is still the one being used.
-        assertThat(wifiStatusTracker.connected).isTrue();
-        assertThat(wifiStatusTracker.rssi).isEqualTo(primaryRssi);
+        assertThat(mWifiStatusTracker.connected).isTrue();
+        assertThat(mWifiStatusTracker.rssi).isEqualTo(primaryRssi);
 
         // Lose the primary network.
         mNetworkCallbackCaptor.getValue().onLost(primaryNetwork);
 
         // Verify we aren't connected anymore.
-        assertThat(wifiStatusTracker.connected).isFalse();
+        assertThat(mWifiStatusTracker.connected).isFalse();
+    }
+
+    @Test
+    public void isCarrierMerged_typicalWifi_false() {
+        WifiInfo primaryWifiInfo = Mockito.mock(WifiInfo.class);
+        when(primaryWifiInfo.isPrimary()).thenReturn(true);
+
+        NetworkCapabilities primaryCap = Mockito.mock(NetworkCapabilities.class);
+        when(primaryCap.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)).thenReturn(true);
+        when(primaryCap.getTransportInfo()).thenReturn(primaryWifiInfo);
+
+        Network primaryNetwork = Mockito.mock(Network.class);
+        int primaryNetworkId = 1;
+        when(primaryNetwork.getNetId()).thenReturn(primaryNetworkId);
+
+        mNetworkCallbackCaptor.getValue().onCapabilitiesChanged(primaryNetwork, primaryCap);
+
+        assertThat(mWifiStatusTracker.isCarrierMerged).isFalse();
+    }
+
+    @Test
+    public void isCarrierMerged_typicalCellular_false() {
+        NetworkCapabilities primaryCap = Mockito.mock(NetworkCapabilities.class);
+        when(primaryCap.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)).thenReturn(true);
+
+        Network primaryNetwork = Mockito.mock(Network.class);
+        int primaryNetworkId = 1;
+        when(primaryNetwork.getNetId()).thenReturn(primaryNetworkId);
+
+        mNetworkCallbackCaptor.getValue().onCapabilitiesChanged(primaryNetwork, primaryCap);
+
+        assertThat(mWifiStatusTracker.isCarrierMerged).isFalse();
+    }
+
+    @Test
+    public void isCarrierMerged_cellularCarrierMergedWifi_true() {
+        WifiInfo primaryWifiInfo = Mockito.mock(WifiInfo.class);
+        when(primaryWifiInfo.isPrimary()).thenReturn(true);
+        when(primaryWifiInfo.isCarrierMerged()).thenReturn(true);
+
+        NetworkCapabilities primaryCap = Mockito.mock(NetworkCapabilities.class);
+        when(primaryCap.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)).thenReturn(true);
+        when(primaryCap.getTransportInfo()).thenReturn(primaryWifiInfo);
+
+        Network primaryNetwork = Mockito.mock(Network.class);
+        int primaryNetworkId = 1;
+        when(primaryNetwork.getNetId()).thenReturn(primaryNetworkId);
+
+        mNetworkCallbackCaptor.getValue().onCapabilitiesChanged(primaryNetwork, primaryCap);
+
+        assertThat(mWifiStatusTracker.isCarrierMerged).isTrue();
+    }
+
+    /** Test for b/225902574. */
+    @Test
+    public void isCarrierMerged_cellularWithUnderlyingCarrierMergedWifi_true() {
+        WifiInfo underlyingCarrierMergedInfo = Mockito.mock(WifiInfo.class);
+        when(underlyingCarrierMergedInfo.isPrimary()).thenReturn(true);
+        when(underlyingCarrierMergedInfo.isCarrierMerged()).thenReturn(true);
+
+        NetworkCapabilities underlyingNetworkCapabilities = Mockito.mock(NetworkCapabilities.class);
+        when(underlyingNetworkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR))
+                .thenReturn(true);
+        when(underlyingNetworkCapabilities.getTransportInfo())
+                .thenReturn(underlyingCarrierMergedInfo);
+
+        Network underlyingNetwork = Mockito.mock(Network.class);
+        when(mConnectivityManager.getNetworkCapabilities(underlyingNetwork))
+                .thenReturn(underlyingNetworkCapabilities);
+
+        NetworkCapabilities mainCapabilities = Mockito.mock(NetworkCapabilities.class);
+        when(mainCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR))
+                .thenReturn(true);
+        when(mainCapabilities.getTransportInfo()).thenReturn(null);
+        when(mainCapabilities.getUnderlyingNetworks())
+                .thenReturn(Arrays.asList(underlyingNetwork));
+
+        Network primaryNetwork = Mockito.mock(Network.class);
+        int primaryNetworkId = 1;
+        when(primaryNetwork.getNetId()).thenReturn(primaryNetworkId);
+
+        mNetworkCallbackCaptor.getValue().onCapabilitiesChanged(primaryNetwork, mainCapabilities);
+
+        assertThat(mWifiStatusTracker.isCarrierMerged).isTrue();
+    }
+
+    @Test
+    public void isDefaultNetwork_typicalWifi_true() {
+        WifiInfo primaryWifiInfo = Mockito.mock(WifiInfo.class);
+        when(primaryWifiInfo.isPrimary()).thenReturn(true);
+
+        NetworkCapabilities primaryCap = Mockito.mock(NetworkCapabilities.class);
+        when(primaryCap.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)).thenReturn(true);
+        when(primaryCap.getTransportInfo()).thenReturn(primaryWifiInfo);
+
+        Network primaryNetwork = Mockito.mock(Network.class);
+        int primaryNetworkId = 1;
+        when(primaryNetwork.getNetId()).thenReturn(primaryNetworkId);
+
+        mDefaultNetworkCallbackCaptor.getValue().onCapabilitiesChanged(primaryNetwork, primaryCap);
+
+        assertThat(mWifiStatusTracker.isDefaultNetwork).isTrue();
+    }
+
+    @Test
+    public void isDefaultNetwork_typicalCellular_false() {
+        NetworkCapabilities primaryCap = Mockito.mock(NetworkCapabilities.class);
+        when(primaryCap.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)).thenReturn(true);
+
+        Network primaryNetwork = Mockito.mock(Network.class);
+        int primaryNetworkId = 1;
+        when(primaryNetwork.getNetId()).thenReturn(primaryNetworkId);
+
+        mDefaultNetworkCallbackCaptor.getValue().onCapabilitiesChanged(primaryNetwork, primaryCap);
+
+        assertThat(mWifiStatusTracker.isDefaultNetwork).isFalse();
+    }
+
+    @Test
+    public void isDefaultNetwork_cellularCarrierMergedWifi_true() {
+        WifiInfo primaryWifiInfo = Mockito.mock(WifiInfo.class);
+        when(primaryWifiInfo.isPrimary()).thenReturn(true);
+        when(primaryWifiInfo.isCarrierMerged()).thenReturn(true);
+
+        NetworkCapabilities primaryCap = Mockito.mock(NetworkCapabilities.class);
+        when(primaryCap.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)).thenReturn(true);
+        when(primaryCap.getTransportInfo()).thenReturn(primaryWifiInfo);
+
+        Network primaryNetwork = Mockito.mock(Network.class);
+        int primaryNetworkId = 1;
+        when(primaryNetwork.getNetId()).thenReturn(primaryNetworkId);
+
+        mDefaultNetworkCallbackCaptor.getValue().onCapabilitiesChanged(primaryNetwork, primaryCap);
+
+        assertThat(mWifiStatusTracker.isDefaultNetwork).isTrue();
+    }
+
+    /** Test for b/225902574. */
+    @Test
+    public void isDefaultNetwork_cellularWithUnderlyingCarrierMergedWifi_true() {
+        WifiInfo underlyingCarrierMergedInfo = Mockito.mock(WifiInfo.class);
+        when(underlyingCarrierMergedInfo.isPrimary()).thenReturn(true);
+        when(underlyingCarrierMergedInfo.isCarrierMerged()).thenReturn(true);
+
+        NetworkCapabilities underlyingNetworkCapabilities = Mockito.mock(NetworkCapabilities.class);
+        when(underlyingNetworkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR))
+                .thenReturn(true);
+        when(underlyingNetworkCapabilities.getTransportInfo())
+                .thenReturn(underlyingCarrierMergedInfo);
+
+        Network underlyingNetwork = Mockito.mock(Network.class);
+        when(mConnectivityManager.getNetworkCapabilities(underlyingNetwork))
+                .thenReturn(underlyingNetworkCapabilities);
+
+        NetworkCapabilities mainCapabilities = Mockito.mock(NetworkCapabilities.class);
+        when(mainCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR))
+                .thenReturn(true);
+        when(mainCapabilities.getTransportInfo()).thenReturn(null);
+        when(mainCapabilities.getUnderlyingNetworks())
+                .thenReturn(Arrays.asList(underlyingNetwork));
+
+        Network primaryNetwork = Mockito.mock(Network.class);
+        int primaryNetworkId = 1;
+        when(primaryNetwork.getNetId()).thenReturn(primaryNetworkId);
+
+        mDefaultNetworkCallbackCaptor.getValue()
+                .onCapabilitiesChanged(primaryNetwork, mainCapabilities);
+
+        assertThat(mWifiStatusTracker.isDefaultNetwork).isTrue();
     }
 }
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index b95a149..a5908a8 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -252,9 +252,11 @@
         // domain
         "tests/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractorTest.kt",
         "tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt",
+        "tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardLongPressInteractorTest.kt",
         "tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt",
         "tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt",
         "tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt",
+        "tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerCallbackInteractorTest.kt",
         "tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt",
         // ui
         "tests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt",
@@ -263,6 +265,7 @@
         "tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt",
         "tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt",
         "tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt",
+        "tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt",
         // Keyguard helper
         "tests/src/com/android/systemui/keyguard/data/quickaffordance/FakeKeyguardQuickAffordanceConfig.kt",
         "tests/src/com/android/systemui/dump/LogBufferHelper.kt",
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 4652ef1..32d6b70 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -966,22 +966,6 @@
                  android:permission="android.permission.BIND_JOB_SERVICE"/>
 
         <!-- region Note Task -->
-        <activity
-            android:name=".notetask.shortcut.CreateNoteTaskShortcutActivity"
-            android:enabled="false"
-            android:exported="true"
-            android:excludeFromRecents="true"
-            android:resizeableActivity="false"
-            android:theme="@android:style/Theme.NoDisplay"
-            android:label="@string/note_task_button_label"
-            android:icon="@drawable/ic_note_task_shortcut_widget">
-
-            <intent-filter>
-                <action android:name="android.intent.action.CREATE_SHORTCUT" />
-                <category android:name="android.intent.category.DEFAULT" />
-            </intent-filter>
-        </activity>
-
         <service android:name=".notetask.NoteTaskControllerUpdateService" />
 
         <activity
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
index 296c2ae..94b3740 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -436,8 +436,8 @@
         }
 
         @BinderThread
-        override fun onAnimationCancelled(isKeyguardOccluded: Boolean) {
-            context.mainExecutor.execute { delegate.onAnimationCancelled(isKeyguardOccluded) }
+        override fun onAnimationCancelled() {
+            context.mainExecutor.execute { delegate.onAnimationCancelled() }
         }
     }
 
@@ -744,7 +744,7 @@
         }
 
         @UiThread
-        override fun onAnimationCancelled(isKeyguardOccluded: Boolean) {
+        override fun onAnimationCancelled() {
             if (timedOut) {
                 return
             }
@@ -754,7 +754,7 @@
             removeTimeout()
 
             animation?.cancel()
-            controller.onLaunchAnimationCancelled(newKeyguardOccludedState = isKeyguardOccluded)
+            controller.onLaunchAnimationCancelled()
         }
 
         private fun IRemoteAnimationFinishedCallback.invoke() {
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationDelegate.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationDelegate.kt
index 337408b..d465962 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationDelegate.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationDelegate.kt
@@ -26,5 +26,5 @@
     )
 
     /** Called on the UI thread when a signal is received to cancel the animation. */
-    @UiThread fun onAnimationCancelled(isKeyguardOccluded: Boolean)
+    @UiThread fun onAnimationCancelled()
 }
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
index 9d1dd1b..3a19990 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
@@ -22,12 +22,11 @@
 import android.annotation.SuppressLint
 import android.content.Context
 import android.graphics.Canvas
-import android.graphics.Rect
 import android.text.Layout
 import android.text.TextUtils
 import android.text.format.DateFormat
 import android.util.AttributeSet
-import android.util.MathUtils
+import android.util.MathUtils.constrainedMap
 import android.widget.TextView
 import com.android.internal.annotations.VisibleForTesting
 import com.android.systemui.animation.GlyphCallback
@@ -40,8 +39,6 @@
 import java.util.Calendar
 import java.util.Locale
 import java.util.TimeZone
-import kotlin.math.max
-import kotlin.math.min
 
 /**
  * Displays the time with the hour positioned above the minutes. (ie: 09 above 30 is 9:30)
@@ -478,122 +475,56 @@
         pw.println("    time=$time")
     }
 
-    fun moveForSplitShade(fromRect: Rect, toRect: Rect, fraction: Float) {
-        // Do we need to cancel an in-flight animation?
-        // Need to also check against 0.0f here; we can sometimes get two calls with fraction == 0,
-        // which trips up the check otherwise.
-        if (lastSeenAnimationProgress != 1.0f &&
-                lastSeenAnimationProgress != 0.0f &&
-                fraction == 0.0f) {
-            // New animation, but need to stop the old one. Figure out where each glyph currently
-            // is in relation to the box position. After that, use the leading digit's current
-            // position as the stop target.
-            currentAnimationNeededStop = true
+    private val moveToCenterDelays
+        get() = if (isLayoutRtl) MOVE_LEFT_DELAYS else MOVE_RIGHT_DELAYS
 
-            // We assume that the current glyph offsets would be relative to the "from" position.
-            val moveAmount = toRect.left - fromRect.left
+    private val moveToSideDelays
+        get() = if (isLayoutRtl) MOVE_RIGHT_DELAYS else MOVE_LEFT_DELAYS
 
-            // Remap the current glyph offsets to be relative to the new "end" position, and figure
-            // out the start/end positions for the stop animation.
-            for (i in 0 until NUM_DIGITS) {
-                glyphOffsets[i] = -moveAmount + glyphOffsets[i]
-                animationCancelStartPosition[i] = glyphOffsets[i]
-            }
-
-            // Use the leading digit's offset as the stop position.
-            if (toRect.left > fromRect.left) {
-                // It _was_ moving left
-                animationCancelStopPosition = glyphOffsets[0]
-            } else {
-                // It was moving right
-                animationCancelStopPosition = glyphOffsets[1]
-            }
-        }
-
-        // Is there a cancellation in progress?
-        if (currentAnimationNeededStop && fraction < ANIMATION_CANCELLATION_TIME) {
-            val animationStopProgress = MathUtils.constrainedMap(
-                    0.0f, 1.0f, 0.0f, ANIMATION_CANCELLATION_TIME, fraction
-            )
-
-            // One of the digits has already stopped.
-            val animationStopStep = 1.0f / (NUM_DIGITS - 1)
-
-            for (i in 0 until NUM_DIGITS) {
-                val stopAmount = if (toRect.left > fromRect.left) {
-                    // It was moving left (before flipping)
-                    MOVE_LEFT_DELAYS[i] * animationStopStep
-                } else {
-                    // It was moving right (before flipping)
-                    MOVE_RIGHT_DELAYS[i] * animationStopStep
-                }
-
-                // Leading digit stops immediately.
-                if (stopAmount == 0.0f) {
-                    glyphOffsets[i] = animationCancelStopPosition
-                } else {
-                    val actualStopAmount = MathUtils.constrainedMap(
-                            0.0f, 1.0f, 0.0f, stopAmount, animationStopProgress
+    /**
+     * Offsets the glyphs of the clock for the step clock animation.
+     *
+     * The animation makes the glyphs of the clock move at different speeds, when the clock is
+     * moving horizontally.
+     *
+     * @param clockStartLeft the [getLeft] position of the clock, before it started moving.
+     * @param clockMoveDirection the direction in which it is moving. A positive number means right,
+     *   and negative means left.
+     * @param moveFraction fraction of the clock movement. 0 means it is at the beginning, and 1
+     *   means it finished moving.
+     */
+    fun offsetGlyphsForStepClockAnimation(
+            clockStartLeft: Int,
+            clockMoveDirection: Int,
+            moveFraction: Float
+    ) {
+        val isMovingToCenter = if (isLayoutRtl) clockMoveDirection < 0 else clockMoveDirection > 0
+        val currentMoveAmount = left - clockStartLeft
+        val digitOffsetDirection = if (isLayoutRtl) -1 else 1
+        for (i in 0 until NUM_DIGITS) {
+            // The delay for the digit, in terms of fraction (i.e. the digit should not move
+            // during 0.0 - 0.1).
+            val digitInitialDelay =
+                    if (isMovingToCenter) {
+                        moveToCenterDelays[i] * MOVE_DIGIT_STEP
+                    } else {
+                        moveToSideDelays[i] * MOVE_DIGIT_STEP
+                    }
+            val digitFraction =
+                    MOVE_INTERPOLATOR.getInterpolation(
+                            constrainedMap(
+                                    0.0f,
+                                    1.0f,
+                                    digitInitialDelay,
+                                    digitInitialDelay + AVAILABLE_ANIMATION_TIME,
+                                    moveFraction
+                            )
                     )
-                    val easedProgress = MOVE_INTERPOLATOR.getInterpolation(actualStopAmount)
-                    val glyphMoveAmount =
-                            animationCancelStopPosition - animationCancelStartPosition[i]
-                    glyphOffsets[i] =
-                            animationCancelStartPosition[i] + glyphMoveAmount * easedProgress
-                }
-            }
-        } else {
-            // Normal part of the animation.
-            // Do we need to remap the animation progress to take account of the cancellation?
-            val actualFraction = if (currentAnimationNeededStop) {
-                MathUtils.constrainedMap(
-                        0.0f, 1.0f, ANIMATION_CANCELLATION_TIME, 1.0f, fraction
-                )
-            } else {
-                fraction
-            }
-
-            val digitFractions = (0 until NUM_DIGITS).map {
-                // The delay for each digit, in terms of fraction (i.e. the digit should not move
-                // during 0.0 - 0.1).
-                val initialDelay = if (toRect.left > fromRect.left) {
-                    MOVE_RIGHT_DELAYS[it] * MOVE_DIGIT_STEP
-                } else {
-                    MOVE_LEFT_DELAYS[it] * MOVE_DIGIT_STEP
-                }
-
-                val f = MathUtils.constrainedMap(
-                        0.0f, 1.0f,
-                        initialDelay, initialDelay + AVAILABLE_ANIMATION_TIME,
-                        actualFraction
-                )
-                MOVE_INTERPOLATOR.getInterpolation(max(min(f, 1.0f), 0.0f))
-            }
-
-            // Was there an animation halt?
-            val moveAmount = if (currentAnimationNeededStop) {
-                // Only need to animate over the remaining space if the animation was aborted.
-                -animationCancelStopPosition
-            } else {
-                toRect.left.toFloat() - fromRect.left.toFloat()
-            }
-
-            for (i in 0 until NUM_DIGITS) {
-                glyphOffsets[i] = -moveAmount + (moveAmount * digitFractions[i])
-            }
+            val moveAmountForDigit = currentMoveAmount * digitFraction
+            val moveAmountDeltaForDigit = moveAmountForDigit - currentMoveAmount
+            glyphOffsets[i] = digitOffsetDirection * moveAmountDeltaForDigit
         }
-
         invalidate()
-
-        if (fraction == 1.0f) {
-            // Reset
-            currentAnimationNeededStop = false
-        }
-
-        lastSeenAnimationProgress = fraction
-
-        // Ensure that the actual clock container is always in the "end" position.
-        this.setLeftTopRightBottom(toRect.left, toRect.top, toRect.right, toRect.bottom)
     }
 
     // DateFormat.getBestDateTimePattern is extremely expensive, and refresh is called often.
@@ -647,9 +578,6 @@
         private const val NUM_DIGITS = 4
         private const val DIGITS_PER_LINE = 2
 
-        // How much of "fraction" to spend on canceling the animation, if needed
-        private const val ANIMATION_CANCELLATION_TIME = 0f
-
         // Delays. Each digit's animation should have a slight delay, so we get a nice
         // "stepping" effect. When moving right, the second digit of the hour should move first.
         // When moving left, the first digit of the hour should move first. The lists encode
@@ -668,6 +596,6 @@
 
         // Total available transition time for each digit, taking into account the step. If step is
         // 0.1, then digit 0 would animate over 0.0 - 0.7, making availableTime 0.7.
-        private val AVAILABLE_ANIMATION_TIME = 1.0f - MOVE_DIGIT_STEP * (NUM_DIGITS - 1)
+        private const val AVAILABLE_ANIMATION_TIME = 1.0f - MOVE_DIGIT_STEP * (NUM_DIGITS - 1)
     }
 }
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
index f57432c..b0c0240 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
@@ -151,6 +151,7 @@
                             { str1 = id },
                             { "Clock Id conflict on load: $str1 is double registered" }
                         )
+                        manager.unloadPlugin()
                         continue
                     }
 
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
index 3fda83d..2cc3600 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
@@ -189,8 +189,9 @@
             view.setLayoutParams(lp)
         }
 
-        fun moveForSplitShade(fromRect: Rect, toRect: Rect, fraction: Float) {
-            view.moveForSplitShade(fromRect, toRect, fraction)
+        /** See documentation at [AnimatableClockView.offsetGlyphsForStepClockAnimation]. */
+        fun offsetGlyphsForStepClockAnimation(fromLeft: Int, direction: Int, fraction: Float) {
+            view.offsetGlyphsForStepClockAnimation(fromLeft, direction, fraction)
         }
     }
 
@@ -277,8 +278,8 @@
         dozeFraction: Float,
         foldFraction: Float,
     ) : DefaultClockAnimations(view, dozeFraction, foldFraction) {
-        override fun onPositionUpdated(fromRect: Rect, toRect: Rect, fraction: Float) {
-            largeClock.moveForSplitShade(fromRect, toRect, fraction)
+        override fun onPositionUpdated(fromLeft: Int, direction: Int, fraction: Float) {
+            largeClock.offsetGlyphsForStepClockAnimation(fromLeft, direction, fraction)
         }
     }
 
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
index 8ef2d80..ca3e710 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
@@ -141,8 +141,16 @@
     /** Runs the battery animation (if any). */
     fun charge() {}
 
-    /** Move the clock, for example, if the notification tray appears in split-shade mode. */
-    fun onPositionUpdated(fromRect: Rect, toRect: Rect, fraction: Float) {}
+    /**
+     * Runs when the clock's position changed during the move animation.
+     *
+     * @param fromLeft the [View.getLeft] position of the clock, before it started moving.
+     * @param direction the direction in which it is moving. A positive number means right, and
+     *   negative means left.
+     * @param fraction fraction of the clock movement. 0 means it is at the beginning, and 1 means
+     *   it finished moving.
+     */
+    fun onPositionUpdated(fromLeft: Int, direction: Int, fraction: Float) {}
 
     /**
      * Runs when swiping clock picker, swipingFraction: 1.0 -> clock is scaled up in the preview,
diff --git a/packages/SystemUI/res/layout/screen_record_dialog.xml b/packages/SystemUI/res/layout/screen_record_dialog.xml
index ab38dd2..ae052502 100644
--- a/packages/SystemUI/res/layout/screen_record_dialog.xml
+++ b/packages/SystemUI/res/layout/screen_record_dialog.xml
@@ -49,13 +49,13 @@
                     android:layout_height="wrap_content"
                     android:textAppearance="?android:attr/textAppearanceLarge"
                     android:fontFamily="@*android:string/config_headlineFontFamily"
-                    android:text="@string/screenrecord_start_label"
+                    android:text="@string/screenrecord_permission_dialog_title"
                     android:layout_marginTop="22dp"
                     android:layout_marginBottom="15dp"/>
                 <TextView
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:text="@string/screenrecord_description"
+                    android:text="@string/screenrecord_permission_dialog_warning_entire_screen"
                     android:textAppearance="?android:attr/textAppearanceSmall"
                     android:textColor="?android:textColorSecondary"
                     android:gravity="center"
@@ -168,7 +168,7 @@
                     android:layout_height="wrap_content"
                     android:layout_weight="0"
                     android:layout_gravity="end"
-                    android:text="@string/screenrecord_start"
+                    android:text="@string/screenrecord_continue"
                     style="@style/Widget.Dialog.Button" />
             </LinearLayout>
         </LinearLayout>
diff --git a/packages/SystemUI/res/layout/screen_share_dialog.xml b/packages/SystemUI/res/layout/screen_share_dialog.xml
index bd71989..7dbe059 100644
--- a/packages/SystemUI/res/layout/screen_share_dialog.xml
+++ b/packages/SystemUI/res/layout/screen_share_dialog.xml
@@ -63,7 +63,7 @@
             android:id="@+id/text_warning"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:text="@string/screenrecord_description"
+            android:text="@string/screenrecord_permission_dialog_warning_entire_screen"
             android:textAppearance="?android:attr/textAppearanceSmall"
             android:textColor="?android:textColorSecondary"
             android:gravity="start"
@@ -91,7 +91,7 @@
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_weight="0"
-                android:text="@string/screenrecord_start"
+                android:text="@string/screenrecord_continue"
                 style="@style/Widget.Dialog.Button" />
         </LinearLayout>
     </LinearLayout>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 4e68efe..853930e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -251,25 +251,22 @@
     <string name="app_clips_save_add_to_note">Add to note</string>
 
     <!-- Notification title displayed for screen recording [CHAR LIMIT=50]-->
-    <string name="screenrecord_name">Screen Recorder</string>
+    <string name="screenrecord_title">Screen Recorder</string>
     <!-- Processing screen recoding video in the background [CHAR LIMIT=30]-->
     <string name="screenrecord_background_processing_label">Processing screen recording</string>
     <!-- Description of the screen recording notification channel [CHAR LIMIT=NONE]-->
     <string name="screenrecord_channel_description">Ongoing notification for a screen record session</string>
+
+    <!-- For updated Screen Recording permission dialog (i.e. with PSS)-->
     <!-- Title for the screen prompting the user to begin recording their screen [CHAR LIMIT=NONE]-->
-    <string name="screenrecord_start_label">Start Recording?</string>
-    <!-- Message reminding the user that sensitive information may be captured during a screen recording [CHAR_LIMIT=NONE]-->
-    <string name="screenrecord_description">While recording, Android System can capture any sensitive information that\u2019s visible on your screen or played on your device. This includes passwords, payment info, photos, messages, and audio.</string>
-    <!-- Dropdown option to record the entire screen [CHAR_LIMIT=30]-->
-    <string name="screenrecord_option_entire_screen">Record entire screen</string>
-    <!-- Dropdown option to record a single app [CHAR_LIMIT=30]-->
-    <string name="screenrecord_option_single_app">Record a single app</string>
+    <string name="screenrecord_permission_dialog_title">Start Recording?</string>
     <!-- Message reminding the user that sensitive information may be captured during a full screen recording for the updated dialog that includes partial screen sharing option [CHAR_LIMIT=350]-->
-    <string name="screenrecord_warning_entire_screen">While you\'re recording, Android has access to anything visible on your screen or played on your device. So be careful with passwords, payment details, messages, or other sensitive information.</string>
+    <string name="screenrecord_permission_dialog_warning_entire_screen">While you’re recording, Android has access to anything visible on your screen or played on your device. So be careful with things like passwords, payment details, messages, photos, and audio and video.</string>
     <!-- Message reminding the user that sensitive information may be captured during a single app screen recording for the updated dialog that includes partial screen sharing option [CHAR_LIMIT=350]-->
-    <string name="screenrecord_warning_single_app">While you\'re recording an app, Android has access to anything shown or played on that app. So be careful with passwords, payment details, messages, or other sensitive information.</string>
+    <string name="screenrecord_permission_dialog_warning_single_app">While you’re recording an app, Android has access to anything shown or played on that app. So be careful with things like passwords, payment details, messages, photos, and audio and video.</string>
     <!-- Button to start a screen recording in the updated screen record dialog that allows to select an app to record [CHAR LIMIT=50]-->
-    <string name="screenrecord_start_recording">Start recording</string>
+    <string name="screenrecord_permission_dialog_continue">Start recording</string>
+
     <!-- Label for a switch to enable recording audio [CHAR LIMIT=NONE]-->
     <string name="screenrecord_audio_label">Record audio</string>
     <!-- Label for the option to record audio from the device [CHAR LIMIT=NONE]-->
@@ -281,7 +278,7 @@
     <!-- Label for an option to record audio from both device and microphone [CHAR LIMIT=NONE]-->
     <string name="screenrecord_device_audio_and_mic_label">Device audio and microphone</string>
     <!-- Button to start a screen recording [CHAR LIMIT=50]-->
-    <string name="screenrecord_start">Start</string>
+    <string name="screenrecord_continue">Start</string>
     <!-- Notification text displayed when we are recording the screen [CHAR LIMIT=100]-->
     <string name="screenrecord_ongoing_screen_only">Recording screen</string>
     <!-- Notification text displayed when we are recording both the screen and audio [CHAR LIMIT=100]-->
@@ -1064,47 +1061,52 @@
     <!-- Label for button in confirmation dialog when exiting guest session [CHAR LIMIT=35] -->
     <string name="user_remove_user_remove">Remove</string>
 
-    <!-- Media projection permission dialog warning text. [CHAR LIMIT=NONE] -->
-    <string name="media_projection_dialog_text"><xliff:g id="app_seeking_permission" example="Hangouts">%s</xliff:g> will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information such as passwords, payment details, photos, messages, and audio that you play.</string>
-
-    <!-- Media projection permission dialog warning text for system services. [CHAR LIMIT=NONE] -->
-    <string name="media_projection_dialog_service_text">The service providing this function will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information such as passwords, payment details, photos, messages, and audio that you play.</string>
-
-    <!-- Media projection permission dialog warning title for system services. [CHAR LIMIT=NONE] -->
-    <string name="media_projection_dialog_service_title">Start recording or casting?</string>
-
+    <!-- Media projection without Partial Screenshare -->
     <!-- Media projection permission dialog warning title. [CHAR LIMIT=NONE] -->
     <string name="media_projection_dialog_title">Start recording or casting with <xliff:g id="app_seeking_permission" example="Hangouts">%s</xliff:g>?</string>
+    <!-- Media projection permission dialog warning text. [CHAR LIMIT=NONE] -->
+    <string name="media_projection_dialog_warning"><xliff:g id="app_seeking_permission" example="Hangouts">%s</xliff:g> will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information such as passwords, payment details, photos, messages, and audio that you play.</string>
+    <!-- Media projection permission dialog warning title for system services. [CHAR LIMIT=NONE] -->
+    <string name="media_projection_sys_service_dialog_title">Start recording or casting?</string>
+    <!-- Media projection permission dialog warning text for system services. [CHAR LIMIT=NONE] -->
+    <string name="media_projection_sys_service_dialog_warning">The service providing this function will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information such as passwords, payment details, photos, messages, and audio that you play.</string>
 
-    <!-- Media projection permission dialog title. [CHAR LIMIT=NONE] -->
-    <string name="media_projection_permission_dialog_title">Allow <xliff:g id="app_seeking_permission" example="Meet">%s</xliff:g> to share or record?</string>
-
-    <!-- Media projection permission dropdown option for capturing the whole screen. [CHAR LIMIT=30] -->
-    <string name="media_projection_permission_dialog_option_entire_screen">Entire screen</string>
-
-    <!-- Media projection permission dropdown option for capturing single app. [CHAR LIMIT=30] -->
-    <string name="media_projection_permission_dialog_option_single_app">A single app</string>
-
-    <!-- Media projection permission warning for capturing the whole screen. [CHAR LIMIT=350] -->
-    <string name="media_projection_permission_dialog_warning_entire_screen">When you\'re sharing, recording, or casting, <xliff:g id="app_seeking_permission" example="Meet">%s</xliff:g> has access to anything visible on your screen or played on your device. So be careful with passwords, payment details, messages, or other sensitive information.</string>
-
-    <!-- Media projection permission warning for capturing an app. [CHAR LIMIT=350] -->
-    <string name="media_projection_permission_dialog_warning_single_app">When you\'re sharing, recording, or casting an app, <xliff:g id="app_seeking_permission" example="Meet">%s</xliff:g> has access to anything shown or played on that app. So be careful with passwords, payment details, messages, or other sensitive information.</string>
-
-    <!-- Media projection permission button to continue with app selection or recording [CHAR LIMIT=60] -->
-    <string name="media_projection_permission_dialog_continue">Continue</string>
-
+    <!-- Permission dropdown option for sharing or recording the whole screen. [CHAR LIMIT=30] -->
+    <string name="screen_share_permission_dialog_option_entire_screen">Entire screen</string>
+    <!-- Permission dropdown option for sharing or recording single app. [CHAR LIMIT=30] -->
+    <string name="screen_share_permission_dialog_option_single_app">A single app</string>
     <!-- Title of the dialog that allows to select an app to share or record [CHAR LIMIT=NONE] -->
-    <string name="media_projection_permission_app_selector_title">Share or record an app</string>
+    <string name="screen_share_permission_app_selector_title">Share or record an app</string>
 
-    <!-- Media projection permission dialog title when there is no app name (e.g. it could be a system service when casting). [CHAR LIMIT=100] -->
-    <string name="media_projection_permission_dialog_system_service_title">Allow this app to share or record?</string>
+    <!-- Media projection that launched from 1P/3P apps -->
+    <!-- 1P/3P app media projection permission dialog title. [CHAR LIMIT=NONE] -->
+    <string name="media_projection_entry_app_permission_dialog_title">Start recording or casting with <xliff:g id="app_seeking_permission" example="Meet">%s</xliff:g>?</string>
+    <!-- 1P/3P app media projection permission warning for capturing the whole screen. [CHAR LIMIT=350] -->
+    <string name="media_projection_entry_app_permission_dialog_warning_entire_screen">When you’re sharing, recording, or casting, <xliff:g id="app_seeking_permission" example="Meet">%s</xliff:g> has access to anything visible on your screen or played on your device. So be careful with things like passwords, payment details, messages, photos, and audio and video.</string>
+    <!-- 1P/3P app media projection permission warning for capturing an app. [CHAR LIMIT=350] -->
+    <string name="media_projection_entry_app_permission_dialog_warning_single_app">When you’re sharing, recording, or casting an app, <xliff:g id="app_seeking_permission" example="Meet">%s</xliff:g> has access to anything shown or played on that app. So be careful with things like passwords, payment details, messages, photos, and audio and video.</string>
+    <!-- 1P/3P apps media projection permission button to continue with app selection or recording [CHAR LIMIT=60] -->
+    <string name="media_projection_entry_app_permission_dialog_continue">Start</string>
 
-    <!-- Media projection permission warning for capturing the whole screen when a system service requests it (e.g. when casting). [CHAR LIMIT=350] -->
-    <string name="media_projection_permission_dialog_system_service_warning_entire_screen">When you\'re sharing, recording, or casting, this app has access to anything visible on your screen or played on your device. So be careful with passwords, payment details, messages, or other sensitive information.</string>
+    <!-- Casting that launched by SysUI (i.e. when there is no app name) -->
+    <!-- System casting media projection permission dialog title. [CHAR LIMIT=100] -->
+    <string name="media_projection_entry_cast_permission_dialog_title">Start casting?</string>
+    <!-- System casting media projection permission warning for capturing the whole screen when SysUI casting requests it. [CHAR LIMIT=350] -->
+    <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen">When you’re casting, Android has access to anything visible on your screen or played on your device. So be careful with things like passwords, payment details, messages, photos, and audio and video.</string>
+    <!-- System casting media projection permission warning for capturing a single app when SysUI casting requests it. [CHAR LIMIT=350] -->
+    <string name="media_projection_entry_cast_permission_dialog_warning_single_app">When you’re casting an app, Android has access to anything shown or played on that app. So be careful with things like passwords, payment details, messages, photos, and audio and video.</string>
+    <!-- System casting media projection permission button to continue for SysUI casting. [CHAR LIMIT=60] -->
+    <string name="media_projection_entry_cast_permission_dialog_continue">Start casting</string>
 
-    <!-- Media projection permission warning for capturing a single app when a system service requests it (e.g. when casting). [CHAR LIMIT=350] -->
-    <string name="media_projection_permission_dialog_system_service_warning_single_app">When you\'re sharing, recording, or casting an app, this app has access to anything shown or played on that app. So be careful with passwords, payment details, messages, or other sensitive information.</string>
+    <!-- Other sharing (not recording nor casting) that launched by SysUI (currently not in use) -->
+    <!-- System sharing media projection permission dialog title. [CHAR LIMIT=100] -->
+    <string name="media_projection_entry_generic_permission_dialog_title">Start sharing?</string>
+    <!-- System sharing media projection permission warning for capturing the whole screen. [CHAR LIMIT=350] -->
+    <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen">When you’re sharing, recording, or casting, Android has access to anything visible on your screen or played on your device. So be careful with things like passwords, payment details, messages, photos, and audio and video.</string>
+    <!-- System sharing media projection permission warning for capturing a single app. [CHAR LIMIT=350] -->
+    <string name="media_projection_entry_generic_permission_dialog_warning_single_app">When you’re sharing, recording, or casting an app, Android has access to anything shown or played on that app. So be careful with things like passwords, payment details, messages, photos, and audio and video.</string>
+    <!-- System sharing media projection permission button to continue. [CHAR LIMIT=60] -->
+    <string name="media_projection_entry_generic_permission_dialog_continue">Start</string>
 
     <!-- Title for the dialog that is shown when screen capturing is disabled by enterprise policy. [CHAR LIMIT=100] -->
     <string name="screen_capturing_disabled_by_policy_dialog_title">Blocked by your IT admin</string>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginActionManager.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginActionManager.java
index 3d05542..4f73fc4 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginActionManager.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginActionManager.java
@@ -109,7 +109,7 @@
     /** Load all plugins matching this instance's action. */
     public void loadAll() {
         if (DEBUG) Log.d(TAG, "startListening");
-        mBgExecutor.execute(this::queryAll);
+        mBgExecutor.execute(() -> queryAll());
     }
 
     /** Unload all plugins managed by this instance. */
@@ -255,17 +255,18 @@
             intent.setPackage(pkgName);
         }
         List<ResolveInfo> result = mPm.queryIntentServices(intent, 0);
-        if (DEBUG) Log.d(TAG, "Found " + result.size() + " plugins");
+        if (DEBUG) {
+            Log.d(TAG, "Found " + result.size() + " plugins");
+            for (ResolveInfo info : result) {
+                ComponentName name = new ComponentName(info.serviceInfo.packageName,
+                        info.serviceInfo.name);
+                Log.d(TAG, "  " + name);
+            }
+        }
+
         if (result.size() > 1 && !mAllowMultiple) {
             // TODO: Show warning.
             Log.w(TAG, "Multiple plugins found for " + mAction);
-            if (DEBUG) {
-                for (ResolveInfo info : result) {
-                    ComponentName name = new ComponentName(info.serviceInfo.packageName,
-                            info.serviceInfo.name);
-                    Log.w(TAG, "  " + name);
-                }
-            }
             return;
         }
         for (ResolveInfo info : result) {
@@ -307,7 +308,7 @@
             // TODO: Only create the plugin before version check if we need it for
             // legacy version check.
             if (DEBUG) {
-                Log.d(TAG, "createPlugin");
+                Log.d(TAG, "createPlugin: " + component);
             }
             try {
                 return mPluginInstanceFactory.create(
@@ -317,7 +318,7 @@
                 reportInvalidVersion(component, component.getClassName(), e);
             }
         } catch (Throwable e) {
-            Log.w(TAG, "Couldn't load plugin: " + packageName, e);
+            Log.w(TAG, "Couldn't load plugin: " + component, e);
             return null;
         }
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java
index 1b0dacc..8dcd2aa 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java
@@ -206,7 +206,7 @@
                 t.close();
                 info.releaseAllSurfaces();
                 if (finishRunnable == null) return;
-                onAnimationCancelled(false /* isKeyguardOccluded */);
+                onAnimationCancelled();
                 finishRunnable.run();
             }
         };
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index edfcb8d..0826f8a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -363,8 +363,6 @@
             } else {
                 View clockView = clockContainerView.getChildAt(0);
 
-                transition.excludeTarget(clockView, /* exclude= */ true);
-
                 TransitionSet set = new TransitionSet();
                 set.addTransition(transition);
 
@@ -389,8 +387,9 @@
 
     @VisibleForTesting
     static class SplitShadeTransitionAdapter extends Transition {
-        private static final String PROP_BOUNDS = "splitShadeTransitionAdapter:bounds";
-        private static final String[] TRANSITION_PROPERTIES = { PROP_BOUNDS };
+        private static final String PROP_BOUNDS_LEFT = "splitShadeTransitionAdapter:boundsLeft";
+        private static final String PROP_X_IN_WINDOW = "splitShadeTransitionAdapter:xInWindow";
+        private static final String[] TRANSITION_PROPERTIES = { PROP_BOUNDS_LEFT, PROP_X_IN_WINDOW};
 
         private final KeyguardClockSwitchController mController;
 
@@ -400,12 +399,10 @@
         }
 
         private void captureValues(TransitionValues transitionValues) {
-            Rect boundsRect = new Rect();
-            boundsRect.left = transitionValues.view.getLeft();
-            boundsRect.top = transitionValues.view.getTop();
-            boundsRect.right = transitionValues.view.getRight();
-            boundsRect.bottom = transitionValues.view.getBottom();
-            transitionValues.values.put(PROP_BOUNDS, boundsRect);
+            transitionValues.values.put(PROP_BOUNDS_LEFT, transitionValues.view.getLeft());
+            int[] locationInWindowTmp = new int[2];
+            transitionValues.view.getLocationInWindow(locationInWindowTmp);
+            transitionValues.values.put(PROP_X_IN_WINDOW, locationInWindowTmp[0]);
         }
 
         @Override
@@ -427,8 +424,12 @@
             }
             ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
 
-            Rect from = (Rect) startValues.values.get(PROP_BOUNDS);
-            Rect to = (Rect) endValues.values.get(PROP_BOUNDS);
+            int fromLeft = (int) startValues.values.get(PROP_BOUNDS_LEFT);
+            int fromWindowX = (int) startValues.values.get(PROP_X_IN_WINDOW);
+            int toWindowX = (int) endValues.values.get(PROP_X_IN_WINDOW);
+            // Using windowX, to determine direction, instead of left, as in RTL the difference of
+            // toLeft - fromLeft is always positive, even when moving left.
+            int direction = toWindowX - fromWindowX > 0 ? 1 : -1;
 
             anim.addUpdateListener(animation -> {
                 ClockController clock = mController.getClock();
@@ -437,7 +438,7 @@
                 }
 
                 clock.getLargeClock().getAnimations()
-                        .onPositionUpdated(from, to, animation.getAnimatedFraction());
+                        .onPositionUpdated(fromLeft, direction, animation.getAnimatedFraction());
             });
 
             return anim;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 2c669bb..9573913 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -396,6 +396,7 @@
     private int mFaceRunningState = BIOMETRIC_STATE_STOPPED;
     private boolean mIsDreaming;
     private boolean mLogoutEnabled;
+    private boolean mIsFaceEnrolled;
     private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
     private int mPostureState = DEVICE_POSTURE_UNKNOWN;
     private FingerprintInteractiveToAuthProvider mFingerprintInteractiveToAuthProvider;
@@ -2572,6 +2573,16 @@
         }
     }
 
+    private void updateFaceEnrolled(int userId) {
+        final Boolean isFaceEnrolled = isFaceSupported()
+                && mBiometricEnabledForUser.get(userId)
+                && mAuthController.isFaceAuthEnrolled(userId);
+        if (mIsFaceEnrolled != isFaceEnrolled) {
+            mLogger.logFaceEnrolledUpdated(mIsFaceEnrolled, isFaceEnrolled);
+        }
+        mIsFaceEnrolled = isFaceEnrolled;
+    }
+
     private boolean isFaceSupported() {
         return mFaceManager != null && !mFaceSensorProperties.isEmpty();
     }
@@ -2611,17 +2622,10 @@
     }
 
     /**
-     * @return true if there's at least one face enrolled for the given user
-     */
-    private boolean isFaceEnrolled(int userId) {
-        return mAuthController.isFaceAuthEnrolled(userId);
-    }
-
-    /**
-     * @return true if there's at least one face enrolled for the current user
+     * @return true if there's at least one face enrolled
      */
     public boolean isFaceEnrolled() {
-        return isFaceEnrolled(getCurrentUser());
+        return mIsFaceEnrolled;
     }
 
     private final UserTracker.Callback mUserChangedCallback = new UserTracker.Callback() {
@@ -3280,13 +3284,14 @@
     @SuppressLint("MissingPermission")
     @VisibleForTesting
     boolean isUnlockWithFingerprintPossible(int userId) {
-        boolean newFpPossible = isFingerprintSupported()
-                && !isFingerprintDisabled(userId) && mAuthController.isFingerprintEnrolled(userId);
-        Boolean oldFpPossible = mIsUnlockWithFingerprintPossible.getOrDefault(userId, false);
-        if (oldFpPossible != newFpPossible) {
-            mLogger.logFpPossibleUpdated(userId, oldFpPossible, newFpPossible);
+        // TODO (b/242022358), make this rely on onEnrollmentChanged event and update it only once.
+        boolean newFpEnrolled = isFingerprintSupported()
+                && !isFingerprintDisabled(userId) && mFpm.hasEnrolledTemplates(userId);
+        Boolean oldFpEnrolled = mIsUnlockWithFingerprintPossible.getOrDefault(userId, false);
+        if (oldFpEnrolled != newFpEnrolled) {
+            mLogger.logFpEnrolledUpdated(userId, oldFpEnrolled, newFpEnrolled);
         }
-        mIsUnlockWithFingerprintPossible.put(userId, newFpPossible);
+        mIsUnlockWithFingerprintPossible.put(userId, newFpEnrolled);
         return mIsUnlockWithFingerprintPossible.get(userId);
     }
 
@@ -3301,13 +3306,24 @@
     /**
      * @deprecated This is being migrated to use modern architecture.
      */
-    @VisibleForTesting
     @Deprecated
-    public boolean isUnlockWithFacePossible(int userId) {
+    private boolean isUnlockWithFacePossible(int userId) {
         if (isFaceAuthInteractorEnabled()) {
             return getFaceAuthInteractor().canFaceAuthRun();
         }
-        return isFaceSupported() && isFaceEnrolled(userId) && !isFaceDisabled(userId);
+        return isFaceAuthEnabledForUser(userId) && !isFaceDisabled(userId);
+    }
+
+    /**
+     * If face hardware is available, user has enrolled and enabled auth via setting.
+     *
+     * @deprecated This is being migrated to use modern architecture.
+     */
+    @Deprecated
+    public boolean isFaceAuthEnabledForUser(int userId) {
+        // TODO (b/242022358), make this rely on onEnrollmentChanged event and update it only once.
+        updateFaceEnrolled(userId);
+        return mIsFaceEnrolled;
     }
 
     private void stopListeningForFingerprint() {
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
index fe40145..1661806 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
@@ -630,7 +630,7 @@
         )
     }
 
-    fun logFpPossibleUpdated(userId: Int, oldValue: Boolean, newValue: Boolean) {
+    fun logFpEnrolledUpdated(userId: Int, oldValue: Boolean, newValue: Boolean) {
         logBuffer.log(
             TAG,
             DEBUG,
@@ -639,7 +639,7 @@
                 bool1 = oldValue
                 bool2 = newValue
             },
-            { "Fp possible state changed for userId: $int1 old: $bool1, new: $bool2" }
+            { "Fp enrolled state changed for userId: $int1 old: $bool1, new: $bool2" }
         )
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/OWNERS b/packages/SystemUI/src/com/android/systemui/accessibility/OWNERS
new file mode 100644
index 0000000..1f66c91
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 44215
+
+include /core/java/android/view/accessibility/OWNERS
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
index f3c71da..4158390 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
@@ -45,6 +45,8 @@
 
 import com.android.internal.R;
 import com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity;
+import com.android.internal.accessibility.util.AccessibilityUtils;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ScreenshotHelper;
 import com.android.systemui.CoreStartable;
 import com.android.systemui.dagger.SysUISingleton;
@@ -520,8 +522,11 @@
                 SCREENSHOT_ACCESSIBILITY_ACTIONS, new Handler(Looper.getMainLooper()), null);
     }
 
-    private void handleHeadsetHook() {
-        sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HEADSETHOOK);
+    @VisibleForTesting
+    void handleHeadsetHook() {
+        if (!AccessibilityUtils.interceptHeadsetHookForActiveCall(mContext)) {
+            sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HEADSETHOOK);
+        }
     }
 
     private void handleAccessibilityButton() {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
index 7bfd84e..155c26d 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java
@@ -463,13 +463,17 @@
         if ((configDiff & ActivityInfo.CONFIG_UI_MODE) != 0
                 || (configDiff & ActivityInfo.CONFIG_ASSETS_PATHS) != 0
                 || (configDiff & ActivityInfo.CONFIG_FONT_SCALE) != 0
+                || (configDiff & ActivityInfo.CONFIG_LOCALE) != 0
                 || (configDiff & ActivityInfo.CONFIG_DENSITY) != 0) {
             // We listen to following config changes to trigger layout inflation:
             // CONFIG_UI_MODE: theme change
             // CONFIG_ASSETS_PATHS: wallpaper change
             // CONFIG_FONT_SCALE: font size change
+            // CONFIG_LOCALE: language change
             // CONFIG_DENSITY: display size change
 
+            mParams.accessibilityTitle = getAccessibilityWindowTitle(mContext);
+
             boolean showSettingPanelAfterThemeChange = mIsVisible;
             hideSettingPanel(/* resetPosition= */ false);
             inflateView();
@@ -490,11 +494,6 @@
                     + mDraggableWindowBounds.top;
             return;
         }
-
-        if ((configDiff & ActivityInfo.CONFIG_LOCALE) != 0) {
-            updateAccessibilityWindowTitle();
-            return;
-        }
     }
 
     private void onWindowInsetChanged() {
@@ -515,13 +514,6 @@
         }
     }
 
-    private void updateAccessibilityWindowTitle() {
-        mParams.accessibilityTitle = getAccessibilityWindowTitle(mContext);
-        if (mIsVisible) {
-            mWindowManager.updateViewLayout(mSettingView, mParams);
-        }
-    }
-
     public void editMagnifierSizeMode(boolean enable) {
         setEditMagnifierSizeMode(enable);
         updateSelectedButton(MagnificationSize.NONE);
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt
index 3d6d335..18bd467 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt
@@ -41,7 +41,8 @@
     private val context: Context,
     @Background private val backgroundExecutor: DelayableExecutor,
     private val lazyController: Lazy<ControlsController>,
-    userTracker: UserTracker
+    private val packageUpdateMonitorFactory: PackageUpdateMonitor.Factory,
+    userTracker: UserTracker,
 ) : ControlsBindingController {
 
     companion object {
@@ -93,7 +94,8 @@
                 backgroundExecutor,
                 actionCallbackService,
                 currentUser,
-                component
+                component,
+                packageUpdateMonitorFactory
         )
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
index 217f4d8..cb2476c 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.controls.controller
 
+import android.annotation.WorkerThread
 import android.content.ComponentName
 import android.content.Context
 import android.content.Intent
@@ -23,7 +24,6 @@
 import android.os.Binder
 import android.os.Bundle
 import android.os.IBinder
-import android.os.RemoteException
 import android.os.UserHandle
 import android.service.controls.ControlsProviderService
 import android.service.controls.ControlsProviderService.CALLBACK_BUNDLE
@@ -38,6 +38,7 @@
 import com.android.internal.annotations.GuardedBy
 import com.android.systemui.util.concurrency.DelayableExecutor
 import java.util.concurrent.TimeUnit
+import java.util.concurrent.atomic.AtomicBoolean
 
 /**
  * Manager for the lifecycle of the connection to a given [ControlsProviderService].
@@ -45,6 +46,9 @@
  * This class handles binding and unbinding and requests to the service. The class will queue
  * requests until the service is connected and dispatch them then.
  *
+ * If the provider app is updated, and we are currently bound to it, it will try to rebind after
+ * update is completed.
+ *
  * @property context A SystemUI context for binding to the services
  * @property executor A delayable executor for posting timeouts
  * @property actionCallbackService a callback interface to hand the remote service for sending
@@ -59,22 +63,22 @@
     private val executor: DelayableExecutor,
     private val actionCallbackService: IControlsActionCallback.Stub,
     val user: UserHandle,
-    val componentName: ComponentName
-) : IBinder.DeathRecipient {
+    val componentName: ComponentName,
+    packageUpdateMonitorFactory: PackageUpdateMonitor.Factory,
+) {
 
     val token: IBinder = Binder()
     private var requiresBound = false
     @GuardedBy("queuedServiceMethods")
     private val queuedServiceMethods: MutableSet<ServiceMethod> = ArraySet()
     private var wrapper: ServiceWrapper? = null
-    private var bindTryCount = 0
     private val TAG = javaClass.simpleName
     private var onLoadCanceller: Runnable? = null
 
+    private var lastForPanel = false
+
     companion object {
-        private const val BIND_RETRY_DELAY = 1000L // ms
         private const val LOAD_TIMEOUT_SECONDS = 20L // seconds
-        private const val MAX_BIND_RETRIES = 5
         private const val DEBUG = true
         private val BIND_FLAGS = Context.BIND_AUTO_CREATE or Context.BIND_FOREGROUND_SERVICE or
             Context.BIND_NOT_PERCEPTIBLE
@@ -91,60 +95,56 @@
         })
     }
 
-    private fun bindService(bind: Boolean, forPanel: Boolean = false) {
-        executor.execute {
-            requiresBound = bind
-            if (bind) {
-                if (bindTryCount != MAX_BIND_RETRIES && wrapper == null) {
-                    if (DEBUG) {
-                        Log.d(TAG, "Binding service $intent")
-                    }
-                    bindTryCount++
-                    try {
-                        val flags = if (forPanel) BIND_FLAGS_PANEL else BIND_FLAGS
-                        val bound = context
-                                .bindServiceAsUser(intent, serviceConnection, flags, user)
-                        if (!bound) {
-                            context.unbindService(serviceConnection)
-                        }
-                    } catch (e: SecurityException) {
-                        Log.e(TAG, "Failed to bind to service", e)
-                    }
-                }
-            } else {
-                if (DEBUG) {
-                    Log.d(TAG, "Unbinding service $intent")
-                }
-                bindTryCount = 0
-                wrapper?.run {
-                    context.unbindService(serviceConnection)
-                }
-                wrapper = null
+    private val packageUpdateMonitor = packageUpdateMonitorFactory.create(
+        user,
+        componentName.packageName,
+    ) {
+        if (requiresBound) {
+            // Let's unbind just in case. onBindingDied should have been called and unbound before.
+            executor.execute {
+                unbindAndCleanup("package updated")
+                bindService(true, lastForPanel)
             }
         }
     }
 
+    private fun bindService(bind: Boolean, forPanel: Boolean = false) {
+        executor.execute {
+            bindServiceBackground(bind, forPanel)
+        }
+    }
+
     private val serviceConnection = object : ServiceConnection {
+
+        val connected = AtomicBoolean(false)
+
         override fun onServiceConnected(name: ComponentName, service: IBinder) {
             if (DEBUG) Log.d(TAG, "onServiceConnected $name")
-            bindTryCount = 0
             wrapper = ServiceWrapper(IControlsProvider.Stub.asInterface(service))
-            try {
-                service.linkToDeath(this@ControlsProviderLifecycleManager, 0)
-            } catch (_: RemoteException) {}
+            packageUpdateMonitor.startMonitoring()
             handlePendingServiceMethods()
         }
 
         override fun onServiceDisconnected(name: ComponentName?) {
             if (DEBUG) Log.d(TAG, "onServiceDisconnected $name")
             wrapper = null
-            bindService(false)
+            // No need to call unbind. We may get a new `onServiceConnected`
         }
 
         override fun onNullBinding(name: ComponentName?) {
             if (DEBUG) Log.d(TAG, "onNullBinding $name")
             wrapper = null
-            context.unbindService(this)
+            executor.execute {
+                unbindAndCleanup("null binding")
+            }
+        }
+
+        override fun onBindingDied(name: ComponentName?) {
+            super.onBindingDied(name)
+            if (DEBUG) Log.d(TAG, "onBindingDied $name")
+            executor.execute {
+                unbindAndCleanup("binder died")
+            }
         }
     }
 
@@ -159,14 +159,55 @@
         }
     }
 
-    override fun binderDied() {
-        if (wrapper == null) return
-        wrapper = null
-        if (requiresBound) {
-            if (DEBUG) {
-                Log.d(TAG, "binderDied")
+    @WorkerThread
+    private fun bindServiceBackground(bind: Boolean, forPanel: Boolean = true) {
+        requiresBound = bind
+        if (bind) {
+            if (wrapper == null) {
+                if (DEBUG) {
+                    Log.d(TAG, "Binding service $intent")
+                }
+                try {
+                    lastForPanel = forPanel
+                    val flags = if (forPanel) BIND_FLAGS_PANEL else BIND_FLAGS
+                    var bound = false
+                    if (serviceConnection.connected.compareAndSet(false, true)) {
+                        bound = context
+                            .bindServiceAsUser(intent, serviceConnection, flags, user)
+                    }
+                    if (!bound) {
+                        Log.d(TAG, "Couldn't bind to $intent")
+                        doUnbind()
+                    }
+                } catch (e: SecurityException) {
+                    Log.e(TAG, "Failed to bind to service", e)
+                    // Couldn't even bind. Let's reset the connected value
+                    serviceConnection.connected.set(false)
+                }
             }
-            // Try rebinding some time later
+        } else {
+            unbindAndCleanup("unbind requested")
+            packageUpdateMonitor.stopMonitoring()
+        }
+    }
+
+    @WorkerThread
+    private fun unbindAndCleanup(reason: String) {
+        if (DEBUG) {
+            Log.d(TAG, "Unbinding service $intent. Reason: $reason")
+        }
+        wrapper = null
+        try {
+            doUnbind()
+        } catch (e: IllegalArgumentException) {
+            Log.e(TAG, "Failed to unbind service", e)
+        }
+    }
+
+    @WorkerThread
+    private fun doUnbind() {
+        if (serviceConnection.connected.compareAndSet(true, false)) {
+            context.unbindService(serviceConnection)
         }
     }
 
@@ -313,7 +354,7 @@
         fun run() {
             if (!callWrapper()) {
                 queueServiceMethod(this)
-                binderDied()
+                executor.execute { unbindAndCleanup("couldn't call through binder") }
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/PackageUpdateMonitor.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/PackageUpdateMonitor.kt
new file mode 100644
index 0000000..1973b62
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/PackageUpdateMonitor.kt
@@ -0,0 +1,76 @@
+/*
+ * 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.controls.controller
+
+import android.content.Context
+import android.os.Handler
+import android.os.UserHandle
+import com.android.internal.content.PackageMonitor
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import java.util.concurrent.atomic.AtomicBoolean
+
+/** [PackageMonitor] that tracks when [packageName] has finished updating for user [user]. */
+class PackageUpdateMonitor
+@AssistedInject
+constructor(
+    @Assisted private val user: UserHandle,
+    @Assisted private val packageName: String,
+    @Assisted private val callback: Runnable,
+    @Background private val bgHandler: Handler,
+    @Application private val context: Context,
+) : PackageMonitor() {
+
+    private val monitoring = AtomicBoolean(false)
+
+    @AssistedFactory
+    fun interface Factory {
+        /**
+         * Create a [PackageUpdateMonitor] for a given [user] and [packageName]. It will run
+         * [callback] every time the package finishes updating.
+         */
+        fun create(user: UserHandle, packageName: String, callback: Runnable): PackageUpdateMonitor
+    }
+
+    /** Start monitoring for package updates. No-op if already monitoring. */
+    fun startMonitoring() {
+        if (monitoring.compareAndSet(/* expected */ false, /* new */ true)) {
+            register(context, user, false, bgHandler)
+        }
+    }
+
+    /** Stop monitoring for package updates. No-op if not monitoring. */
+    fun stopMonitoring() {
+        if (monitoring.compareAndSet(/* expected */ true, /* new */ false)) {
+            unregister()
+        }
+    }
+
+    /**
+     * If the package and the user match the ones for this [PackageUpdateMonitor], it will run
+     * [callback].
+     */
+    override fun onPackageUpdateFinished(packageName: String?, uid: Int) {
+        super.onPackageUpdateFinished(packageName, uid)
+        if (packageName == this.packageName && UserHandle.getUserHandleForUid(uid) == user) {
+            callback.run()
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ServiceWrapper.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ServiceWrapper.kt
index 2c717f5..45cb13b 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ServiceWrapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ServiceWrapper.kt
@@ -16,11 +16,11 @@
 
 package com.android.systemui.controls.controller
 
-import android.service.controls.actions.ControlAction
 import android.service.controls.IControlsActionCallback
 import android.service.controls.IControlsProvider
 import android.service.controls.IControlsSubscriber
 import android.service.controls.IControlsSubscription
+import android.service.controls.actions.ControlAction
 import android.service.controls.actions.ControlActionWrapper
 import android.util.Log
 
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamLogger.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamLogger.kt
new file mode 100644
index 0000000..eb79290
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamLogger.kt
@@ -0,0 +1,30 @@
+/*
+ * 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.dreams
+
+import com.android.systemui.log.dagger.DreamLog
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
+import javax.inject.Inject
+
+/** Logs dream-related stuff to a {@link LogBuffer}. */
+class DreamLogger @Inject constructor(@DreamLog private val buffer: LogBuffer) {
+    /** Logs a debug message to the buffer. */
+    fun d(tag: String, message: String) {
+        buffer.log(tag, LogLevel.DEBUG, { str1 = message }, { message })
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
index 5b56c04..df46e07 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
@@ -21,6 +21,7 @@
 import android.animation.ValueAnimator
 import android.view.View
 import android.view.animation.Interpolator
+import androidx.core.animation.doOnCancel
 import androidx.core.animation.doOnEnd
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
@@ -65,7 +66,11 @@
     private val mDreamInTranslationYDistance: Int,
     @Named(DreamOverlayModule.DREAM_IN_TRANSLATION_Y_DURATION)
     private val mDreamInTranslationYDurationMs: Long,
+    private val mLogger: DreamLogger,
 ) {
+    companion object {
+        private const val TAG = "DreamOverlayAnimationsController"
+    }
 
     private var mAnimator: Animator? = null
     private lateinit var view: View
@@ -169,8 +174,11 @@
                 doOnEnd {
                     mAnimator = null
                     mOverlayStateController.setEntryAnimationsFinished(true)
+                    mLogger.d(TAG, "Dream overlay entry animations finished.")
                 }
+                doOnCancel { mLogger.d(TAG, "Dream overlay entry animations canceled.") }
                 start()
+                mLogger.d(TAG, "Dream overlay entry animations started.")
             }
     }
 
@@ -232,8 +240,11 @@
                 doOnEnd {
                     mAnimator = null
                     mOverlayStateController.setExitAnimationsRunning(false)
+                    mLogger.d(TAG, "Dream overlay exit animations finished.")
                 }
+                doOnCancel { mLogger.d(TAG, "Dream overlay exit animations canceled.") }
                 start()
+                mLogger.d(TAG, "Dream overlay exit animations started.")
             }
         mOverlayStateController.setExitAnimationsRunning(true)
         return mAnimator as AnimatorSet
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 9427303..e31834c 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -68,8 +68,6 @@
     val NOTIFICATION_MEMORY_LOGGING_ENABLED =
         unreleasedFlag(119, "notification_memory_logging_enabled")
 
-    @JvmField val USE_ROUNDNESS_SOURCETYPES = releasedFlag(116, "use_roundness_sourcetype")
-
     @JvmField
     val SIMPLIFIED_APPEAR_FRACTION =
         releasedFlag(259395680, "simplified_appear_fraction")
@@ -81,7 +79,8 @@
     // TODO(b/278873737): Tracking Bug
     @JvmField
     val LOAD_NOTIFICATIONS_BEFORE_THE_USER_SWITCH_IS_COMPLETE =
-            unreleasedFlag(278873737, "load_notifications_before_the_user_switch_is_complete")
+            unreleasedFlag(278873737, "load_notifications_before_the_user_switch_is_complete",
+                    teamfood = true)
 
     // TODO(b/277338665): Tracking Bug
     @JvmField
@@ -116,7 +115,7 @@
 
     // TODO(b/275694445): Tracking Bug
     @JvmField
-    val LOCKSCREEN_WITHOUT_SECURE_LOCK_WHEN_DREAMING = releasedFlag(208,
+    val LOCKSCREEN_WITHOUT_SECURE_LOCK_WHEN_DREAMING = unreleasedFlag(208,
         "lockscreen_without_secure_lock_when_dreaming")
 
     /**
@@ -679,8 +678,8 @@
 
     // TODO(b/272805037): Tracking Bug
     @JvmField
-    val ADVANCED_VPN_ENABLED = unreleasedFlag(2800, name = "AdvancedVpn__enable_feature",
-            namespace = "vpn", teamfood = true)
+    val ADVANCED_VPN_ENABLED = releasedFlag(2800, name = "AdvancedVpn__enable_feature",
+            namespace = "vpn")
 
     // TODO(b/278761837): Tracking Bug
     @JvmField
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 107e685..8b6bd24 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -243,7 +243,7 @@
                         Slog.e(TAG, "Called mergeAnimation, but finish callback is missing");
                         return;
                     }
-                    runner.onAnimationCancelled(false /* isKeyguardOccluded */);
+                    runner.onAnimationCancelled();
                     currentFinishCB.onTransitionFinished(null /* wct */, null /* t */);
                 } catch (RemoteException e) {
                     // nothing, we'll just let it finish on its own I guess.
@@ -418,7 +418,7 @@
         }
 
         @Override // Binder interface
-        public void onAnimationCancelled(boolean isKeyguardOccluded) {
+        public void onAnimationCancelled() {
             mKeyguardViewMediator.cancelKeyguardExitAnimation();
         }
     };
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 93ddfba..1a126d7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -959,20 +959,15 @@
                 @Nullable private ValueAnimator mOccludeByDreamAnimator;
 
                 @Override
-                public void onAnimationCancelled(boolean isKeyguardOccluded) {
+                public void onAnimationCancelled() {
                     mContext.getMainExecutor().execute(() -> {
                         if (mOccludeByDreamAnimator != null) {
                             mOccludeByDreamAnimator.cancel();
                         }
                     });
-                    // The value of isKeyguardOccluded here may come from mergeAnimation, which
-                    // isn't reliable. In all cases, after running or cancelling this animation,
-                    // keyguard should be occluded.
+
+                    Log.d(TAG, "OccludeByDreamAnimator#onAnimationCancelled. Set occluded = true");
                     setOccluded(true /* isOccluded */, false /* animate */);
-                    if (DEBUG) {
-                        Log.d(TAG, "Occlude by Dream animation cancelled. Occluded state is now: "
-                                + mOccluded);
-                    }
                 }
 
                 @Override
@@ -984,6 +979,7 @@
                         // Usually we rely on animation completion to synchronize occluded status,
                         // but there was no animation to play, so just update it now.
                         setOccluded(true /* isOccluded */, false /* animate */);
+                        finishedCallback.onAnimationFinished();
                     }
                 }
 
@@ -991,11 +987,8 @@
                         RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
                         IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException {
                     if (apps == null || apps.length == 0 || apps[0] == null) {
-                        if (DEBUG) {
-                            Log.d(TAG, "No apps provided to the OccludeByDream runner; "
-                                    + "skipping occluding animation.");
-                        }
-                        finishedCallback.onAnimationFinished();
+                        Log.d(TAG, "No apps provided to the OccludeByDream runner; "
+                                + "skipping occluding animation.");
                         return false;
                     }
 
@@ -1005,7 +998,6 @@
                     if (!isDream) {
                         Log.w(TAG, "The occluding app isn't Dream; "
                                 + "finishing up. Please check that the config is correct.");
-                        finishedCallback.onAnimationFinished();
                         return false;
                     }
 
@@ -1071,17 +1063,14 @@
                 private final Matrix mUnoccludeMatrix = new Matrix();
 
                 @Override
-                public void onAnimationCancelled(boolean isKeyguardOccluded) {
+                public void onAnimationCancelled() {
                     mContext.getMainExecutor().execute(() -> {
                         if (mUnoccludeAnimator != null) {
                             mUnoccludeAnimator.cancel();
                         }
                     });
 
-                    setOccluded(isKeyguardOccluded /* isOccluded */, false /* animate */);
-                    Log.d(TAG, "Unocclude animation cancelled. Occluded state is now: "
-                            + mOccluded);
-
+                    Log.d(TAG, "Unocclude animation cancelled.");
                     mInteractionJankMonitor.cancel(CUJ_LOCKSCREEN_OCCLUSION);
                 }
 
@@ -3404,9 +3393,9 @@
         }
 
         @Override
-        public void onAnimationCancelled(boolean isKeyguardOccluded) throws RemoteException {
+        public void onAnimationCancelled() throws RemoteException {
             if (mRunner != null) {
-                mRunner.onAnimationCancelled(isKeyguardOccluded);
+                mRunner.onAnimationCancelled();
             }
         }
 
@@ -3452,13 +3441,9 @@
         }
 
         @Override
-        public void onAnimationCancelled(boolean isKeyguardOccluded) throws RemoteException {
-            super.onAnimationCancelled(isKeyguardOccluded);
-
-            Log.d(TAG, "Occlude animation cancelled by WM. "
-                    + "Setting occluded state to: " + isKeyguardOccluded);
-            setOccluded(isKeyguardOccluded /* occluded */, false /* animate */);
-
+        public void onAnimationCancelled() throws RemoteException {
+            super.onAnimationCancelled();
+            Log.d(TAG, "Occlude animation cancelled by WM.");
             mInteractionJankMonitor.cancel(CUJ_LOCKSCREEN_OCCLUSION);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt
index 9b94cdb..148d425 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AlternateBouncerInteractor.kt
@@ -41,17 +41,6 @@
     var receivedDownTouch = false
     val isVisible: Flow<Boolean> = bouncerRepository.alternateBouncerVisible
 
-    private val keyguardStateControllerCallback: KeyguardStateController.Callback =
-        object : KeyguardStateController.Callback {
-            override fun onUnlockedChanged() {
-                maybeHide()
-            }
-        }
-
-    init {
-        keyguardStateController.addCallback(keyguardStateControllerCallback)
-    }
-
     /**
      * Sets the correct bouncer states to show the alternate bouncer if it can show.
      *
@@ -102,11 +91,18 @@
         return (systemClock.uptimeMillis() - bouncerRepository.lastAlternateBouncerVisibleTime) >
             MIN_VISIBILITY_DURATION_UNTIL_TOUCHES_DISMISS_ALTERNATE_BOUNCER_MS
     }
-
-    private fun maybeHide() {
+    /**
+     * Should only be called through StatusBarKeyguardViewManager which propagates the source of
+     * truth to other concerned controllers. Will hide the alternate bouncer if it's no longer
+     * allowed to show.
+     *
+     * @return true if the alternate bouncer was newly hidden, else false.
+     */
+    fun maybeHide(): Boolean {
         if (isVisibleState() && !canShowAlternateBouncerForFingerprint()) {
-            hide()
+            return hide()
         }
+        return false
     }
 
     companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/DreamLog.kt b/packages/SystemUI/src/com/android/systemui/log/dagger/DreamLog.kt
new file mode 100644
index 0000000..cb9913ab
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/DreamLog.kt
@@ -0,0 +1,22 @@
+/*
+ * 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 javax.inject.Qualifier
+
+/** A [com.android.systemui.log.LogBuffer] for dream-related logging. */
+@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class DreamLog
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 077ee02..658f6a0 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -440,4 +440,14 @@
     public static LogBuffer provideKeyguardLogBuffer(LogBufferFactory factory) {
         return factory.create("KeyguardLog", 250);
     }
+
+    /**
+     * Provides a {@link LogBuffer} for dream-related logs.
+     */
+    @Provides
+    @SysUISingleton
+    @DreamLog
+    public static LogBuffer provideDreamLogBuffer(LogBufferFactory factory) {
+        return factory.create("DreamLog", 250);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/log/table/LogProxy.kt b/packages/SystemUI/src/com/android/systemui/log/table/LogProxy.kt
new file mode 100644
index 0000000..53886aa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/table/LogProxy.kt
@@ -0,0 +1,67 @@
+/*
+ * 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.table
+
+import android.util.Log
+import javax.inject.Inject
+
+/** Dagger-friendly interface so we can inject a fake [android.util.Log] in tests */
+interface LogProxy {
+    /** verbose log */
+    fun v(tag: String, message: String)
+
+    /** debug log */
+    fun d(tag: String, message: String)
+
+    /** info log */
+    fun i(tag: String, message: String)
+
+    /** warning log */
+    fun w(tag: String, message: String)
+
+    /** error log */
+    fun e(tag: String, message: String)
+
+    /** wtf log */
+    fun wtf(tag: String, message: String)
+}
+
+class LogProxyDefault @Inject constructor() : LogProxy {
+    override fun v(tag: String, message: String) {
+        Log.v(tag, message)
+    }
+
+    override fun d(tag: String, message: String) {
+        Log.d(tag, message)
+    }
+
+    override fun i(tag: String, message: String) {
+        Log.i(tag, message)
+    }
+
+    override fun w(tag: String, message: String) {
+        Log.w(tag, message)
+    }
+
+    override fun e(tag: String, message: String) {
+        Log.e(tag, message)
+    }
+
+    override fun wtf(tag: String, message: String) {
+        Log.wtf(tag, message)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt
index faaa205..9d883cc 100644
--- a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt
@@ -19,10 +19,17 @@
 import android.os.Trace
 import com.android.systemui.Dumpable
 import com.android.systemui.common.buffer.RingBuffer
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.plugins.log.LogcatEchoTracker
 import com.android.systemui.util.time.SystemClock
 import java.io.PrintWriter
 import java.text.SimpleDateFormat
 import java.util.Locale
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.launch
 
 /**
  * A logger that logs changes in table format.
@@ -73,12 +80,18 @@
     maxSize: Int,
     private val name: String,
     private val systemClock: SystemClock,
+    private val logcatEchoTracker: LogcatEchoTracker,
+    @Background private val bgDispatcher: CoroutineDispatcher,
+    private val coroutineScope: CoroutineScope,
+    private val localLogcat: LogProxy = LogProxyDefault(),
 ) : Dumpable {
     init {
         if (maxSize <= 0) {
             throw IllegalArgumentException("maxSize must be > 0")
         }
     }
+    // For local logcat, send messages across this channel so the background job can process them
+    private val logMessageChannel = Channel<TableChange>(capacity = 10)
 
     private val buffer = RingBuffer(maxSize) { TableChange() }
 
@@ -105,6 +118,16 @@
             tableLogBuffer = this,
         )
 
+    /** Start this log buffer logging in the background */
+    internal fun init() {
+        coroutineScope.launch(bgDispatcher) {
+            while (!logMessageChannel.isClosedForReceive) {
+                val log = logMessageChannel.receive()
+                echoToDesiredEndpoints(log)
+            }
+        }
+    }
+
     /**
      * Log the differences between [prevVal] and [newVal].
      *
@@ -189,6 +212,7 @@
         Trace.beginSection("TableLogBuffer#logChange(string)")
         val change = obtain(timestamp, prefix, columnName, isInitial)
         change.set(value)
+        tryAddMessage(change)
         Trace.endSection()
     }
 
@@ -202,6 +226,7 @@
         Trace.beginSection("TableLogBuffer#logChange(boolean)")
         val change = obtain(timestamp, prefix, columnName, isInitial)
         change.set(value)
+        tryAddMessage(change)
         Trace.endSection()
     }
 
@@ -215,9 +240,14 @@
         Trace.beginSection("TableLogBuffer#logChange(int)")
         val change = obtain(timestamp, prefix, columnName, isInitial)
         change.set(value)
+        tryAddMessage(change)
         Trace.endSection()
     }
 
+    private fun tryAddMessage(change: TableChange) {
+        logMessageChannel.trySend(change)
+    }
+
     // TODO(b/259454430): Add additional change types here.
 
     @Synchronized
@@ -258,6 +288,17 @@
         Trace.endSection()
     }
 
+    private fun echoToDesiredEndpoints(change: TableChange) {
+        if (
+            logcatEchoTracker.isBufferLoggable(bufferName = name, LogLevel.DEBUG) ||
+                logcatEchoTracker.isTagLoggable(change.columnName, LogLevel.DEBUG)
+        ) {
+            if (change.hasData()) {
+                localLogcat.d(name, change.logcatRepresentation())
+            }
+        }
+    }
+
     @Synchronized
     override fun dump(pw: PrintWriter, args: Array<out String>) {
         pw.println(HEADER_PREFIX + name)
@@ -284,6 +325,12 @@
         pw.println()
     }
 
+    /** Transforms an individual [TableChange] into a String for logcat */
+    private fun TableChange.logcatRepresentation(): String {
+        val formattedTimestamp = TABLE_LOG_DATE_FORMAT.format(timestamp)
+        return "$formattedTimestamp$SEPARATOR${getName()}$SEPARATOR${getVal()}"
+    }
+
     /**
      * A private implementation of [TableRowLogger].
      *
diff --git a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt
index 06668d3..42e742d 100644
--- a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt
@@ -17,10 +17,15 @@
 package com.android.systemui.log.table
 
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.log.LogBufferHelper.Companion.adjustMaxSize
+import com.android.systemui.plugins.log.LogcatEchoTracker
 import com.android.systemui.util.time.SystemClock
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
 
 @SysUISingleton
 class TableLogBufferFactory
@@ -28,6 +33,9 @@
 constructor(
     private val dumpManager: DumpManager,
     private val systemClock: SystemClock,
+    private val logcatEchoTracker: LogcatEchoTracker,
+    @Background private val bgDispatcher: CoroutineDispatcher,
+    @Application private val coroutineScope: CoroutineScope,
 ) {
     private val existingBuffers = mutableMapOf<String, TableLogBuffer>()
 
@@ -44,8 +52,17 @@
         name: String,
         maxSize: Int,
     ): TableLogBuffer {
-        val tableBuffer = TableLogBuffer(adjustMaxSize(maxSize), name, systemClock)
+        val tableBuffer =
+            TableLogBuffer(
+                adjustMaxSize(maxSize),
+                name,
+                systemClock,
+                logcatEchoTracker,
+                bgDispatcher,
+                coroutineScope,
+            )
         dumpManager.registerNormalDumpable(name, tableBuffer)
+        tableBuffer.init()
         return tableBuffer
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
index 0860c20..aec7b5f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
@@ -259,7 +259,7 @@
             putExtra(Intent.EXTRA_INTENT, queryIntent)
 
             // Update the title of the chooser
-            val title = resources.getString(R.string.media_projection_permission_app_selector_title)
+            val title = resources.getString(R.string.screen_share_permission_app_selector_title)
             putExtra(Intent.EXTRA_TITLE, title)
 
             // Select host app's profile tab by default
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
index e217e36..28adfbb 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
@@ -157,8 +157,8 @@
         CharSequence dialogTitle = null;
         String appName = null;
         if (Utils.isHeadlessRemoteDisplayProvider(packageManager, mPackageName)) {
-            dialogText = getString(R.string.media_projection_dialog_service_text);
-            dialogTitle = getString(R.string.media_projection_dialog_service_title);
+            dialogText = getString(R.string.media_projection_sys_service_dialog_warning);
+            dialogTitle = getString(R.string.media_projection_sys_service_dialog_title);
         } else {
             String label = aInfo.loadLabel(packageManager).toString();
 
@@ -188,7 +188,7 @@
                     paint, MAX_APP_NAME_SIZE_PX, TextUtils.TruncateAt.END).toString();
             appName = BidiFormatter.getInstance().unicodeWrap(unsanitizedAppName);
 
-            String actionText = getString(R.string.media_projection_dialog_text, appName);
+            String actionText = getString(R.string.media_projection_dialog_warning, appName);
             SpannableString message = new SpannableString(actionText);
 
             int appNameIndex = actionText.indexOf(appName);
diff --git a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
index 2a8168b..05e04a1 100644
--- a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
@@ -88,18 +88,9 @@
         private final IBinder mToken;
         private final Ringtone mRingtone;
 
-        public Client(IBinder token, Uri uri, UserHandle user, AudioAttributes aa) {
-            this(token, uri, user, aa, null);
-        }
-
-        Client(IBinder token, Uri uri, UserHandle user, AudioAttributes aa,
-                @Nullable VolumeShaper.Configuration volumeShaperConfig) {
+        Client(IBinder token, Ringtone ringtone) {
             mToken = token;
-
-            mRingtone = new Ringtone(getContextForUser(user), false);
-            mRingtone.setAudioAttributesField(aa);
-            mRingtone.setUri(uri, volumeShaperConfig);
-            mRingtone.createLocalMediaPlayer();
+            mRingtone = ringtone;
         }
 
         @Override
@@ -129,11 +120,28 @@
             Client client;
             synchronized (mClients) {
                 client = mClients.get(token);
-                if (client == null) {
-                    final UserHandle user = Binder.getCallingUserHandle();
-                    client = new Client(token, uri, user, aa, volumeShaperConfig);
-                    token.linkToDeath(client, 0);
-                    mClients.put(token, client);
+            }
+            // Don't hold the lock while constructing the ringtone, since it can be slow. The caller
+            // shouldn't call play on the same ringtone from 2 threads, so this shouldn't race and
+            // waste the build.
+            if (client == null) {
+                final UserHandle user = Binder.getCallingUserHandle();
+                Ringtone ringtone = new Ringtone(getContextForUser(user), false);
+                ringtone.setAudioAttributesField(aa);
+                ringtone.setUri(uri, volumeShaperConfig);
+                ringtone.createLocalMediaPlayer();
+                synchronized (mClients) {
+                    client = mClients.get(token);
+                    if (client == null) {
+                        client = new Client(token, ringtone);
+                        token.linkToDeath(client, 0);
+                        mClients.put(token, client);
+                        ringtone = null;  // "owned" by the client now.
+                    }
+                }
+                // Clean up ringtone if it was abandoned (a client already existed).
+                if (ringtone != null) {
+                    ringtone.stop();
                 }
             }
             client.mRingtone.setLooping(looping);
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDeviceManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDeviceManager.kt
index 120704c..3fc3ad6 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDeviceManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDeviceManager.kt
@@ -154,6 +154,7 @@
             get() = controller?.sessionToken
         private var started = false
         private var playbackType = PLAYBACK_TYPE_UNKNOWN
+        private var playbackVolumeControlId: String? = null
         private var current: MediaDeviceData? = null
             set(value) {
                 val sameWithoutIcon = value != null && value.equalsWithoutIcon(field)
@@ -181,6 +182,7 @@
                     localMediaManager.startScan()
                     muteAwaitConnectionManager?.startListening()
                     playbackType = controller?.playbackInfo?.playbackType ?: PLAYBACK_TYPE_UNKNOWN
+                    playbackVolumeControlId = controller?.playbackInfo?.volumeControlId
                     controller?.registerCallback(this)
                     updateCurrent()
                     started = true
@@ -209,6 +211,8 @@
                 println("    current device is ${current?.name}")
                 val type = controller?.playbackInfo?.playbackType
                 println("    PlaybackType=$type (1 for local, 2 for remote) cached=$playbackType")
+                val volumeControlId = controller?.playbackInfo?.volumeControlId
+                println("    volumeControlId=$volumeControlId cached= $playbackVolumeControlId")
                 println("    routingSession=$routingSession")
                 println("    selectedRoutes=$selectedRoutes")
             }
@@ -217,10 +221,15 @@
         @WorkerThread
         override fun onAudioInfoChanged(info: MediaController.PlaybackInfo?) {
             val newPlaybackType = info?.playbackType ?: PLAYBACK_TYPE_UNKNOWN
-            if (newPlaybackType == playbackType) {
+            val newPlaybackVolumeControlId = info?.volumeControlId
+            if (
+                newPlaybackType == playbackType &&
+                    newPlaybackVolumeControlId == playbackVolumeControlId
+            ) {
                 return
             }
             playbackType = newPlaybackType
+            playbackVolumeControlId = newPlaybackVolumeControlId
             updateCurrent()
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
index 0aa4349..1e9a466 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
@@ -67,6 +67,7 @@
 import com.android.systemui.util.time.SystemClock
 import com.android.systemui.util.traceSection
 import java.io.PrintWriter
+import java.util.Locale
 import java.util.TreeMap
 import javax.inject.Inject
 import javax.inject.Provider
@@ -166,6 +167,8 @@
             }
         }
 
+    private var carouselLocale: Locale? = null
+
     /** Whether the media card currently has the "expanded" layout */
     @VisibleForTesting
     var currentlyExpanded = true
@@ -218,6 +221,15 @@
                 updatePlayers(recreateMedia = false)
                 inflateSettingsButton()
             }
+
+            override fun onLocaleListChanged() {
+                // Update players only if system primary language changes.
+                if (carouselLocale != context.resources.configuration.locales.get(0)) {
+                    carouselLocale = context.resources.configuration.locales.get(0)
+                    updatePlayers(recreateMedia = true)
+                    inflateSettingsButton()
+                }
+            }
         }
 
     private val keyguardUpdateMonitorCallback =
@@ -262,6 +274,7 @@
                 this::logSmartspaceImpression,
                 logger
             )
+        carouselLocale = context.resources.configuration.locales.get(0)
         isRtl = context.resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL
         inflateSettingsButton()
         mediaContent = mediaCarousel.requireViewById(R.id.media_carousel)
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 9ebc8e4..8e014c6 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -126,10 +126,11 @@
     private final LocalBluetoothManager mLocalBluetoothManager;
     private final ActivityStarter mActivityStarter;
     private final DialogLaunchAnimator mDialogLaunchAnimator;
-    private final List<MediaDevice> mGroupMediaDevices = new CopyOnWriteArrayList<>();
     private final CommonNotifCollection mNotifCollection;
     private final Object mMediaDevicesLock = new Object();
     @VisibleForTesting
+    final List<MediaDevice> mGroupMediaDevices = new CopyOnWriteArrayList<>();
+    @VisibleForTesting
     final List<MediaDevice> mMediaDevices = new CopyOnWriteArrayList<>();
     final List<MediaDevice> mCachedMediaDevices = new CopyOnWriteArrayList<>();
     private final List<MediaItem> mMediaItemList = new CopyOnWriteArrayList<>();
@@ -713,7 +714,7 @@
             dividerItems.forEach((key, item) -> {
                 finalMediaItems.add(key, item);
             });
-            finalMediaItems.add(new MediaItem());
+            attachConnectNewDeviceItemIfNeeded(finalMediaItems);
             mMediaItemList.clear();
             mMediaItemList.addAll(finalMediaItems);
         }
@@ -749,7 +750,7 @@
                     finalMediaItems.add(new MediaItem(device));
                 }
             }
-            finalMediaItems.add(new MediaItem());
+            attachConnectNewDeviceItemIfNeeded(finalMediaItems);
             mMediaItemList.clear();
             mMediaItemList.addAll(finalMediaItems);
         }
@@ -760,6 +761,13 @@
                 new MediaItem(title, MediaItem.MediaItemType.TYPE_GROUP_DIVIDER));
     }
 
+    private void attachConnectNewDeviceItemIfNeeded(List<MediaItem> mediaItems) {
+        // Attach "Connect a device" item only when current output is not remote and not a group
+        if (!isCurrentConnectedDeviceRemote() && getSelectedMediaDevice().size() == 1) {
+            mediaItems.add(new MediaItem());
+        }
+    }
+
     private void attachRangeInfo(List<MediaDevice> devices) {
         for (MediaDevice mediaDevice : devices) {
             if (mNearbyDeviceInfoMap.containsKey(mediaDevice.getId())) {
@@ -1251,7 +1259,8 @@
         return null;
     }
 
-    private final MediaController.Callback mCb = new MediaController.Callback() {
+    @VisibleForTesting
+    final MediaController.Callback mCb = new MediaController.Callback() {
         @Override
         public void onMetadataChanged(MediaMetadata metadata) {
             mCallback.onMediaChanged();
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
index 8aec0c6..d4052f5 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskController.kt
@@ -42,7 +42,6 @@
 import com.android.systemui.devicepolicy.areKeyguardShortcutsDisabled
 import com.android.systemui.notetask.NoteTaskRoleManagerExt.createNoteShortcutInfoAsUser
 import com.android.systemui.notetask.NoteTaskRoleManagerExt.getDefaultRoleHolderAsUser
-import com.android.systemui.notetask.shortcut.CreateNoteTaskShortcutActivity
 import com.android.systemui.notetask.shortcut.LaunchNoteTaskManagedProfileProxyActivity
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.shared.system.ActivityManagerKt.isInForeground
@@ -231,8 +230,6 @@
      * Widget Picker to all users.
      */
     fun setNoteTaskShortcutEnabled(value: Boolean, user: UserHandle) {
-        val componentName = ComponentName(context, CreateNoteTaskShortcutActivity::class.java)
-
         val enabledState =
             if (value) {
                 PackageManager.COMPONENT_ENABLED_STATE_ENABLED
@@ -249,8 +246,9 @@
             } else {
                 context.createContextAsUser(user, /* flags= */ 0)
             }
+
         userContext.packageManager.setComponentEnabledSetting(
-            componentName,
+            SETTINGS_CREATE_NOTE_TASK_SHORTCUT_COMPONENT,
             enabledState,
             PackageManager.DONT_KILL_APP,
         )
@@ -298,6 +296,19 @@
     companion object {
         val TAG = NoteTaskController::class.simpleName.orEmpty()
 
+        /**
+         * IMPORTANT! The shortcut package name and class should be synchronized with Settings:
+         * [com.android.settings.notetask.shortcut.CreateNoteTaskShortcutActivity].
+         *
+         * Changing the package name or class is a breaking change.
+         */
+        @VisibleForTesting
+        val SETTINGS_CREATE_NOTE_TASK_SHORTCUT_COMPONENT =
+            ComponentName(
+                "com.android.settings",
+                "com.android.settings.notetask.shortcut.CreateNoteTaskShortcutActivity",
+            )
+
         const val SHORTCUT_ID = "note_task_shortcut_id"
 
         /**
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt
index a166393..2c62ffd 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskModule.kt
@@ -24,7 +24,6 @@
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
 import com.android.systemui.notetask.quickaffordance.NoteTaskQuickAffordanceModule
-import com.android.systemui.notetask.shortcut.CreateNoteTaskShortcutActivity
 import com.android.systemui.notetask.shortcut.LaunchNoteTaskActivity
 import com.android.systemui.notetask.shortcut.LaunchNoteTaskManagedProfileProxyActivity
 import dagger.Binds
@@ -46,9 +45,6 @@
     @[Binds IntoMap ClassKey(LaunchNoteTaskManagedProfileProxyActivity::class)]
     fun LaunchNoteTaskManagedProfileProxyActivity.bindNoteTaskLauncherProxyActivity(): Activity
 
-    @[Binds IntoMap ClassKey(CreateNoteTaskShortcutActivity::class)]
-    fun CreateNoteTaskShortcutActivity.bindNoteTaskShortcutActivity(): Activity
-
     companion object {
 
         @[Provides NoteTaskEnabledKey]
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/shortcut/CreateNoteTaskShortcutActivity.kt b/packages/SystemUI/src/com/android/systemui/notetask/shortcut/CreateNoteTaskShortcutActivity.kt
deleted file mode 100644
index 0cfb0a5..0000000
--- a/packages/SystemUI/src/com/android/systemui/notetask/shortcut/CreateNoteTaskShortcutActivity.kt
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2022 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.
- */
-
-@file:OptIn(InternalNoteTaskApi::class)
-
-package com.android.systemui.notetask.shortcut
-
-import android.app.Activity
-import android.app.role.RoleManager
-import android.content.pm.ShortcutManager
-import android.os.Bundle
-import androidx.activity.ComponentActivity
-import com.android.systemui.notetask.InternalNoteTaskApi
-import com.android.systemui.notetask.NoteTaskRoleManagerExt.createNoteShortcutInfoAsUser
-import javax.inject.Inject
-
-/**
- * Activity responsible for create a shortcut for notes action. If the shortcut is enabled, a new
- * shortcut will appear in the widget picker. If the shortcut is selected, the Activity here will be
- * launched, creating a new shortcut for [CreateNoteTaskShortcutActivity], and will finish.
- *
- * @see <a
- *   href="https://developer.android.com/develop/ui/views/launch/shortcuts/creating-shortcuts#custom-pinned">Creating
- *   a custom shortcut activity</a>
- */
-class CreateNoteTaskShortcutActivity
-@Inject
-constructor(
-    private val roleManager: RoleManager,
-    private val shortcutManager: ShortcutManager,
-) : ComponentActivity() {
-
-    override fun onCreate(savedInstanceState: Bundle?) {
-        super.onCreate(savedInstanceState)
-
-        val shortcutInfo = roleManager.createNoteShortcutInfoAsUser(context = this, user)
-        val shortcutIntent = shortcutManager.createShortcutResultIntent(shortcutInfo)
-        setResult(Activity.RESULT_OK, shortcutIntent)
-
-        finish()
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/HeaderPrivacyIconsController.kt b/packages/SystemUI/src/com/android/systemui/qs/HeaderPrivacyIconsController.kt
index 6f645b5..995c6a4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/HeaderPrivacyIconsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/HeaderPrivacyIconsController.kt
@@ -26,7 +26,9 @@
 import javax.inject.Inject
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.shade.ShadeModule.Companion.SHADE_HEADER
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import javax.inject.Named
 
 interface ChipVisibilityListener {
     fun onChipVisibilityRefreshed(visible: Boolean)
@@ -45,10 +47,10 @@
 class HeaderPrivacyIconsController @Inject constructor(
     private val privacyItemController: PrivacyItemController,
     private val uiEventLogger: UiEventLogger,
-    private val privacyChip: OngoingPrivacyChip,
+    @Named(SHADE_HEADER) private val privacyChip: OngoingPrivacyChip,
     private val privacyDialogController: PrivacyDialogController,
     private val privacyLogger: PrivacyLogger,
-    private val iconContainer: StatusIconContainer,
+    @Named(SHADE_HEADER) private val iconContainer: StatusIconContainer,
     private val permissionManager: PermissionManager,
     @Background private val backgroundExecutor: Executor,
     @Main private val uiExecutor: Executor,
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/MediaProjectionPermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/MediaProjectionPermissionDialog.kt
index 201557c..f4f5f66 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/MediaProjectionPermissionDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/MediaProjectionPermissionDialog.kt
@@ -28,12 +28,14 @@
 ) : BaseScreenSharePermissionDialog(context, createOptionList(appName), appName) {
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
+        // TODO(b/270018943): Handle the case of System sharing (not recording nor casting)
         if (appName == null) {
-            setDialogTitle(R.string.media_projection_permission_dialog_system_service_title)
+            setDialogTitle(R.string.media_projection_entry_cast_permission_dialog_title)
+            setStartButtonText(R.string.media_projection_entry_cast_permission_dialog_continue)
         } else {
-            setDialogTitle(R.string.media_projection_permission_dialog_title)
+            setDialogTitle(R.string.media_projection_entry_app_permission_dialog_title)
+            setStartButtonText(R.string.media_projection_entry_app_permission_dialog_continue)
         }
-        setStartButtonText(R.string.media_projection_permission_dialog_continue)
         setStartButtonOnClickListener {
             // Note that it is important to run this callback before dismissing, so that the
             // callback can disable the dialog exit animation if it wants to.
@@ -50,26 +52,26 @@
         private fun createOptionList(appName: String?): List<ScreenShareOption> {
             val singleAppWarningText =
                 if (appName == null) {
-                    R.string.media_projection_permission_dialog_system_service_warning_single_app
+                    R.string.media_projection_entry_cast_permission_dialog_warning_single_app
                 } else {
-                    R.string.media_projection_permission_dialog_warning_single_app
+                    R.string.media_projection_entry_app_permission_dialog_warning_single_app
                 }
             val entireScreenWarningText =
                 if (appName == null) {
-                    R.string.media_projection_permission_dialog_system_service_warning_entire_screen
+                    R.string.media_projection_entry_cast_permission_dialog_warning_entire_screen
                 } else {
-                    R.string.media_projection_permission_dialog_warning_entire_screen
+                    R.string.media_projection_entry_app_permission_dialog_warning_entire_screen
                 }
 
             return listOf(
                 ScreenShareOption(
                     mode = ENTIRE_SCREEN,
-                    spinnerText = R.string.media_projection_permission_dialog_option_entire_screen,
+                    spinnerText = R.string.screen_share_permission_dialog_option_entire_screen,
                     warningText = entireScreenWarningText
                 ),
                 ScreenShareOption(
                     mode = SINGLE_APP,
-                    spinnerText = R.string.media_projection_permission_dialog_option_single_app,
+                    spinnerText = R.string.screen_share_permission_dialog_option_single_app,
                     warningText = singleAppWarningText
                 )
             )
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index 4349bd7..69008cc 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -262,7 +262,7 @@
         Resources res = getResources();
         NotificationChannel channel = new NotificationChannel(
                 CHANNEL_ID,
-                getString(R.string.screenrecord_name),
+                getString(R.string.screenrecord_title),
                 NotificationManager.IMPORTANCE_DEFAULT);
         channel.setDescription(getString(R.string.screenrecord_channel_description));
         channel.enableVibration(true);
@@ -270,7 +270,7 @@
 
         Bundle extras = new Bundle();
         extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
-                res.getString(R.string.screenrecord_name));
+                res.getString(R.string.screenrecord_title));
         String notificationTitle = res.getString(R.string.screenrecord_start_error);
 
         Notification.Builder builder = new Notification.Builder(this, CHANNEL_ID)
@@ -290,7 +290,7 @@
         Resources res = getResources();
         NotificationChannel channel = new NotificationChannel(
                 CHANNEL_ID,
-                getString(R.string.screenrecord_name),
+                getString(R.string.screenrecord_title),
                 NotificationManager.IMPORTANCE_DEFAULT);
         channel.setDescription(getString(R.string.screenrecord_channel_description));
         channel.enableVibration(true);
@@ -298,7 +298,7 @@
 
         Bundle extras = new Bundle();
         extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
-                res.getString(R.string.screenrecord_name));
+                res.getString(R.string.screenrecord_title));
 
         String notificationTitle = mAudioSource == ScreenRecordingAudioSource.NONE
                 ? res.getString(R.string.screenrecord_ongoing_screen_only)
@@ -335,7 +335,7 @@
 
         Bundle extras = new Bundle();
         extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
-                res.getString(R.string.screenrecord_name));
+                res.getString(R.string.screenrecord_title));
 
         Notification.Builder builder = new Notification.Builder(getApplicationContext(), CHANNEL_ID)
                 .setContentTitle(notificationTitle)
@@ -365,7 +365,7 @@
 
         Bundle extras = new Bundle();
         extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
-                getResources().getString(R.string.screenrecord_name));
+                getResources().getString(R.string.screenrecord_title));
 
         Notification.Builder builder = new Notification.Builder(this, CHANNEL_ID)
                 .setSmallIcon(R.drawable.ic_screenrecord)
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
index efa45a4..2a21aaa 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
@@ -100,7 +100,7 @@
         window.addPrivateFlags(WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS);
 
         window.setGravity(Gravity.CENTER);
-        setTitle(R.string.screenrecord_name);
+        setTitle(R.string.screenrecord_title);
 
         setContentView(R.layout.screen_record_dialog);
 
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt
index 30509e2..bfaf3d0 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt
@@ -62,8 +62,8 @@
     private lateinit var options: Spinner
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
-        setDialogTitle(R.string.screenrecord_start_label)
-        setStartButtonText(R.string.screenrecord_start_recording)
+        setDialogTitle(R.string.screenrecord_permission_dialog_title)
+        setStartButtonText(R.string.screenrecord_permission_dialog_continue)
         setStartButtonOnClickListener { v: View? ->
             onStartRecordingClicked?.run()
             if (selectedScreenShareOption.mode == ENTIRE_SCREEN) {
@@ -186,13 +186,13 @@
             return listOf(
                 ScreenShareOption(
                     ENTIRE_SCREEN,
-                    R.string.screenrecord_option_entire_screen,
-                    R.string.screenrecord_warning_entire_screen
+                    R.string.screen_share_permission_dialog_option_entire_screen,
+                    R.string.screenrecord_permission_dialog_warning_entire_screen
                 ),
                 ScreenShareOption(
                     SINGLE_APP,
-                    R.string.screenrecord_option_single_app,
-                    R.string.screenrecord_warning_single_app
+                    R.string.screen_share_permission_dialog_option_single_app,
+                    R.string.screenrecord_permission_dialog_warning_single_app
                 )
             )
         }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
index aa8e2c0..187019a 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
@@ -154,5 +154,5 @@
             }
         }
 
-        override fun onAnimationCancelled(isKeyguardOccluded: Boolean) {}
+        override fun onAnimationCancelled() {}
     }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index c9d1da38..77a65b2 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -150,7 +150,7 @@
                 }
 
                 @Override
-                public void onAnimationCancelled(boolean isKeyguardOccluded) {
+                public void onAnimationCancelled() {
                 }
             };
 
diff --git a/packages/SystemUI/src/com/android/systemui/shade/CombinedShadeHeadersConstraintManagerImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/CombinedShadeHeadersConstraintManagerImpl.kt
index b3d31f2..7e0f504 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/CombinedShadeHeadersConstraintManagerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/CombinedShadeHeadersConstraintManagerImpl.kt
@@ -19,12 +19,12 @@
 import android.view.ViewGroup
 import androidx.constraintlayout.widget.ConstraintSet
 import com.android.systemui.R
-import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent
+import com.android.systemui.dagger.SysUISingleton
 
 /**
  * Standard implementation of [CombinedShadeHeadersConstraintManager].
  */
-@CentralSurfacesComponent.CentralSurfacesScope
+@SysUISingleton
 object CombinedShadeHeadersConstraintManagerImpl : CombinedShadeHeadersConstraintManager {
 
     override fun privacyChipVisibilityConstraints(visible: Boolean): ConstraintsChanges {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
index ef14d1c..4012736 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
@@ -70,6 +70,7 @@
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.screenrecord.RecordingController;
+import com.android.systemui.shade.data.repository.ShadeRepository;
 import com.android.systemui.shade.transition.ShadeTransitionController;
 import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
@@ -136,6 +137,7 @@
     private final KeyguardFaceAuthInteractor mKeyguardFaceAuthInteractor;
     private final FeatureFlags mFeatureFlags;
     private final InteractionJankMonitor mInteractionJankMonitor;
+    private final ShadeRepository mShadeRepository;
     private final FalsingManager mFalsingManager;
     private final AccessibilityManager mAccessibilityManager;
     private final MetricsLogger mMetricsLogger;
@@ -321,7 +323,8 @@
             FeatureFlags featureFlags,
             InteractionJankMonitor interactionJankMonitor,
             ShadeLogger shadeLog,
-            KeyguardFaceAuthInteractor keyguardFaceAuthInteractor
+            KeyguardFaceAuthInteractor keyguardFaceAuthInteractor,
+            ShadeRepository shadeRepository
     ) {
         mPanelViewControllerLazy = panelViewControllerLazy;
         mPanelView = panelView;
@@ -363,6 +366,7 @@
         mKeyguardFaceAuthInteractor = keyguardFaceAuthInteractor;
         mFeatureFlags = featureFlags;
         mInteractionJankMonitor = interactionJankMonitor;
+        mShadeRepository = shadeRepository;
 
         mLockscreenShadeTransitionController.addCallback(new LockscreenShadeTransitionCallback());
     }
@@ -1001,6 +1005,7 @@
 
         mDepthController.setQsPanelExpansion(qsExpansionFraction);
         mStatusBarKeyguardViewManager.setQsExpansion(qsExpansionFraction);
+        mShadeRepository.setQsExpansion(qsExpansionFraction);
 
         // TODO (b/265193930): remove dependency on NPVC
         float shadeExpandedFraction = mBarState == KEYGUARD
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
index f0815e9..86ae4ec 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
@@ -41,6 +41,7 @@
 import com.android.systemui.animation.ShadeInterpolation
 import com.android.systemui.battery.BatteryMeterView
 import com.android.systemui.battery.BatteryMeterViewController
+import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.demomode.DemoMode
 import com.android.systemui.demomode.DemoModeController
 import com.android.systemui.dump.DumpManager
@@ -52,14 +53,13 @@
 import com.android.systemui.shade.ShadeHeaderController.Companion.LARGE_SCREEN_HEADER_TRANSITION_ID
 import com.android.systemui.shade.ShadeHeaderController.Companion.QQS_HEADER_CONSTRAINT
 import com.android.systemui.shade.ShadeHeaderController.Companion.QS_HEADER_CONSTRAINT
+import com.android.systemui.shade.ShadeModule.Companion.SHADE_HEADER
 import com.android.systemui.shade.carrier.ShadeCarrierGroup
 import com.android.systemui.shade.carrier.ShadeCarrierGroupController
 import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider
 import com.android.systemui.statusbar.phone.StatusBarIconController
 import com.android.systemui.statusbar.phone.StatusBarLocation
 import com.android.systemui.statusbar.phone.StatusIconContainer
-import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent.CentralSurfacesScope
-import com.android.systemui.statusbar.phone.dagger.StatusBarViewModule.SHADE_HEADER
 import com.android.systemui.statusbar.policy.Clock
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.statusbar.policy.NextAlarmController
@@ -79,7 +79,7 @@
  * * [LARGE_SCREEN_HEADER_TRANSITION_ID]: [LARGE_SCREEN_HEADER_CONSTRAINT] for all other
  *   configurations
  */
-@CentralSurfacesScope
+@SysUISingleton
 class ShadeHeaderController
 @Inject
 constructor(
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
index 9cd8c54..b7551cf 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
@@ -16,21 +16,36 @@
 
 package com.android.systemui.shade
 
+import android.content.ContentResolver
+import android.os.Handler
 import android.view.LayoutInflater
+import android.view.ViewStub
+import androidx.constraintlayout.motion.widget.MotionLayout
 import com.android.keyguard.LockIconView
 import com.android.systemui.CoreStartable
 import com.android.systemui.R
+import com.android.systemui.battery.BatteryMeterView
+import com.android.systemui.battery.BatteryMeterViewController
 import com.android.systemui.biometrics.AuthRippleController
 import com.android.systemui.biometrics.AuthRippleView
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.privacy.OngoingPrivacyChip
+import com.android.systemui.settings.UserTracker
 import com.android.systemui.statusbar.LightRevealScrim
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
+import com.android.systemui.statusbar.phone.StatusIconContainer
 import com.android.systemui.statusbar.phone.TapAgainView
+import com.android.systemui.statusbar.policy.BatteryController
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.tuner.TunerService
 import dagger.Binds
 import dagger.Module
 import dagger.Provides
 import dagger.multibindings.ClassKey
 import dagger.multibindings.IntoMap
+import javax.inject.Named
 
 /** Module for classes related to the notification shade. */
 @Module
@@ -42,6 +57,8 @@
     abstract fun bindAuthRippleController(controller: AuthRippleController): CoreStartable
 
     companion object {
+        const val SHADE_HEADER = "large_screen_shade_header"
+
         @Provides
         @SysUISingleton
         // TODO(b/277762009): Do something similar to
@@ -109,5 +126,75 @@
         ): TapAgainView {
             return notificationPanelView.findViewById(R.id.shade_falsing_tap_again)
         }
+
+        // TODO(b/277762009): Only allow this view's controller to inject the view. See above.
+        @Provides
+        @SysUISingleton
+        @Named(SHADE_HEADER)
+        fun providesShadeHeaderView(
+            notificationShadeWindowView: NotificationShadeWindowView,
+        ): MotionLayout {
+            val stub = notificationShadeWindowView.findViewById<ViewStub>(R.id.qs_header_stub)
+            val layoutId = R.layout.combined_qs_header
+            stub.layoutResource = layoutId
+            return stub.inflate() as MotionLayout
+        }
+
+        @Provides
+        @SysUISingleton
+        fun providesCombinedShadeHeadersConstraintManager(): CombinedShadeHeadersConstraintManager {
+            return CombinedShadeHeadersConstraintManagerImpl
+        }
+
+        // TODO(b/277762009): Only allow this view's controller to inject the view. See above.
+        @Provides
+        @SysUISingleton
+        @Named(SHADE_HEADER)
+        fun providesBatteryMeterView(@Named(SHADE_HEADER) view: MotionLayout): BatteryMeterView {
+            return view.findViewById(R.id.batteryRemainingIcon)
+        }
+
+        @Provides
+        @SysUISingleton
+        @Named(SHADE_HEADER)
+        fun providesBatteryMeterViewController(
+            @Named(SHADE_HEADER) batteryMeterView: BatteryMeterView,
+            userTracker: UserTracker,
+            configurationController: ConfigurationController,
+            tunerService: TunerService,
+            @Main mainHandler: Handler,
+            contentResolver: ContentResolver,
+            featureFlags: FeatureFlags,
+            batteryController: BatteryController,
+        ): BatteryMeterViewController {
+            return BatteryMeterViewController(
+                batteryMeterView,
+                userTracker,
+                configurationController,
+                tunerService,
+                mainHandler,
+                contentResolver,
+                featureFlags,
+                batteryController,
+            )
+        }
+
+        @Provides
+        @SysUISingleton
+        @Named(SHADE_HEADER)
+        fun providesOngoingPrivacyChip(
+            @Named(SHADE_HEADER) header: MotionLayout,
+        ): OngoingPrivacyChip {
+            return header.findViewById(R.id.privacy_chip)
+        }
+
+        @Provides
+        @SysUISingleton
+        @Named(SHADE_HEADER)
+        fun providesStatusIconContainer(
+            @Named(SHADE_HEADER) header: MotionLayout,
+        ): StatusIconContainer {
+            return header.findViewById(R.id.statusIcons)
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt
index bf7a2be..44c8e48 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt
@@ -25,11 +25,23 @@
 import javax.inject.Inject
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.flow.distinctUntilChanged
 
 interface ShadeRepository {
     /** ShadeModel information regarding shade expansion events */
     val shadeModel: Flow<ShadeModel>
+
+    /** Amount qs has expanded. Quick Settings can be expanded without the full shade expansion. */
+    val qsExpansion: StateFlow<Float>
+
+    /** Amount shade has expanded with regard to the UDFPS location */
+    val udfpsTransitionToFullShadeProgress: StateFlow<Float>
+
+    fun setQsExpansion(qsExpansion: Float)
+    fun setUdfpsTransitionToFullShadeProgress(progress: Float)
 }
 
 /** Business logic for shade interactions */
@@ -62,6 +74,20 @@
             }
             .distinctUntilChanged()
 
+    private val _qsExpansion = MutableStateFlow(0f)
+    override val qsExpansion: StateFlow<Float> = _qsExpansion.asStateFlow()
+
+    private var _udfpsTransitionToFullShadeProgress = MutableStateFlow(0f)
+    override val udfpsTransitionToFullShadeProgress: StateFlow<Float> =
+        _udfpsTransitionToFullShadeProgress.asStateFlow()
+    override fun setQsExpansion(qsExpansion: Float) {
+        _qsExpansion.value = qsExpansion
+    }
+
+    override fun setUdfpsTransitionToFullShadeProgress(progress: Float) {
+        _udfpsTransitionToFullShadeProgress.value = progress
+    }
+
     companion object {
         private const val TAG = "ShadeRepository"
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LegacyNotificationShelfControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/LegacyNotificationShelfControllerImpl.java
index 4ef2063..505f45d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LegacyNotificationShelfControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LegacyNotificationShelfControllerImpl.java
@@ -52,7 +52,7 @@
         mActivatableNotificationViewController = activatableNotificationViewController;
         mKeyguardBypassController = keyguardBypassController;
         mStatusBarStateController = statusBarStateController;
-        mView.useRoundnessSourceTypes(featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES));
+        mView.useRoundnessSourceTypes(true);
         mView.setSensitiveRevealAnimEndabled(featureFlags.isEnabled(Flags.SENSITIVE_REVEAL_ANIM));
         mOnAttachStateChangeListener = new View.OnAttachStateChangeListener() {
             @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index c5f64b0..7f016f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -32,6 +32,7 @@
 import com.android.systemui.plugins.qs.QS
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.shade.ShadeViewController
+import com.android.systemui.shade.data.repository.ShadeRepository
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.ExpandableView
@@ -74,6 +75,7 @@
     falsingManager: FalsingManager,
     dumpManager: DumpManager,
     qsTransitionControllerFactory: LockscreenShadeQsTransitionController.Factory,
+    private val shadeRepository: ShadeRepository,
 ) : Dumpable {
     private var pulseHeight: Float = 0f
     @get:VisibleForTesting
@@ -449,6 +451,7 @@
         }
 
         val udfpsProgress = MathUtils.saturate(dragDownAmount / udfpsTransitionDistance)
+        shadeRepository.setUdfpsTransitionToFullShadeProgress(udfpsProgress)
         udfpsKeyguardViewController?.setTransitionToFullShadeProgress(udfpsProgress)
 
         val statusBarProgress = MathUtils.saturate(dragDownAmount / statusBarTransitionDistance)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index 9bf05cb..19c612e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -261,8 +261,7 @@
                 mStatusBarStateController.removeCallback(mStatusBarStateListener);
             }
         });
-        mView.useRoundnessSourceTypes(
-                mFeatureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES));
+        mView.useRoundnessSourceTypes(true);
     }
 
     private final StatusBarStateController.StateListener mStatusBarStateListener =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt
index 99c6ddb..8106715 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt
@@ -81,7 +81,7 @@
         ActivatableNotificationViewBinder.bind(viewModel, shelf, falsingManager)
         shelf.apply {
             setRefactorFlagEnabled(true)
-            useRoundnessSourceTypes(featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES))
+            useRoundnessSourceTypes(true)
             setSensitiveRevealAnimEndabled(featureFlags.isEnabled(Flags.SENSITIVE_REVEAL_ANIM))
             // TODO(278765923): Replace with eventual NotificationIconContainerViewBinder#bind()
             notificationIconAreaController.setShelfIcons(shelfIcons)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
index fde8c4d..b6aec83ae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManager.java
@@ -25,8 +25,6 @@
 import com.android.systemui.R;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
 import com.android.systemui.statusbar.notification.LegacySourceType;
 import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
 import com.android.systemui.statusbar.notification.Roundable;
@@ -73,8 +71,7 @@
     NotificationRoundnessManager(
             NotificationSectionsFeatureManager sectionsFeatureManager,
             NotificationRoundnessLogger notifLogger,
-            DumpManager dumpManager,
-            FeatureFlags featureFlags) {
+            DumpManager dumpManager) {
         int numberOfSections = sectionsFeatureManager.getNumberOfBuckets();
         mFirstInSectionViews = new ExpandableView[numberOfSections];
         mLastInSectionViews = new ExpandableView[numberOfSections];
@@ -82,7 +79,7 @@
         mTmpLastInSectionViews = new ExpandableView[numberOfSections];
         mNotifLogger = notifLogger;
         mDumpManager = dumpManager;
-        mUseRoundnessSourceTypes = featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES);
+        mUseRoundnessSourceTypes = true;
 
         mDumpManager.registerDumpable(TAG, this);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
index 070b439..57b6dbc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
@@ -19,8 +19,6 @@
 import android.util.Log
 import android.view.View
 import com.android.internal.annotations.VisibleForTesting
-import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
 import com.android.systemui.media.controls.ui.KeyguardMediaController
 import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
 import com.android.systemui.statusbar.notification.SourceType
@@ -51,11 +49,10 @@
     @IncomingHeader private val incomingHeaderController: SectionHeaderController,
     @PeopleHeader private val peopleHeaderController: SectionHeaderController,
     @AlertingHeader private val alertingHeaderController: SectionHeaderController,
-    @SilentHeader private val silentHeaderController: SectionHeaderController,
-    featureFlags: FeatureFlags
+    @SilentHeader private val silentHeaderController: SectionHeaderController
 ) : SectionProvider {
 
-    private val useRoundnessSourceTypes = featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES)
+    private val useRoundnessSourceTypes = true
 
     private val configurationListener = object : ConfigurationController.ConfigurationListener {
         override fun onLocaleListChanged() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 3bc2066..abcb825 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -625,7 +625,7 @@
         mDebugLines = featureFlags.isEnabled(Flags.NSSL_DEBUG_LINES);
         mDebugRemoveAnimation = featureFlags.isEnabled(Flags.NSSL_DEBUG_REMOVE_ANIMATION);
         mSimplifiedAppearFraction = featureFlags.isEnabled(Flags.SIMPLIFIED_APPEAR_FRACTION);
-        mUseRoundnessSourceTypes = featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES);
+        mUseRoundnessSourceTypes = true;
         mSensitiveRevealAnimEndabled = featureFlags.isEnabled(Flags.SENSITIVE_REVEAL_ANIM);
         setAnimatedInsetsEnabled(featureFlags.isEnabled(Flags.ANIMATED_NOTIFICATION_SHADE_INSETS));
         mSectionsManager = Dependency.get(NotificationSectionsManager.class);
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 4751fb6..d96a2cd 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
@@ -61,7 +61,6 @@
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
 import com.android.systemui.media.controls.ui.KeyguardMediaController;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.FalsingManager;
@@ -126,8 +125,6 @@
 import com.android.systemui.util.Compile;
 import com.android.systemui.util.settings.SecureSettings;
 
-import kotlin.Unit;
-
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Optional;
@@ -723,7 +720,7 @@
         mShadeController = shadeController;
         mNotifIconAreaController = notifIconAreaController;
         mFeatureFlags = featureFlags;
-        mUseRoundnessSourceTypes = featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES);
+        mUseRoundnessSourceTypes = true;
         mNotificationTargetsHelper = notificationTargetsHelper;
         mSecureSettings = secureSettings;
         mDismissibilityProvider = dismissibilityProvider;
@@ -822,7 +819,7 @@
                 mView.generateRemoveAnimation(mKeyguardMediaController.getSinglePaneContainer());
             }
             mView.requestChildrenUpdate();
-            return Unit.INSTANCE;
+            return kotlin.Unit.INSTANCE;
         });
 
         // attach callback, and then call it to update mView immediately
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
index 91f53b6..2d0a6cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
@@ -35,7 +35,6 @@
 import com.android.systemui.SwipeHelper;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
@@ -81,7 +80,7 @@
             NotificationRoundnessManager notificationRoundnessManager) {
         super(callback, resources, viewConfiguration, falsingManager, featureFlags);
         mNotificationRoundnessManager = notificationRoundnessManager;
-        mUseRoundnessSourceTypes = featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES);
+        mUseRoundnessSourceTypes = true;
         mMenuListener = menuListener;
         mCallback = callback;
         mFalsingCheck = () -> resetExposedMenuView(true /* animate */, true /* force */);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelper.kt
index 8b6d6a4f..cd0c1b1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelper.kt
@@ -20,7 +20,7 @@
 constructor(
     featureFlags: FeatureFlags,
 ) {
-    private val useRoundnessSourceTypes = featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES)
+    private val useRoundnessSourceTypes = true
 
     /**
      * This method looks for views that can be rounded (and implement [Roundable]) during a
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index e705afc..0c4821c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -27,8 +27,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.widget.ViewClippingUtil;
 import com.android.systemui.R;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shade.ShadeHeadsUpTracker;
@@ -120,14 +118,13 @@
             NotificationStackScrollLayoutController stackScrollerController,
             ShadeViewController shadeViewController,
             NotificationRoundnessManager notificationRoundnessManager,
-            FeatureFlags featureFlags,
             HeadsUpStatusBarView headsUpStatusBarView,
             Clock clockView,
             @Named(OPERATOR_NAME_FRAME_VIEW) Optional<View> operatorNameViewOptional) {
         super(headsUpStatusBarView);
         mNotificationIconAreaController = notificationIconAreaController;
         mNotificationRoundnessManager = notificationRoundnessManager;
-        mUseRoundnessSourceTypes = featureFlags.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES);
+        mUseRoundnessSourceTypes = true;
         mHeadsUpManager = headsUpManager;
 
         // We may be mid-HUN-expansion when this controller is re-created (for example, if the user
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
index c17366a..74ab47f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
@@ -115,7 +115,9 @@
         val onKeyguard = keyguardUpdateMonitor.isKeyguardVisible &&
                 !statusBarStateController.isDozing
 
-        val shouldListen = (onKeyguard || bouncerVisible) && keyguardUpdateMonitor.isFaceEnrolled
+        val userId = KeyguardUpdateMonitor.getCurrentUser()
+        val isFaceEnabled = keyguardUpdateMonitor.isFaceAuthEnabledForUser(userId)
+        val shouldListen = (onKeyguard || bouncerVisible) && isFaceEnabled
         if (shouldListen != isListening) {
             isListening = shouldListen
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 89dddbf..f2fbd7d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -136,7 +136,7 @@
     private final DreamOverlayStateController mDreamOverlayStateController;
     @Nullable
     private final FoldAodAnimationController mFoldAodAnimationController;
-    private KeyguardMessageAreaController<AuthKeyguardMessageArea> mKeyguardMessageAreaController;
+    KeyguardMessageAreaController<AuthKeyguardMessageArea> mKeyguardMessageAreaController;
     private final PrimaryBouncerCallbackInteractor mPrimaryBouncerCallbackInteractor;
     private final PrimaryBouncerInteractor mPrimaryBouncerInteractor;
     private final AlternateBouncerInteractor mAlternateBouncerInteractor;
@@ -430,6 +430,7 @@
             mDockManager.addListener(mDockEventListener);
             mIsDocked = mDockManager.isDocked();
         }
+        mKeyguardStateController.addCallback(mKeyguardStateControllerCallback);
     }
 
     /** Register a callback, to be invoked by the Predictive Back system. */
@@ -1564,6 +1565,14 @@
                 || mode == KeyguardSecurityModel.SecurityMode.SimPuk;
     }
 
+    private KeyguardStateController.Callback mKeyguardStateControllerCallback =
+            new KeyguardStateController.Callback() {
+        @Override
+        public void onUnlockedChanged() {
+            updateAlternateBouncerShowing(mAlternateBouncerInteractor.maybeHide());
+        }
+    };
+
     /**
      * Delegate used to send show and hide events to an alternate authentication method instead of
      * the regular pin/pattern/password bouncer.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
index 2c57a26..67243b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
@@ -16,26 +16,15 @@
 
 package com.android.systemui.statusbar.phone.dagger;
 
-import android.content.ContentResolver;
-import android.os.Handler;
 import android.view.LayoutInflater;
-import android.view.ViewStub;
-
-import androidx.constraintlayout.motion.widget.MotionLayout;
 
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.R;
-import com.android.systemui.battery.BatteryMeterView;
-import com.android.systemui.battery.BatteryMeterViewController;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.privacy.OngoingPrivacyChip;
-import com.android.systemui.settings.UserTracker;
-import com.android.systemui.shade.CombinedShadeHeadersConstraintManager;
-import com.android.systemui.shade.CombinedShadeHeadersConstraintManagerImpl;
 import com.android.systemui.shade.NotificationPanelView;
 import com.android.systemui.shade.NotificationPanelViewController;
 import com.android.systemui.shade.NotificationShadeWindowView;
@@ -59,17 +48,13 @@
 import com.android.systemui.statusbar.phone.StatusBarHideIconsForBouncerManager;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.phone.StatusBarLocationPublisher;
-import com.android.systemui.statusbar.phone.StatusIconContainer;
 import com.android.systemui.statusbar.phone.SystemBarAttributesListener;
 import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
 import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragmentLogger;
 import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent;
 import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.window.StatusBarWindowStateController;
-import com.android.systemui.tuner.TunerService;
 import com.android.systemui.util.CarrierConfigTracker;
 import com.android.systemui.util.settings.SecureSettings;
 
@@ -90,7 +75,6 @@
         })
 public abstract class StatusBarViewModule {
 
-    public static final String SHADE_HEADER = "large_screen_shade_header";
     public static final String STATUS_BAR_FRAGMENT = "status_bar_fragment";
 
     /** */
@@ -136,76 +120,6 @@
     abstract ShadeViewController bindsShadeViewController(
             NotificationPanelViewController notificationPanelViewController);
 
-    @Provides
-    @Named(SHADE_HEADER)
-    @CentralSurfacesComponent.CentralSurfacesScope
-    public static MotionLayout getLargeScreenShadeHeaderBarView(
-            NotificationShadeWindowView notificationShadeWindowView,
-            FeatureFlags featureFlags) {
-        ViewStub stub = notificationShadeWindowView.findViewById(R.id.qs_header_stub);
-        int layoutId = R.layout.combined_qs_header;
-        stub.setLayoutResource(layoutId);
-        MotionLayout v = (MotionLayout) stub.inflate();
-        return v;
-    }
-
-    /** */
-    @Provides
-    @CentralSurfacesComponent.CentralSurfacesScope
-    public static CombinedShadeHeadersConstraintManager
-            provideCombinedShadeHeadersConstraintManager() {
-        return CombinedShadeHeadersConstraintManagerImpl.INSTANCE;
-    }
-
-    /** */
-    @Provides
-    @CentralSurfacesComponent.CentralSurfacesScope
-    public static OngoingPrivacyChip getSplitShadeOngoingPrivacyChip(
-            @Named(SHADE_HEADER) MotionLayout header) {
-        return header.findViewById(R.id.privacy_chip);
-    }
-
-    /** */
-    @Provides
-    @CentralSurfacesComponent.CentralSurfacesScope
-    static StatusIconContainer providesStatusIconContainer(
-            @Named(SHADE_HEADER) MotionLayout header) {
-        return header.findViewById(R.id.statusIcons);
-    }
-
-    /** */
-    @Provides
-    @CentralSurfacesComponent.CentralSurfacesScope
-    @Named(SHADE_HEADER)
-    static BatteryMeterView getBatteryMeterView(@Named(SHADE_HEADER) MotionLayout view) {
-        return view.findViewById(R.id.batteryRemainingIcon);
-    }
-
-    @Provides
-    @CentralSurfacesComponent.CentralSurfacesScope
-    @Named(SHADE_HEADER)
-    static BatteryMeterViewController getBatteryMeterViewController(
-            @Named(SHADE_HEADER) BatteryMeterView batteryMeterView,
-            UserTracker userTracker,
-            ConfigurationController configurationController,
-            TunerService tunerService,
-            @Main Handler mainHandler,
-            ContentResolver contentResolver,
-            FeatureFlags featureFlags,
-            BatteryController batteryController
-    ) {
-        return new BatteryMeterViewController(
-                batteryMeterView,
-                userTracker,
-                configurationController,
-                tunerService,
-                mainHandler,
-                contentResolver,
-                featureFlags,
-                batteryController);
-
-    }
-
     /** */
     @Provides
     @CentralSurfacesComponent.CentralSurfacesScope
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
index 3d811cf..673819b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -240,7 +240,7 @@
                 || (Build.IS_DEBUGGABLE && DEBUG_AUTH_WITH_ADB && mDebugUnlocked);
         boolean trustManaged = mKeyguardUpdateMonitor.getUserTrustIsManaged(user);
         boolean trusted = mKeyguardUpdateMonitor.getUserHasTrust(user);
-        boolean faceAuthEnabled = mKeyguardUpdateMonitor.isFaceEnrolled();
+        boolean faceAuthEnabled = mKeyguardUpdateMonitor.isFaceAuthEnabledForUser(user);
         boolean changed = secure != mSecure || canDismissLockScreen != mCanDismissLockScreen
                 || trustManaged != mTrustManaged || mTrusted != trusted
                 || mFaceAuthEnabled != faceAuthEnabled;
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 71246c9..2962c14 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -383,7 +383,6 @@
     }
 
     private void setupFingerprintAuth(boolean isClass3) throws RemoteException {
-        when(mAuthController.isFingerprintEnrolled(anyInt())).thenReturn(true);
         when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
         when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
         mFingerprintSensorProperties = List.of(
@@ -2693,42 +2692,33 @@
     }
     @Test
     public void testFingerprintSensorProperties() throws RemoteException {
-        // GIVEN no fingerprint sensor properties
-        when(mAuthController.isFingerprintEnrolled(anyInt())).thenReturn(true);
         mFingerprintAuthenticatorsRegisteredCallback.onAllAuthenticatorsRegistered(
                 new ArrayList<>());
 
-        // THEN fingerprint is not possible
         assertThat(mKeyguardUpdateMonitor.isUnlockWithFingerprintPossible(
                 KeyguardUpdateMonitor.getCurrentUser())).isFalse();
 
-        // WHEN there are fingerprint sensor properties
         mFingerprintAuthenticatorsRegisteredCallback
                 .onAllAuthenticatorsRegistered(mFingerprintSensorProperties);
 
-        // THEN unlock with fp is possible & fingerprint starts listening
+        verifyFingerprintAuthenticateCall();
         assertThat(mKeyguardUpdateMonitor.isUnlockWithFingerprintPossible(
                 KeyguardUpdateMonitor.getCurrentUser())).isTrue();
-        verifyFingerprintAuthenticateCall();
     }
     @Test
     public void testFaceSensorProperties() throws RemoteException {
-        // GIVEN no face sensor properties
-        when(mAuthController.isFaceAuthEnrolled(anyInt())).thenReturn(true);
         mFaceAuthenticatorsRegisteredCallback.onAllAuthenticatorsRegistered(new ArrayList<>());
 
-        // THEN face is not possible
-        assertThat(mKeyguardUpdateMonitor.isUnlockWithFacePossible(
+        assertThat(mKeyguardUpdateMonitor.isFaceAuthEnabledForUser(
                 KeyguardUpdateMonitor.getCurrentUser())).isFalse();
 
-        // WHEN there are face sensor properties
         mFaceAuthenticatorsRegisteredCallback.onAllAuthenticatorsRegistered(mFaceSensorProperties);
+        biometricsEnabledForCurrentUser();
 
-        // THEN face is possible but face does NOT start listening immediately
-        assertThat(mKeyguardUpdateMonitor.isUnlockWithFacePossible(
-                KeyguardUpdateMonitor.getCurrentUser())).isTrue();
         verifyFaceAuthenticateNeverCalled();
         verifyFaceDetectNeverCalled();
+        assertThat(mKeyguardUpdateMonitor.isFaceAuthEnabledForUser(
+                KeyguardUpdateMonitor.getCurrentUser())).isTrue();
     }
 
     @Test
@@ -2801,6 +2791,9 @@
     }
 
     private void mockCanBypassLockscreen(boolean canBypass) {
+        // force update the isFaceEnrolled cache:
+        mKeyguardUpdateMonitor.isFaceAuthEnabledForUser(getCurrentUser());
+
         mKeyguardUpdateMonitor.setKeyguardBypassController(mKeyguardBypassController);
         when(mKeyguardBypassController.canBypass()).thenReturn(canBypass);
     }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/SplitShadeTransitionAdapterTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/SplitShadeTransitionAdapterTest.kt
index dea2082..6fe8892 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/SplitShadeTransitionAdapterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/SplitShadeTransitionAdapterTest.kt
@@ -18,6 +18,7 @@
 import android.animation.Animator
 import android.testing.AndroidTestingRunner
 import android.transition.TransitionValues
+import android.view.View
 import androidx.test.filters.SmallTest
 import com.android.keyguard.KeyguardStatusViewController.SplitShadeTransitionAdapter
 import com.android.systemui.SysuiTestCase
@@ -44,14 +45,16 @@
 
     @Test
     fun createAnimator_nullStartValues_returnsNull() {
-        val animator = adapter.createAnimator(startValues = null, endValues = TransitionValues())
+        val endValues = createEndValues()
+
+        val animator = adapter.createAnimator(startValues = null, endValues = endValues)
 
         assertThat(animator).isNull()
     }
 
     @Test
     fun createAnimator_nullEndValues_returnsNull() {
-        val animator = adapter.createAnimator(startValues = TransitionValues(), endValues = null)
+        val animator = adapter.createAnimator(startValues = createStartValues(), endValues = null)
 
         assertThat(animator).isNull()
     }
@@ -59,10 +62,22 @@
     @Test
     fun createAnimator_nonNullStartAndEndValues_returnsAnimator() {
         val animator =
-            adapter.createAnimator(startValues = TransitionValues(), endValues = TransitionValues())
+            adapter.createAnimator(startValues = createStartValues(), endValues = createEndValues())
 
         assertThat(animator).isNotNull()
     }
+
+    private fun createStartValues() =
+        TransitionValues().also { values ->
+            values.view = View(context)
+            adapter.captureStartValues(values)
+        }
+
+    private fun createEndValues() =
+        TransitionValues().also { values ->
+            values.view = View(context)
+            adapter.captureEndValues(values)
+        }
 }
 
 private fun SplitShadeTransitionAdapter.createAnimator(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/OWNERS b/packages/SystemUI/tests/src/com/android/systemui/accessibility/OWNERS
new file mode 100644
index 0000000..a2001e6
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/view/accessibility/OWNERS
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/SystemActionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/SystemActionsTest.java
new file mode 100644
index 0000000..025c88c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/SystemActionsTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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.accessibility;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.hardware.input.InputManager;
+import android.os.RemoteException;
+import android.telecom.TelecomManager;
+import android.telephony.TelephonyManager;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.KeyEvent;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.settings.FakeDisplayTracker;
+import com.android.systemui.settings.UserTracker;
+import com.android.systemui.shade.ShadeController;
+import com.android.systemui.statusbar.NotificationShadeWindowController;
+import com.android.systemui.statusbar.phone.CentralSurfaces;
+
+import dagger.Lazy;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+@TestableLooper.RunWithLooper
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class SystemActionsTest extends SysuiTestCase {
+    @Mock
+    private UserTracker mUserTracker;
+    @Mock
+    private NotificationShadeWindowController mNotificationShadeController;
+    @Mock
+    private ShadeController mShadeController;
+    @Mock
+    private Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy;
+    @Mock
+    private Optional<Recents> mRecentsOptional;
+    @Mock
+    private TelecomManager mTelecomManager;
+    @Mock
+    private InputManager mInputManager;
+    private final FakeDisplayTracker mDisplayTracker = new FakeDisplayTracker(mContext);
+
+    private SystemActions mSystemActions;
+
+    @Before
+    public void setUp() throws RemoteException {
+        MockitoAnnotations.initMocks(this);
+        mContext.addMockSystemService(TelecomManager.class, mTelecomManager);
+        mContext.addMockSystemService(InputManager.class, mInputManager);
+        mSystemActions = new SystemActions(mContext, mUserTracker, mNotificationShadeController,
+                mShadeController, mCentralSurfacesOptionalLazy, mRecentsOptional, mDisplayTracker);
+    }
+
+    @Test
+    public void handleHeadsetHook_callStateIdle_injectsKeyEvents() {
+        when(mTelecomManager.getCallState()).thenReturn(TelephonyManager.CALL_STATE_IDLE);
+        // Use a custom doAnswer captor that copies the KeyEvent before storing it, because the
+        // method under test modifies the event object after injecting it which prevents
+        // reliably asserting on the event properties.
+        final List<KeyEvent> keyEvents = new ArrayList<>();
+        doAnswer(invocation -> {
+            keyEvents.add(new KeyEvent(invocation.getArgument(0)));
+            return null;
+        }).when(mInputManager).injectInputEvent(any(), anyInt());
+
+        mSystemActions.handleHeadsetHook();
+
+        assertThat(keyEvents.size()).isEqualTo(2);
+        assertThat(keyEvents.get(0).getKeyCode()).isEqualTo(KeyEvent.KEYCODE_HEADSETHOOK);
+        assertThat(keyEvents.get(0).getAction()).isEqualTo(KeyEvent.ACTION_DOWN);
+        assertThat(keyEvents.get(1).getKeyCode()).isEqualTo(KeyEvent.KEYCODE_HEADSETHOOK);
+        assertThat(keyEvents.get(1).getAction()).isEqualTo(KeyEvent.ACTION_UP);
+    }
+
+    @Test
+    public void handleHeadsetHook_callStateRinging_answersCall() {
+        when(mTelecomManager.getCallState()).thenReturn(TelephonyManager.CALL_STATE_RINGING);
+
+        mSystemActions.handleHeadsetHook();
+
+        verify(mTelecomManager).acceptRingingCall();
+    }
+
+    @Test
+    public void handleHeadsetHook_callStateOffhook_endsCall() {
+        when(mTelecomManager.getCallState()).thenReturn(TelephonyManager.CALL_STATE_OFFHOOK);
+
+        mSystemActions.handleHeadsetHook();
+
+        verify(mTelecomManager).endCall();
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
index 578e1d4..cc00436 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
@@ -159,22 +159,11 @@
     @Test
     fun doesNotStartIfAnimationIsCancelled() {
         val runner = activityLaunchAnimator.createRunner(controller)
-        runner.onAnimationCancelled(false /* isKeyguardOccluded */)
+        runner.onAnimationCancelled()
         runner.onAnimationStart(0, emptyArray(), emptyArray(), emptyArray(), iCallback)
 
         waitForIdleSync()
-        verify(controller).onLaunchAnimationCancelled(false /* newKeyguardOccludedState */)
-        verify(controller, never()).onLaunchAnimationStart(anyBoolean())
-    }
-
-    @Test
-    fun passesOccludedStateToLaunchAnimationCancelled_ifTrue() {
-        val runner = activityLaunchAnimator.createRunner(controller)
-        runner.onAnimationCancelled(true /* isKeyguardOccluded */)
-        runner.onAnimationStart(0, emptyArray(), emptyArray(), emptyArray(), iCallback)
-
-        waitForIdleSync()
-        verify(controller).onLaunchAnimationCancelled(true /* newKeyguardOccludedState */)
+        verify(controller).onLaunchAnimationCancelled()
         verify(controller, never()).onLaunchAnimationStart(anyBoolean())
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt
index ebbe096..26cbd77 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt
@@ -41,11 +41,11 @@
 import org.mockito.Captor
 import org.mockito.Mock
 import org.mockito.Mockito
-import org.mockito.Mockito.`when`
 import org.mockito.Mockito.mock
 import org.mockito.Mockito.never
 import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
 import org.mockito.MockitoAnnotations
 
 @SmallTest
@@ -378,7 +378,13 @@
     executor: DelayableExecutor,
     lazyController: Lazy<ControlsController>,
     userTracker: UserTracker
-) : ControlsBindingControllerImpl(context, executor, lazyController, userTracker) {
+) : ControlsBindingControllerImpl(
+    context,
+    executor,
+    lazyController,
+    mock(PackageUpdateMonitor.Factory::class.java),
+    userTracker
+) {
 
     companion object {
         val providers = mutableListOf<ControlsProviderLifecycleManager>()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt
index da548f7..b5d3476 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt
@@ -30,6 +30,10 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.time.FakeSystemClock
 import org.junit.After
 import org.junit.Assert.assertEquals
@@ -39,17 +43,17 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.ArgumentCaptor
-import org.mockito.ArgumentMatchers
-import org.mockito.ArgumentMatchers.any
 import org.mockito.ArgumentMatchers.anyString
-import org.mockito.ArgumentMatchers.eq
 import org.mockito.Captor
 import org.mockito.Mock
-import org.mockito.Mockito.`when`
 import org.mockito.Mockito.anyInt
-import org.mockito.Mockito.mock
+import org.mockito.Mockito.clearInvocations
+import org.mockito.Mockito.inOrder
 import org.mockito.Mockito.never
+import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyNoMoreInteractions
+import org.mockito.Mockito.`when`
 import org.mockito.MockitoAnnotations
 
 @SmallTest
@@ -62,16 +66,21 @@
     private lateinit var subscriberService: IControlsSubscriber.Stub
     @Mock
     private lateinit var service: IControlsProvider.Stub
-
+    @Mock
+    private lateinit var packageUpdateMonitor: PackageUpdateMonitor
     @Captor
     private lateinit var wrapperCaptor: ArgumentCaptor<ControlActionWrapper>
 
+    private lateinit var packageUpdateMonitorFactory: FakePackageUpdateMonitorFactory
+
     private val componentName = ComponentName("test.pkg", "test.cls")
     private lateinit var manager: ControlsProviderLifecycleManager
     private lateinit var executor: FakeExecutor
+    private lateinit var fakeSystemClock: FakeSystemClock
 
     companion object {
         fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
+        private val USER = UserHandle.of(0)
     }
 
     @Before
@@ -79,16 +88,20 @@
         MockitoAnnotations.initMocks(this)
 
         context.addMockService(componentName, service)
-        executor = FakeExecutor(FakeSystemClock())
+        fakeSystemClock = FakeSystemClock()
+        executor = FakeExecutor(fakeSystemClock)
         `when`(service.asBinder()).thenCallRealMethod()
-        `when`(service.queryLocalInterface(ArgumentMatchers.anyString())).thenReturn(service)
+        `when`(service.queryLocalInterface(anyString())).thenReturn(service)
+
+        packageUpdateMonitorFactory = FakePackageUpdateMonitorFactory(packageUpdateMonitor)
 
         manager = ControlsProviderLifecycleManager(
                 context,
                 executor,
                 actionCallbackService,
-                UserHandle.of(0),
-                componentName
+                USER,
+                componentName,
+                packageUpdateMonitorFactory,
         )
     }
 
@@ -122,7 +135,7 @@
 
     @Test
     fun testNullBinding() {
-        val mockContext = mock(Context::class.java)
+        val mockContext = mock<Context>()
         lateinit var serviceConnection: ServiceConnection
         `when`(mockContext.bindServiceAsUser(any(), any(), anyInt(), any())).thenAnswer {
             val component = (it.arguments[0] as Intent).component
@@ -139,8 +152,9 @@
                 mockContext,
                 executor,
                 actionCallbackService,
-                UserHandle.of(0),
-                componentName
+                USER,
+                componentName,
+                packageUpdateMonitorFactory,
         )
 
         nullManager.bindService()
@@ -229,14 +243,15 @@
 
     @Test
     fun testFalseBindCallsUnbind() {
-        val falseContext = mock(Context::class.java)
+        val falseContext = mock<Context>()
         `when`(falseContext.bindServiceAsUser(any(), any(), anyInt(), any())).thenReturn(false)
         val manager = ControlsProviderLifecycleManager(
             falseContext,
             executor,
             actionCallbackService,
-            UserHandle.of(0),
-            componentName
+            USER,
+            componentName,
+            packageUpdateMonitorFactory,
         )
         manager.bindService()
         executor.runAllReady()
@@ -247,4 +262,150 @@
         verify(falseContext).bindServiceAsUser(any(), captor.capture(), anyInt(), any())
         verify(falseContext).unbindService(captor.value)
     }
+
+    @Test
+    fun testPackageUpdateMonitor_createdWithCorrectValues() {
+        assertEquals(USER, packageUpdateMonitorFactory.lastUser)
+        assertEquals(componentName.packageName, packageUpdateMonitorFactory.lastPackage)
+    }
+
+    @Test
+    fun testBound_packageMonitorStartsMonitoring() {
+        manager.bindService()
+        executor.runAllReady()
+
+        // Service will connect and monitoring should start
+        verify(packageUpdateMonitor).startMonitoring()
+    }
+
+    @Test
+    fun testOnPackageUpdateWhileBound_unbound_thenBindAgain() {
+        val mockContext = mock<Context> {
+            `when`(bindServiceAsUser(any(), any(), anyInt(), any())).thenReturn(true)
+        }
+
+        val manager = ControlsProviderLifecycleManager(
+            mockContext,
+            executor,
+            actionCallbackService,
+            USER,
+            componentName,
+            packageUpdateMonitorFactory,
+        )
+
+        manager.bindService()
+        executor.runAllReady()
+        clearInvocations(mockContext)
+
+        packageUpdateMonitorFactory.lastCallback?.run()
+        executor.runAllReady()
+
+        val inOrder = inOrder(mockContext)
+        inOrder.verify(mockContext).unbindService(any())
+        inOrder.verify(mockContext).bindServiceAsUser(any(), any(), anyInt(), any())
+    }
+
+    @Test
+    fun testOnPackageUpdateWhenNotBound_nothingHappens() {
+        val mockContext = mock<Context> {
+            `when`(bindServiceAsUser(any(), any(), anyInt(), any())).thenReturn(true)
+        }
+
+        ControlsProviderLifecycleManager(
+            mockContext,
+            executor,
+            actionCallbackService,
+            USER,
+            componentName,
+            packageUpdateMonitorFactory,
+        )
+
+        packageUpdateMonitorFactory.lastCallback?.run()
+        verifyNoMoreInteractions(mockContext)
+    }
+
+    @Test
+    fun testUnbindService_stopsTracking() {
+        manager.bindService()
+        manager.unbindService()
+        executor.runAllReady()
+
+        verify(packageUpdateMonitor).stopMonitoring()
+    }
+
+    @Test
+    fun testRebindForPanelWithSameFlags() {
+        val mockContext = mock<Context> {
+            `when`(bindServiceAsUser(any(), any(), anyInt(), any())).thenReturn(true)
+        }
+
+        val manager = ControlsProviderLifecycleManager(
+            mockContext,
+            executor,
+            actionCallbackService,
+            USER,
+            componentName,
+            packageUpdateMonitorFactory,
+        )
+
+        manager.bindServiceForPanel()
+        executor.runAllReady()
+
+        val flagsCaptor = argumentCaptor<Int>()
+        verify(mockContext).bindServiceAsUser(any(), any(), capture(flagsCaptor), any())
+        clearInvocations(mockContext)
+
+        packageUpdateMonitorFactory.lastCallback?.run()
+        executor.runAllReady()
+
+        verify(mockContext).bindServiceAsUser(any(), any(), eq(flagsCaptor.value), any())
+    }
+
+    @Test
+    fun testBindAfterSecurityExceptionWorks() {
+        val mockContext = mock<Context> {
+            `when`(bindServiceAsUser(any(), any(), anyInt(), any()))
+                .thenThrow(SecurityException("exception"))
+        }
+
+        val manager = ControlsProviderLifecycleManager(
+            mockContext,
+            executor,
+            actionCallbackService,
+            USER,
+            componentName,
+            packageUpdateMonitorFactory,
+        )
+
+        manager.bindServiceForPanel()
+        executor.runAllReady()
+
+        `when`(mockContext.bindServiceAsUser(any(), any(), anyInt(), any())).thenReturn(true)
+
+        manager.bindServiceForPanel()
+        executor.runAllReady()
+
+        verify(mockContext, times(2)).bindServiceAsUser(any(), any(), anyInt(), any())
+    }
+
+    private class FakePackageUpdateMonitorFactory(
+        private val monitor: PackageUpdateMonitor
+    ) : PackageUpdateMonitor.Factory {
+
+        var lastUser: UserHandle? = null
+        var lastPackage: String? = null
+        var lastCallback: Runnable? = null
+
+        override fun create(
+            user: UserHandle,
+            packageName: String,
+            callback: Runnable
+        ): PackageUpdateMonitor {
+            lastUser = user
+            lastPackage = packageName
+            lastCallback = callback
+            return monitor
+        }
+    }
 }
+
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/PackageUpdateMonitorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/PackageUpdateMonitorTest.kt
new file mode 100644
index 0000000..6954710
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/PackageUpdateMonitorTest.kt
@@ -0,0 +1,114 @@
+/*
+ * 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.controls.controller
+
+import android.content.Context
+import android.os.Handler
+import android.os.UserHandle
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.mock
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.clearInvocations
+import org.mockito.Mockito.never
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyNoMoreInteractions
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class PackageUpdateMonitorTest : SysuiTestCase() {
+
+    @Mock private lateinit var context: Context
+    @Mock private lateinit var bgHandler: Handler
+
+    private lateinit var underTest: PackageUpdateMonitor
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+    }
+
+    @Test
+    fun startMonitoring_registerOnlyOnce() {
+        underTest = PackageUpdateMonitor(USER, PACKAGE, {}, bgHandler, context)
+
+        underTest.startMonitoring()
+        // There are two receivers registered
+        verify(context, times(2))
+            .registerReceiverAsUser(any(), eq(USER), any(), eq(null), eq(bgHandler))
+
+        underTest.startMonitoring()
+        verifyNoMoreInteractions(context)
+    }
+
+    @Test
+    fun stopMonitoring_unregistersOnlyOnce() {
+        underTest = PackageUpdateMonitor(USER, PACKAGE, {}, bgHandler, context)
+
+        underTest.startMonitoring()
+        clearInvocations(context)
+
+        underTest.stopMonitoring()
+        verify(context).unregisterReceiver(any())
+
+        underTest.stopMonitoring()
+        verifyNoMoreInteractions(context)
+    }
+
+    @Test
+    fun onPackageUpdated_correctPackageAndUser_callbackRuns() {
+        val callback = mock<Runnable>()
+
+        underTest = PackageUpdateMonitor(USER, PACKAGE, callback, bgHandler, context)
+
+        underTest.onPackageUpdateFinished(PACKAGE, UserHandle.getUid(USER.identifier, 10000))
+        verify(callback).run()
+    }
+
+    @Test
+    fun onPackageUpdated_correctPackage_wrongUser_callbackDoesntRun() {
+        val callback = mock<Runnable>()
+
+        underTest = PackageUpdateMonitor(USER, PACKAGE, callback, bgHandler, context)
+
+        underTest.onPackageUpdateFinished(PACKAGE, UserHandle.getUid(USER.identifier + 1, 10000))
+        verify(callback, never()).run()
+    }
+
+    @Test
+    fun onPackageUpdated_wrongPackage_correctUser_callbackDoesntRun() {
+        val callback = mock<Runnable>()
+
+        underTest = PackageUpdateMonitor(USER, PACKAGE, callback, bgHandler, context)
+
+        underTest.onPackageUpdateFinished("bad", UserHandle.getUid(USER.identifier + 1, 10000))
+        verify(callback, never()).run()
+    }
+
+    companion object {
+        private val USER = UserHandle.of(0)
+        private val PACKAGE = "pkg"
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
index b7c6246..039682c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
@@ -24,6 +24,7 @@
 import org.mockito.ArgumentCaptor
 import org.mockito.Mock
 import org.mockito.Mockito.anyLong
+import org.mockito.Mockito.atLeastOnce
 import org.mockito.Mockito.eq
 import org.mockito.Mockito.never
 import org.mockito.Mockito.times
@@ -49,6 +50,7 @@
     @Mock private lateinit var stateController: DreamOverlayStateController
     @Mock private lateinit var configController: ConfigurationController
     @Mock private lateinit var transitionViewModel: DreamingToLockscreenTransitionViewModel
+    @Mock private lateinit var logger: DreamLogger
     private lateinit var controller: DreamOverlayAnimationsController
 
     @Before
@@ -67,6 +69,7 @@
                 DREAM_IN_COMPLICATIONS_ANIMATION_DURATION,
                 DREAM_IN_TRANSLATION_Y_DISTANCE,
                 DREAM_IN_TRANSLATION_Y_DURATION,
+                logger
             )
 
         val mockView: View = mock()
@@ -82,9 +85,9 @@
         verify(stateController).setExitAnimationsRunning(true)
 
         val captor = argumentCaptor<Animator.AnimatorListener>()
-        verify(mockAnimator).addListener(captor.capture())
+        verify(mockAnimator, atLeastOnce()).addListener(captor.capture())
 
-        captor.value.onAnimationEnd(mockAnimator)
+        captor.allValues.forEach { it.onAnimationEnd(mockAnimator) }
         verify(stateController).setExitAnimationsRunning(false)
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt
index 6f9dedf..fae6375 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryTest.kt
@@ -18,9 +18,12 @@
 package com.android.systemui.keyboard.data.repository
 
 import android.hardware.input.InputManager
+import android.hardware.input.InputManager.KeyboardBacklightListener
+import android.hardware.input.KeyboardBacklightState
 import android.view.InputDevice
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.FlowValue
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.mock
@@ -29,9 +32,11 @@
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.first
 import kotlinx.coroutines.test.StandardTestDispatcher
 import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Test
@@ -50,6 +55,7 @@
 
     @Captor
     private lateinit var deviceListenerCaptor: ArgumentCaptor<InputManager.InputDeviceListener>
+    @Captor private lateinit var backlightListenerCaptor: ArgumentCaptor<KeyboardBacklightListener>
     @Mock private lateinit var inputManager: InputManager
 
     private lateinit var underTest: KeyboardRepository
@@ -174,7 +180,71 @@
 
     @Test
     fun passesKeyboardBacklightValues_fromBacklightListener() {
-        // TODO(b/268645734): implement when implementing backlight listener
+        testScope.runTest {
+            // we want to capture backlight listener but this can only be done after Flow is
+            // subscribed to and listener is actually registered in inputManager
+            val backlight by collectLastValueImmediately(underTest.backlight)
+
+            verify(inputManager)
+                .registerKeyboardBacklightListener(any(), backlightListenerCaptor.capture())
+
+            backlightListenerCaptor.value.onBacklightChanged(current = 1, max = 5)
+
+            assertThat(backlight?.level).isEqualTo(1)
+            assertThat(backlight?.maxLevel).isEqualTo(5)
+        }
+    }
+
+    private fun <T> TestScope.collectLastValueImmediately(flow: Flow<T>): FlowValue<T?> {
+        val lastValue = collectLastValue(flow)
+        // runCurrent() makes us wait for collect that happens in collectLastValue and ensures
+        // Flow is initialized
+        runCurrent()
+        return lastValue
+    }
+
+    @Test
+    fun keyboardBacklightValuesNotPassed_fromBacklightListener_whenNotTriggeredByKeyPress() {
+        testScope.runTest() {
+            val backlight by collectLastValueImmediately(underTest.backlight)
+            verify(inputManager)
+                .registerKeyboardBacklightListener(any(), backlightListenerCaptor.capture())
+
+            backlightListenerCaptor.value.onBacklightChanged(
+                current = 1,
+                max = 5,
+                triggeredByKeyPress = false
+            )
+            assertThat(backlight).isNull()
+        }
+    }
+
+    @Test
+    fun passesKeyboardBacklightValues_fromBacklightListener_whenTriggeredByKeyPress() {
+        testScope.runTest() {
+            val backlight by collectLastValueImmediately(underTest.backlight)
+            verify(inputManager)
+                .registerKeyboardBacklightListener(any(), backlightListenerCaptor.capture())
+
+            backlightListenerCaptor.value.onBacklightChanged(
+                current = 1,
+                max = 5,
+                triggeredByKeyPress = true
+            )
+            assertThat(backlight).isNotNull()
+        }
+    }
+
+    private fun KeyboardBacklightListener.onBacklightChanged(
+        current: Int,
+        max: Int,
+        triggeredByKeyPress: Boolean = true
+    ) {
+        onKeyboardBacklightChanged(
+            /* deviceId= */ 0,
+            TestBacklightState(current, max),
+            triggeredByKeyPress
+        )
     }
 
     private companion object {
@@ -199,4 +269,12 @@
                 whenever(it.isFullKeyboard).thenReturn(fullKeyboard)
             }
     }
+
+    private class TestBacklightState(
+        private val brightnessLevel: Int,
+        private val maxBrightnessLevel: Int
+    ) : KeyboardBacklightState() {
+        override fun getBrightnessLevel() = brightnessLevel
+        override fun getMaxBrightnessLevel() = maxBrightnessLevel
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
index b46d996..f8cb408 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
@@ -19,7 +19,6 @@
 
 import androidx.test.filters.SmallTest
 import com.android.systemui.R
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.controls.ControlsServiceInfo
 import com.android.systemui.controls.controller.ControlsController
@@ -46,7 +45,6 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RoboPilotTest
 @RunWith(Parameterized::class)
 class HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest : SysuiTestCase() {
 
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 b50cf73..1d0b58a 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
@@ -67,6 +67,7 @@
 import com.android.systemui.user.data.repository.FakeUserRepository
 import com.android.systemui.util.mockito.KotlinArgumentCaptor
 import com.android.systemui.util.mockito.captureMany
+import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
 import com.android.systemui.util.time.FakeSystemClock
 import com.android.systemui.util.time.SystemClock
@@ -193,8 +194,24 @@
         bypassControllerOverride: KeyguardBypassController? = bypassController
     ): DeviceEntryFaceAuthRepositoryImpl {
         val systemClock = FakeSystemClock()
-        val faceAuthBuffer = TableLogBuffer(10, "face auth", systemClock)
-        val faceDetectBuffer = TableLogBuffer(10, "face detect", systemClock)
+        val faceAuthBuffer =
+            TableLogBuffer(
+                10,
+                "face auth",
+                systemClock,
+                mock(),
+                testDispatcher,
+                testScope.backgroundScope
+            )
+        val faceDetectBuffer =
+            TableLogBuffer(
+                10,
+                "face detect",
+                systemClock,
+                mock(),
+                testDispatcher,
+                testScope.backgroundScope
+            )
         keyguardTransitionRepository = FakeKeyguardTransitionRepository()
         val keyguardTransitionInteractor =
             KeyguardTransitionInteractor(keyguardTransitionRepository)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
index f4d2843..d0bfaa9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
@@ -23,7 +23,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.SmallTest
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.Interpolators
 import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -48,7 +47,6 @@
 import org.junit.runner.RunWith
 
 @SmallTest
-@RoboPilotTest
 @RunWith(AndroidJUnit4::class)
 @FlakyTest(bugId = 270760395)
 class KeyguardTransitionRepositoryTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/table/FakeLogProxy.kt b/packages/SystemUI/tests/src/com/android/systemui/log/table/FakeLogProxy.kt
new file mode 100644
index 0000000..471c461
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/log/table/FakeLogProxy.kt
@@ -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.systemui.log.table
+
+/**
+ * Fake [LogProxy] that collects all lines sent to it. Mimics the ADB logcat format without the
+ * timestamp. [FakeLogProxy.d] will write a log like so:
+ * ```
+ * logger.d("TAG", "message here")
+ * // writes this to the [logs] field
+ * "D TAG: message here"
+ * ```
+ *
+ * Logs sent to this class are collected as a list of strings for simple test assertions.
+ */
+class FakeLogProxy : LogProxy {
+    val logs: MutableList<String> = mutableListOf()
+
+    override fun v(tag: String, message: String) {
+        logs.add("V $tag: $message")
+    }
+
+    override fun d(tag: String, message: String) {
+        logs.add("D $tag: $message")
+    }
+
+    override fun i(tag: String, message: String) {
+        logs.add("I $tag: $message")
+    }
+
+    override fun w(tag: String, message: String) {
+        logs.add("W $tag: $message")
+    }
+
+    override fun e(tag: String, message: String) {
+        logs.add("E $tag: $message")
+    }
+
+    override fun wtf(tag: String, message: String) {
+        logs.add("WTF $tag: $message")
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/table/LogDiffsForTableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/log/table/LogDiffsForTableTest.kt
index c49337a..1d182cf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/log/table/LogDiffsForTableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/log/table/LogDiffsForTableTest.kt
@@ -19,6 +19,7 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.log.table.TableChange.Companion.IS_INITIAL_PREFIX
+import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
 import java.io.PrintWriter
@@ -39,7 +40,8 @@
 @OptIn(ExperimentalCoroutinesApi::class)
 class LogDiffsForTableTest : SysuiTestCase() {
 
-    private val testScope = TestScope(UnconfinedTestDispatcher())
+    private val testDispatcher = UnconfinedTestDispatcher()
+    private val testScope = TestScope(testDispatcher)
 
     private lateinit var systemClock: FakeSystemClock
     private lateinit var tableLogBuffer: TableLogBuffer
@@ -47,7 +49,15 @@
     @Before
     fun setUp() {
         systemClock = FakeSystemClock()
-        tableLogBuffer = TableLogBuffer(MAX_SIZE, BUFFER_NAME, systemClock)
+        tableLogBuffer =
+            TableLogBuffer(
+                MAX_SIZE,
+                BUFFER_NAME,
+                systemClock,
+                mock(),
+                testDispatcher,
+                testScope.backgroundScope,
+            )
     }
 
     // ---- Flow<Boolean> tests ----
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferFactoryTest.kt
index af83a56..8ba7643 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferFactoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferFactoryTest.kt
@@ -22,13 +22,20 @@
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import org.junit.Test
 
+@OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
 class TableLogBufferFactoryTest : SysuiTestCase() {
     private val dumpManager: DumpManager = mock()
     private val systemClock = FakeSystemClock()
-    private val underTest = TableLogBufferFactory(dumpManager, systemClock)
+    private val testDispatcher = UnconfinedTestDispatcher()
+    private val testScope = TestScope(testDispatcher)
+    private val underTest =
+        TableLogBufferFactory(dumpManager, systemClock, mock(), testDispatcher, testScope)
 
     @Test
     fun create_alwaysCreatesNewInstance() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt
index aed830a..a2b2322 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt
@@ -19,31 +19,66 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.log.table.TableChange.Companion.IS_INITIAL_PREFIX
+import com.android.systemui.plugins.log.LogLevel
+import com.android.systemui.plugins.log.LogcatEchoTracker
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
 import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
 import java.io.PrintWriter
 import java.io.StringWriter
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import org.junit.Before
 import org.junit.Test
 
+@OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
 class TableLogBufferTest : SysuiTestCase() {
     private lateinit var underTest: TableLogBuffer
 
     private lateinit var systemClock: FakeSystemClock
     private lateinit var outputWriter: StringWriter
+    private lateinit var logcatEchoTracker: LogcatEchoTracker
+    private lateinit var localLogcat: FakeLogProxy
+
+    private val testDispatcher = UnconfinedTestDispatcher()
+    private val testScope = TestScope(testDispatcher)
 
     @Before
     fun setup() {
+        localLogcat = FakeLogProxy()
+        logcatEchoTracker = mock()
         systemClock = FakeSystemClock()
         outputWriter = StringWriter()
 
-        underTest = TableLogBuffer(MAX_SIZE, NAME, systemClock)
+        underTest =
+            TableLogBuffer(
+                MAX_SIZE,
+                NAME,
+                systemClock,
+                logcatEchoTracker,
+                testDispatcher,
+                testScope.backgroundScope,
+                localLogcat = localLogcat,
+            )
+        underTest.init()
     }
 
     @Test(expected = IllegalArgumentException::class)
     fun maxSizeZero_throwsException() {
-        TableLogBuffer(maxSize = 0, "name", systemClock)
+        TableLogBuffer(
+            maxSize = 0,
+            "name",
+            systemClock,
+            logcatEchoTracker,
+            testDispatcher,
+            testScope.backgroundScope,
+            localLogcat = localLogcat,
+        )
     }
 
     @Test
@@ -791,6 +826,112 @@
         assertThat(dumpedString).contains(evictedColumnLog3)
     }
 
+    @Test
+    fun logcat_bufferNotLoggable_tagNotLoggable_noEcho() {
+        whenever(logcatEchoTracker.isBufferLoggable(eq(NAME), any())).thenReturn(false)
+        whenever(logcatEchoTracker.isTagLoggable(eq("columnName"), any())).thenReturn(false)
+
+        underTest.logChange("prefix", "columnName", true)
+
+        assertThat(localLogcat.logs).isEmpty()
+    }
+
+    @Test
+    fun logcat_bufferIsLoggable_tagNotLoggable_echoes() {
+        whenever(logcatEchoTracker.isBufferLoggable(eq(NAME), any())).thenReturn(true)
+        whenever(logcatEchoTracker.isTagLoggable(eq("columnName"), any())).thenReturn(false)
+
+        underTest.logChange("prefix", "columnName", true)
+
+        assertThat(localLogcat.logs).hasSize(1)
+    }
+
+    @Test
+    fun logcat_bufferNotLoggable_tagIsLoggable_echoes() {
+        whenever(logcatEchoTracker.isBufferLoggable(eq(NAME), any())).thenReturn(false)
+        whenever(logcatEchoTracker.isTagLoggable(eq("columnName"), any())).thenReturn(true)
+
+        underTest.logChange("prefix", "columnName", true)
+
+        assertThat(localLogcat.logs).hasSize(1)
+    }
+
+    @Test
+    fun logcat_echoesDebugLogs_debugDisabled_noEcho() {
+        // Allow any log other than debug
+        whenever(logcatEchoTracker.isBufferLoggable(eq(NAME), any())).thenAnswer { invocation ->
+            (invocation.getArgument(1) as LogLevel) != LogLevel.DEBUG
+        }
+
+        underTest.logChange("prefix", "columnName", true)
+
+        assertThat(localLogcat.logs).isEmpty()
+    }
+
+    @Test
+    fun logcat_echoesDebugLogs_debugEnabled_echoes() {
+        // Only allow debug logs
+        whenever(logcatEchoTracker.isBufferLoggable(eq(NAME), eq(LogLevel.DEBUG))).thenReturn(true)
+
+        underTest.logChange("prefix", "columnName", true)
+
+        assertThat(localLogcat.logs).hasSize(1)
+    }
+
+    @Test
+    fun logcat_bufferNotLoggable_tagIsLoggable_usesColNameForTagCheck() {
+        systemClock.setCurrentTimeMillis(1000L)
+
+        val nonLoggingTag = "nonLoggingColName"
+        val loggingTag = "loggingColName"
+
+        whenever(logcatEchoTracker.isBufferLoggable(eq(NAME), any())).thenReturn(false)
+        whenever(logcatEchoTracker.isTagLoggable(eq(loggingTag), eq(LogLevel.DEBUG)))
+            .thenReturn(true)
+        whenever(logcatEchoTracker.isTagLoggable(eq(nonLoggingTag), eq(LogLevel.DEBUG)))
+            .thenReturn(false)
+
+        underTest.logChange("", nonLoggingTag, true)
+        underTest.logChange("", loggingTag, true)
+
+        assertThat(localLogcat.logs).hasSize(1)
+
+        val timestamp = TABLE_LOG_DATE_FORMAT.format(1000L)
+        val expectedMessage = "${timestamp}${SEPARATOR}${loggingTag}${SEPARATOR}true"
+        val expectedLine = "D $NAME: $expectedMessage"
+
+        assertThat(localLogcat.logs[0]).isEqualTo(expectedLine)
+    }
+
+    @Test
+    fun logcat_bufferLoggable_multipleMessagesAreEchoed() {
+        systemClock.setCurrentTimeMillis(1000L)
+        whenever(logcatEchoTracker.isBufferLoggable(eq(NAME), any())).thenReturn(true)
+
+        val col1 = "column1"
+        val col2 = "column2"
+
+        // Log a couple of columns that flip bits
+        underTest.logChange("", col1, true)
+        underTest.logChange("", col2, false)
+        underTest.logChange("", col1, false)
+        underTest.logChange("", col2, true)
+
+        assertThat(localLogcat.logs).hasSize(4)
+
+        val timestamp = TABLE_LOG_DATE_FORMAT.format(1000L)
+        val msg1 = "${timestamp}${SEPARATOR}${col1}${SEPARATOR}true"
+        val msg2 = "${timestamp}${SEPARATOR}${col2}${SEPARATOR}false"
+        val msg3 = "${timestamp}${SEPARATOR}${col1}${SEPARATOR}false"
+        val msg4 = "${timestamp}${SEPARATOR}${col2}${SEPARATOR}true"
+        val expected = listOf(msg1, msg2, msg3, msg4).map { "D $NAME: $it" }
+
+        // Logs use the same bg dispatcher for writing to logcat, they should be in order
+        for ((msg, logLine) in expected zip localLogcat.logs) {
+            assertThat(logLine).isEqualTo(msg)
+        }
+    }
+
     private fun dumpChanges(): String {
         underTest.dump(PrintWriter(outputWriter), arrayOf())
         return outputWriter.toString()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDeviceManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDeviceManagerTest.kt
index a45e9d9..0c57e7b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDeviceManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDeviceManagerTest.kt
@@ -468,7 +468,7 @@
     }
 
     @Test
-    fun audioInfoChanged() {
+    fun audioInfoPlaybackTypeChanged() {
         whenever(playbackInfo.getPlaybackType()).thenReturn(PlaybackInfo.PLAYBACK_TYPE_LOCAL)
         whenever(controller.getPlaybackInfo()).thenReturn(playbackInfo)
         // GIVEN a controller with local playback type
@@ -486,6 +486,25 @@
     }
 
     @Test
+    fun audioInfoVolumeControlIdChanged() {
+        whenever(playbackInfo.getPlaybackType()).thenReturn(PlaybackInfo.PLAYBACK_TYPE_LOCAL)
+        whenever(playbackInfo.getVolumeControlId()).thenReturn(null)
+        whenever(controller.getPlaybackInfo()).thenReturn(playbackInfo)
+        // GIVEN a controller with local playback type
+        manager.onMediaDataLoaded(KEY, null, mediaData)
+        fakeBgExecutor.runAllReady()
+        fakeFgExecutor.runAllReady()
+        reset(mr2)
+        // WHEN onAudioInfoChanged fires with a volume control id change
+        whenever(playbackInfo.getVolumeControlId()).thenReturn("placeholder id")
+        val captor = ArgumentCaptor.forClass(MediaController.Callback::class.java)
+        verify(controller).registerCallback(captor.capture())
+        captor.value.onAudioInfoChanged(playbackInfo)
+        // THEN the route is checked
+        verify(mr2).getRoutingSessionForMediaController(eq(controller))
+    }
+
+    @Test
     fun audioInfoHasntChanged() {
         whenever(playbackInfo.getPlaybackType()).thenReturn(PlaybackInfo.PLAYBACK_TYPE_REMOTE)
         whenever(controller.getPlaybackInfo()).thenReturn(playbackInfo)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
index 745f094..07f7c15 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
@@ -19,6 +19,7 @@
 import android.app.PendingIntent
 import android.content.res.ColorStateList
 import android.content.res.Configuration
+import android.os.LocaleList
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.util.MathUtils.abs
@@ -56,6 +57,7 @@
 import com.android.systemui.util.mockito.capture
 import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.time.FakeSystemClock
+import java.util.Locale
 import javax.inject.Provider
 import junit.framework.Assert.assertEquals
 import junit.framework.Assert.assertFalse
@@ -71,6 +73,7 @@
 import org.mockito.Mock
 import org.mockito.Mockito.floatThat
 import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
 import org.mockito.Mockito.reset
 import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
@@ -123,6 +126,7 @@
     @Before
     fun setup() {
         MockitoAnnotations.initMocks(this)
+        context.resources.configuration.locales = LocaleList(Locale.US, Locale.UK)
         transitionRepository = FakeKeyguardTransitionRepository()
         mediaCarouselController =
             MediaCarouselController(
@@ -713,6 +717,23 @@
     }
 
     @Test
+    fun testOnLocaleListChanged_playersAreAddedBack() {
+        context.resources.configuration.locales = LocaleList(Locale.US, Locale.UK, Locale.CANADA)
+        testConfigurationChange(configListener.value::onLocaleListChanged)
+
+        verify(pageIndicator, never()).tintList =
+            ColorStateList.valueOf(context.getColor(R.color.media_paging_indicator))
+
+        context.resources.configuration.locales = LocaleList(Locale.UK, Locale.US, Locale.CANADA)
+        testConfigurationChange(configListener.value::onLocaleListChanged)
+
+        verify(pageIndicator).tintList =
+            ColorStateList.valueOf(context.getColor(R.color.media_paging_indicator))
+        // When recreateMedia is set to true, page indicator is updated on removal and addition.
+        verify(pageIndicator, times(4)).setNumPages(any())
+    }
+
+    @Test
     fun testRecommendation_persistentEnabled_newSmartspaceLoaded_updatesSort() {
         testRecommendation_persistentEnabled_inactiveSmartspaceDataLoaded_isAdded()
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
index 0bdcaf4..299303d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
@@ -19,6 +19,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
@@ -33,7 +34,12 @@
 
 import android.app.KeyguardManager;
 import android.app.Notification;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
 import android.media.AudioDeviceAttributes;
 import android.media.AudioManager;
@@ -44,6 +50,7 @@
 import android.media.RoutingSessionInfo;
 import android.media.session.MediaController;
 import android.media.session.MediaSessionManager;
+import android.media.session.PlaybackState;
 import android.os.PowerExemptionManager;
 import android.os.RemoteException;
 import android.service.notification.StatusBarNotification;
@@ -74,6 +81,9 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -93,29 +103,54 @@
     private static final String TEST_SONG = "test_song";
     private static final String TEST_SESSION_ID = "test_session_id";
     private static final String TEST_SESSION_NAME = "test_session_name";
-    private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
-    private final ActivityLaunchAnimator.Controller mActivityLaunchAnimatorController = mock(
-            ActivityLaunchAnimator.Controller.class);
-    private final NearbyMediaDevicesManager mNearbyMediaDevicesManager = mock(
-            NearbyMediaDevicesManager.class);
+    @Mock
+    private DialogLaunchAnimator mDialogLaunchAnimator;
+    @Mock
+    private ActivityLaunchAnimator.Controller mActivityLaunchAnimatorController;
+    @Mock
+    private NearbyMediaDevicesManager mNearbyMediaDevicesManager;
     // Mock
-    private MediaController mMediaController = mock(MediaController.class);
-    private MediaSessionManager mMediaSessionManager = mock(MediaSessionManager.class);
-    private CachedBluetoothDeviceManager mCachedBluetoothDeviceManager =
-            mock(CachedBluetoothDeviceManager.class);
-    private LocalBluetoothManager mLocalBluetoothManager = mock(LocalBluetoothManager.class);
-    private MediaOutputController.Callback mCb = mock(MediaOutputController.Callback.class);
-    private MediaDevice mMediaDevice1 = mock(MediaDevice.class);
-    private MediaDevice mMediaDevice2 = mock(MediaDevice.class);
-    private NearbyDevice mNearbyDevice1 = mock(NearbyDevice.class);
-    private NearbyDevice mNearbyDevice2 = mock(NearbyDevice.class);
-    private MediaMetadata mMediaMetadata = mock(MediaMetadata.class);
-    private RoutingSessionInfo mRemoteSessionInfo = mock(RoutingSessionInfo.class);
-    private ActivityStarter mStarter = mock(ActivityStarter.class);
-    private AudioManager mAudioManager = mock(AudioManager.class);
-    private KeyguardManager mKeyguardManager = mock(KeyguardManager.class);
-    private PowerExemptionManager mPowerExemptionManager = mock(PowerExemptionManager.class);
-    private CommonNotifCollection mNotifCollection = mock(CommonNotifCollection.class);
+    @Mock
+    private MediaController mMediaController;
+    @Mock
+    private MediaSessionManager mMediaSessionManager;
+    @Mock
+    private CachedBluetoothDeviceManager mCachedBluetoothDeviceManager;
+    @Mock
+    private LocalBluetoothManager mLocalBluetoothManager;
+    @Mock
+    private MediaOutputController.Callback mCb;
+    @Mock
+    private MediaDevice mMediaDevice1;
+    @Mock
+    private MediaDevice mMediaDevice2;
+    @Mock
+    private NearbyDevice mNearbyDevice1;
+    @Mock
+    private NearbyDevice mNearbyDevice2;
+    @Mock
+    private MediaMetadata mMediaMetadata;
+    @Mock
+    private RoutingSessionInfo mRemoteSessionInfo;
+    @Mock
+    private ActivityStarter mStarter;
+    @Mock
+    private AudioManager mAudioManager;
+    @Mock
+    private KeyguardManager mKeyguardManager;
+    @Mock
+    private ActivityLaunchAnimator.Controller mController;
+    @Mock
+    private PowerExemptionManager mPowerExemptionManager;
+    @Mock
+    private CommonNotifCollection mNotifCollection;
+    @Mock
+    private PackageManager mPackageManager;
+    @Mock
+    private Drawable mDrawable;
+    @Mock
+    private PlaybackState mPlaybackState;
+
     private FeatureFlags mFlags = mock(FeatureFlags.class);
     private View mDialogLaunchView = mock(View.class);
     private MediaOutputController.Callback mCallback = mock(MediaOutputController.Callback.class);
@@ -131,8 +166,11 @@
 
     @Before
     public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext.setMockPackageManager(mPackageManager);
         mSpyContext = spy(mContext);
         when(mMediaController.getPackageName()).thenReturn(TEST_PACKAGE_NAME);
+        when(mMediaController.getPlaybackState()).thenReturn(mPlaybackState);
         mMediaControllers.add(mMediaController);
         when(mMediaSessionManager.getActiveSessions(any())).thenReturn(mMediaControllers);
         doReturn(mMediaSessionManager).when(mSpyContext).getSystemService(
@@ -258,6 +296,34 @@
     }
 
     @Test
+    public void tryToLaunchMediaApplication_intentNotNull_startActivity() {
+        when(mDialogLaunchAnimator.createActivityLaunchController(any(View.class))).thenReturn(
+                mController);
+        Intent intent = new Intent(TEST_PACKAGE_NAME);
+        doReturn(intent).when(mPackageManager).getLaunchIntentForPackage(TEST_PACKAGE_NAME);
+        mMediaOutputController.start(mCallback);
+
+        mMediaOutputController.tryToLaunchMediaApplication(mDialogLaunchView);
+
+        verify(mStarter).startActivity(any(Intent.class), anyBoolean(),
+                Mockito.eq(mController));
+    }
+
+    @Test
+    public void tryToLaunchInAppRoutingIntent_componentNameNotNull_startActivity() {
+        when(mDialogLaunchAnimator.createActivityLaunchController(any(View.class))).thenReturn(
+                mController);
+        mMediaOutputController.start(mCallback);
+        when(mLocalMediaManager.getLinkedItemComponentName()).thenReturn(
+                new ComponentName(TEST_PACKAGE_NAME, ""));
+
+        mMediaOutputController.tryToLaunchInAppRoutingIntent(TEST_DEVICE_1_ID, mDialogLaunchView);
+
+        verify(mStarter).startActivity(any(Intent.class), anyBoolean(),
+                Mockito.eq(mController));
+    }
+
+    @Test
     public void onDevicesUpdated_unregistersNearbyDevicesCallback() throws RemoteException {
         mMediaOutputController.start(mCb);
 
@@ -342,6 +408,30 @@
     }
 
     @Test
+    public void advanced_onDeviceListUpdateWithConnectedDeviceRemote_verifyItemSize() {
+        when(mFlags.isEnabled(Flags.OUTPUT_SWITCHER_ADVANCED_LAYOUT)).thenReturn(true);
+        when(mMediaDevice1.getFeatures()).thenReturn(
+                ImmutableList.of(MediaRoute2Info.FEATURE_REMOTE_PLAYBACK));
+        when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mMediaDevice1);
+        mMediaOutputController.start(mCb);
+        reset(mCb);
+
+        mMediaOutputController.onDeviceListUpdate(mMediaDevices);
+        final List<MediaDevice> devices = new ArrayList<>();
+        for (MediaItem item : mMediaOutputController.getMediaItemList()) {
+            if (item.getMediaDevice().isPresent()) {
+                devices.add(item.getMediaDevice().get());
+            }
+        }
+
+        assertThat(devices.containsAll(mMediaDevices)).isTrue();
+        assertThat(devices.size()).isEqualTo(mMediaDevices.size());
+        assertThat(mMediaOutputController.getMediaItemList().size()).isEqualTo(
+                mMediaDevices.size() + 1);
+        verify(mCb).onDeviceListChanged();
+    }
+
+    @Test
     public void advanced_categorizeMediaItems_withSuggestedDevice_verifyDeviceListSize() {
         when(mFlags.isEnabled(Flags.OUTPUT_SWITCHER_ADVANCED_LAYOUT)).thenReturn(true);
         when(mMediaDevice1.isSuggestedDevice()).thenReturn(true);
@@ -582,6 +672,17 @@
     }
 
     @Test
+    public void isAnyDeviceTransferring_advancedLayoutSupport() {
+        when(mFlags.isEnabled(Flags.OUTPUT_SWITCHER_ADVANCED_LAYOUT)).thenReturn(true);
+        when(mMediaDevice1.getState()).thenReturn(
+                LocalMediaManager.MediaDeviceState.STATE_CONNECTING);
+        mMediaOutputController.start(mCb);
+        mMediaOutputController.onDeviceListUpdate(mMediaDevices);
+
+        assertThat(mMediaOutputController.isAnyDeviceTransferring()).isTrue();
+    }
+
+    @Test
     public void isPlaying_stateIsNull() {
         when(mMediaController.getPlaybackState()).thenReturn(null);
 
@@ -661,22 +762,6 @@
     }
 
     @Test
-    public void connectDevice_verifyConnect() {
-        when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mMediaDevice2);
-
-        mMediaOutputController.connectDevice(mMediaDevice1);
-
-        // Wait for background thread execution
-        try {
-            Thread.sleep(100);
-        } catch (InterruptedException e) {
-            e.printStackTrace();
-        }
-
-        verify(mLocalMediaManager).connectDevice(mMediaDevice1);
-    }
-
-    @Test
     public void getActiveRemoteMediaDevice_isSystemSession_returnSession() {
         when(mRemoteSessionInfo.getId()).thenReturn(TEST_SESSION_ID);
         when(mRemoteSessionInfo.getName()).thenReturn(TEST_SESSION_NAME);
@@ -883,6 +968,56 @@
     }
 
     @Test
+    public void getDeviceIconCompat_deviceIconIsNotNull_returnsIcon() {
+        when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mMediaDevice2);
+        when(mMediaDevice1.getIcon()).thenReturn(mDrawable);
+
+        assertThat(mMediaOutputController.getDeviceIconCompat(mMediaDevice1)).isInstanceOf(
+                IconCompat.class);
+    }
+
+    @Test
+    public void getDeviceIconCompat_deviceIconIsNull_returnsIcon() {
+        when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mMediaDevice2);
+        when(mMediaDevice1.getIcon()).thenReturn(null);
+
+        assertThat(mMediaOutputController.getDeviceIconCompat(mMediaDevice1)).isInstanceOf(
+                IconCompat.class);
+    }
+
+    @Test
+    public void setColorFilter_setColorFilterToDrawable() {
+        mMediaOutputController.setColorFilter(mDrawable, true);
+
+        verify(mDrawable).setColorFilter(any(PorterDuffColorFilter.class));
+    }
+
+    @Test
+    public void resetGroupMediaDevices_clearGroupDevices() {
+        final MediaDevice selectedMediaDevice1 = mock(MediaDevice.class);
+        final MediaDevice selectedMediaDevice2 = mock(MediaDevice.class);
+        final MediaDevice selectableMediaDevice1 = mock(MediaDevice.class);
+        final MediaDevice selectableMediaDevice2 = mock(MediaDevice.class);
+        final List<MediaDevice> selectedMediaDevices = new ArrayList<>();
+        final List<MediaDevice> selectableMediaDevices = new ArrayList<>();
+        when(selectedMediaDevice1.getId()).thenReturn(TEST_DEVICE_1_ID);
+        when(selectedMediaDevice2.getId()).thenReturn(TEST_DEVICE_2_ID);
+        when(selectableMediaDevice1.getId()).thenReturn(TEST_DEVICE_3_ID);
+        when(selectableMediaDevice2.getId()).thenReturn(TEST_DEVICE_4_ID);
+        selectedMediaDevices.add(selectedMediaDevice1);
+        selectedMediaDevices.add(selectedMediaDevice2);
+        selectableMediaDevices.add(selectableMediaDevice1);
+        selectableMediaDevices.add(selectableMediaDevice2);
+        doReturn(selectedMediaDevices).when(mLocalMediaManager).getSelectedMediaDevice();
+        doReturn(selectableMediaDevices).when(mLocalMediaManager).getSelectableMediaDevice();
+        assertThat(mMediaOutputController.getGroupMediaDevices().isEmpty()).isFalse();
+
+        mMediaOutputController.resetGroupMediaDevices();
+
+        assertThat(mMediaOutputController.mGroupMediaDevices.isEmpty()).isTrue();
+    }
+
+    @Test
     public void isVolumeControlEnabled_isCastWithVolumeFixed_returnsFalse() {
         when(mMediaDevice1.getDeviceType()).thenReturn(
                 MediaDevice.MediaDeviceType.TYPE_CAST_DEVICE);
@@ -919,6 +1054,42 @@
     }
 
     @Test
+    public void setTemporaryAllowListExceptionIfNeeded_packageNameIsNull_NoAction() {
+        MediaOutputController testMediaOutputController = new MediaOutputController(mSpyContext,
+                null,
+                mMediaSessionManager, mLocalBluetoothManager, mStarter,
+                mNotifCollection, mDialogLaunchAnimator,
+                Optional.of(mNearbyMediaDevicesManager), mAudioManager, mPowerExemptionManager,
+                mKeyguardManager, mFlags);
+
+        testMediaOutputController.setTemporaryAllowListExceptionIfNeeded(mMediaDevice2);
+
+        verify(mPowerExemptionManager, never()).addToTemporaryAllowList(anyString(), anyInt(),
+                anyString(),
+                anyLong());
+    }
+
+    @Test
+    public void onMetadataChanged_triggersOnMetadataChanged() {
+        mMediaOutputController.mCallback = this.mCallback;
+
+        mMediaOutputController.mCb.onMetadataChanged(mMediaMetadata);
+
+        verify(mMediaOutputController.mCallback).onMediaChanged();
+    }
+
+    @Test
+    public void onPlaybackStateChanged_updateWithNullState_onMediaStoppedOrPaused() {
+        when(mPlaybackState.getState()).thenReturn(PlaybackState.STATE_PLAYING);
+        mMediaOutputController.mCallback = this.mCallback;
+        mMediaOutputController.start(mCb);
+
+        mMediaOutputController.mCb.onPlaybackStateChanged(null);
+
+        verify(mMediaOutputController.mCallback).onMediaStoppedOrPaused();
+    }
+
+    @Test
     public void launchBluetoothPairing_isKeyguardLocked_dismissDialog() {
         when(mDialogLaunchAnimator.createActivityLaunchController(mDialogLaunchView)).thenReturn(
                 mActivityLaunchAnimatorController);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
index 55f221d..5dbcd33 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt
@@ -45,8 +45,8 @@
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.notetask.NoteTaskController.Companion.EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE
+import com.android.systemui.notetask.NoteTaskController.Companion.SETTINGS_CREATE_NOTE_TASK_SHORTCUT_COMPONENT
 import com.android.systemui.notetask.NoteTaskController.Companion.SHORTCUT_ID
-import com.android.systemui.notetask.shortcut.CreateNoteTaskShortcutActivity
 import com.android.systemui.notetask.shortcut.LaunchNoteTaskActivity
 import com.android.systemui.notetask.shortcut.LaunchNoteTaskManagedProfileProxyActivity
 import com.android.systemui.settings.FakeUserTracker
@@ -423,8 +423,8 @@
                 eq(COMPONENT_ENABLED_STATE_ENABLED),
                 eq(PackageManager.DONT_KILL_APP),
             )
-        assertThat(argument.value.className)
-            .isEqualTo(CreateNoteTaskShortcutActivity::class.java.name)
+
+        assertThat(argument.value).isEqualTo(SETTINGS_CREATE_NOTE_TASK_SHORTCUT_COMPONENT)
     }
 
     @Test
@@ -438,8 +438,7 @@
                 eq(COMPONENT_ENABLED_STATE_DISABLED),
                 eq(PackageManager.DONT_KILL_APP),
             )
-        assertThat(argument.value.className)
-            .isEqualTo(CreateNoteTaskShortcutActivity::class.java.name)
+        assertThat(argument.value).isEqualTo(SETTINGS_CREATE_NOTE_TASK_SHORTCUT_COMPONENT)
     }
 
     @Test
@@ -458,8 +457,7 @@
                 eq(COMPONENT_ENABLED_STATE_ENABLED),
                 eq(PackageManager.DONT_KILL_APP),
             )
-        assertThat(argument.value.className)
-            .isEqualTo(CreateNoteTaskShortcutActivity::class.java.name)
+        assertThat(argument.value).isEqualTo(SETTINGS_CREATE_NOTE_TASK_SHORTCUT_COMPONENT)
     }
 
     @Test
@@ -479,8 +477,7 @@
                 eq(COMPONENT_ENABLED_STATE_DISABLED),
                 eq(PackageManager.DONT_KILL_APP),
             )
-        assertThat(argument.value.className)
-            .isEqualTo(CreateNoteTaskShortcutActivity::class.java.name)
+        assertThat(argument.value).isEqualTo(SETTINGS_CREATE_NOTE_TASK_SHORTCUT_COMPONENT)
     }
     // endregion
 
@@ -664,8 +661,7 @@
                 eq(COMPONENT_ENABLED_STATE_ENABLED),
                 eq(PackageManager.DONT_KILL_APP),
             )
-        assertThat(actualComponent.value.className)
-            .isEqualTo(CreateNoteTaskShortcutActivity::class.java.name)
+        assertThat(actualComponent.value).isEqualTo(SETTINGS_CREATE_NOTE_TASK_SHORTCUT_COMPONENT)
         verify(shortcutManager, never()).disableShortcuts(any())
         verify(shortcutManager).enableShortcuts(listOf(SHORTCUT_ID))
         val actualShortcuts = argumentCaptor<List<ShortcutInfo>>()
@@ -696,8 +692,7 @@
                 eq(COMPONENT_ENABLED_STATE_DISABLED),
                 eq(PackageManager.DONT_KILL_APP),
             )
-        assertThat(argument.value.className)
-            .isEqualTo(CreateNoteTaskShortcutActivity::class.java.name)
+        assertThat(argument.value).isEqualTo(SETTINGS_CREATE_NOTE_TASK_SHORTCUT_COMPONENT)
         verify(shortcutManager).disableShortcuts(listOf(SHORTCUT_ID))
         verify(shortcutManager, never()).enableShortcuts(any())
         verify(shortcutManager, never()).updateShortcuts(any())
@@ -714,8 +709,7 @@
                 eq(COMPONENT_ENABLED_STATE_DISABLED),
                 eq(PackageManager.DONT_KILL_APP),
             )
-        assertThat(argument.value.className)
-            .isEqualTo(CreateNoteTaskShortcutActivity::class.java.name)
+        assertThat(argument.value).isEqualTo(SETTINGS_CREATE_NOTE_TASK_SHORTCUT_COMPONENT)
         verify(shortcutManager).disableShortcuts(listOf(SHORTCUT_ID))
         verify(shortcutManager, never()).enableShortcuts(any())
         verify(shortcutManager, never()).updateShortcuts(any())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index f870631..1edc63c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -115,6 +115,7 @@
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.qs.QSFragment;
 import com.android.systemui.screenrecord.RecordingController;
+import com.android.systemui.shade.data.repository.ShadeRepository;
 import com.android.systemui.shade.transition.ShadeTransitionController;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.KeyguardIndicationController;
@@ -304,6 +305,7 @@
             mEmptySpaceClickListenerCaptor;
     @Mock protected ActivityStarter mActivityStarter;
     @Mock protected KeyguardFaceAuthInteractor mKeyguardFaceAuthInteractor;
+    @Mock protected ShadeRepository mShadeRepository;
 
     protected final int mMaxUdfpsBurnInOffsetY = 5;
     protected KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor;
@@ -672,7 +674,8 @@
                 mFeatureFlags,
                 mInteractionJankMonitor,
                 mShadeLog,
-                mKeyguardFaceAuthInteractor
+                mKeyguardFaceAuthInteractor,
+                mShadeRepository
         );
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerTest.java
index 908f7cb..8a9161e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerTest.java
@@ -69,6 +69,7 @@
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.qs.QSFragment;
 import com.android.systemui.screenrecord.RecordingController;
+import com.android.systemui.shade.data.repository.ShadeRepository;
 import com.android.systemui.shade.transition.ShadeTransitionController;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -88,6 +89,8 @@
 import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
+import dagger.Lazy;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -98,8 +101,6 @@
 
 import java.util.List;
 
-import dagger.Lazy;
-
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
@@ -241,7 +242,8 @@
                 mFeatureFlags,
                 mInteractionJankMonitor,
                 mShadeLogger,
-                mock(KeyguardFaceAuthInteractor.class)
+                mock(KeyguardFaceAuthInteractor.class),
+                mock(ShadeRepository.class)
         );
 
         mFragmentListener = mQsController.getQsFragmentListener();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
new file mode 100644
index 0000000..8f2c93b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
@@ -0,0 +1,133 @@
+/*
+ * 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.shade.data.repository
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.RoboPilotTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.shade.ShadeExpansionChangeEvent
+import com.android.systemui.shade.ShadeExpansionStateManager
+import com.android.systemui.shade.domain.model.ShadeModel
+import com.android.systemui.util.mockito.withArgCaptor
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RoboPilotTest
+@RunWith(AndroidJUnit4::class)
+class ShadeRepositoryImplTest : SysuiTestCase() {
+
+    @Mock private lateinit var shadeExpansionStateManager: ShadeExpansionStateManager
+    private val testDispatcher = StandardTestDispatcher()
+    private val testScope = TestScope(testDispatcher)
+
+    private lateinit var underTest: ShadeRepositoryImpl
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        underTest = ShadeRepositoryImpl(shadeExpansionStateManager)
+    }
+
+    @Test
+    fun shadeExpansionChangeEvent() =
+        testScope.runTest {
+            var latest: ShadeModel? = null
+            val job = underTest.shadeModel.onEach { latest = it }.launchIn(this)
+            runCurrent()
+            assertThat(latest?.expansionAmount).isEqualTo(0f)
+            assertThat(latest?.isExpanded).isEqualTo(false)
+            assertThat(latest?.isUserDragging).isEqualTo(false)
+
+            val captor = withArgCaptor {
+                verify(shadeExpansionStateManager).addExpansionListener(capture())
+            }
+
+            captor.onPanelExpansionChanged(
+                ShadeExpansionChangeEvent(
+                    fraction = 1f,
+                    expanded = true,
+                    tracking = false,
+                    dragDownPxAmount = 0f,
+                )
+            )
+            runCurrent()
+            assertThat(latest?.expansionAmount).isEqualTo(1f)
+            assertThat(latest?.isExpanded).isEqualTo(true)
+            assertThat(latest?.isUserDragging).isEqualTo(false)
+
+            captor.onPanelExpansionChanged(
+                ShadeExpansionChangeEvent(
+                    fraction = .67f,
+                    expanded = false,
+                    tracking = true,
+                    dragDownPxAmount = 0f,
+                )
+            )
+            runCurrent()
+            assertThat(latest?.expansionAmount).isEqualTo(.67f)
+            assertThat(latest?.isExpanded).isEqualTo(false)
+            assertThat(latest?.isUserDragging).isEqualTo(true)
+
+            job.cancel()
+        }
+
+    @Test
+    fun updateQsExpansion() =
+        testScope.runTest {
+            assertThat(underTest.qsExpansion.value).isEqualTo(0f)
+
+            underTest.setQsExpansion(.5f)
+            assertThat(underTest.qsExpansion.value).isEqualTo(.5f)
+
+            underTest.setQsExpansion(.82f)
+            assertThat(underTest.qsExpansion.value).isEqualTo(.82f)
+
+            underTest.setQsExpansion(1f)
+            assertThat(underTest.qsExpansion.value).isEqualTo(1f)
+        }
+
+    @Test
+    fun updateUdfpsTransitionToFullShadeProgress() =
+        testScope.runTest {
+            assertThat(underTest.udfpsTransitionToFullShadeProgress.value).isEqualTo(0f)
+
+            underTest.setUdfpsTransitionToFullShadeProgress(.5f)
+            assertThat(underTest.udfpsTransitionToFullShadeProgress.value).isEqualTo(.5f)
+
+            underTest.setUdfpsTransitionToFullShadeProgress(.82f)
+            assertThat(underTest.udfpsTransitionToFullShadeProgress.value).isEqualTo(.82f)
+
+            underTest.setUdfpsTransitionToFullShadeProgress(1f)
+            assertThat(underTest.udfpsTransitionToFullShadeProgress.value).isEqualTo(1f)
+        }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
index 78f5bf2..eef4470 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
@@ -43,6 +43,8 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when` as whenever
 import org.mockito.junit.MockitoJUnit
@@ -172,7 +174,7 @@
     }
 
     @Test
-    fun clockIdConflict_ErrorWithoutCrash() {
+    fun clockIdConflict_ErrorWithoutCrash_unloadDuplicate() {
         val mockPluginLifecycle1 = mock<PluginLifecycleManager<ClockProviderPlugin>>()
         val plugin1 = FakeClockPlugin()
             .addClock("clock_1", "clock 1", { mockClock }, { mockThumbnail })
@@ -199,6 +201,8 @@
         assertEquals(registry.createExampleClock("clock_2"), mockClock)
         assertEquals(registry.getClockThumbnail("clock_1"), mockThumbnail)
         assertEquals(registry.getClockThumbnail("clock_2"), mockThumbnail)
+        verify(mockPluginLifecycle1, never()).unloadPlugin()
+        verify(mockPluginLifecycle2, times(2)).unloadPlugin()
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
index 2106da8..2351f760 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -15,6 +15,7 @@
 import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.plugins.qs.QS
 import com.android.systemui.shade.ShadeViewController
+import com.android.systemui.shade.data.repository.FakeShadeRepository
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper
 import com.android.systemui.statusbar.notification.stack.AmbientState
@@ -127,6 +128,7 @@
                 },
                 qsTransitionControllerFactory = { qsTransitionController },
                 activityStarter = activityStarter,
+                shadeRepository = FakeShadeRepository(),
             )
         transitionController.addCallback(transitionControllerCallback)
         whenever(nsslController.view).thenReturn(stackscroller)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java
deleted file mode 100644
index bd0a556..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- * Copyright (C) 2018 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.stack;
-
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.atLeast;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.res.Resources;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.testing.TestableLooper.RunWithLooper;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.logging.NotificationRoundnessLogger;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.row.ExpandableView;
-import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
-import com.android.systemui.util.DeviceConfigProxy;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.MockitoAnnotations;
-
-import java.util.HashSet;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@RunWithLooper
-public class NotificationRoundnessManagerTest extends SysuiTestCase {
-
-    private NotificationRoundnessManager mRoundnessManager;
-    private HashSet<ExpandableView> mAnimatedChildren = new HashSet<>();
-    private Runnable mRoundnessCallback = mock(Runnable.class);
-    private ExpandableNotificationRow mFirst;
-    private ExpandableNotificationRow mSecond;
-    private NotificationRoundnessLogger mLogger = mock(NotificationRoundnessLogger.class);
-    private float mSmallRadiusRatio;
-
-    @Before
-    public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        final Resources resources = mContext.getResources();
-        mSmallRadiusRatio = resources.getDimension(R.dimen.notification_corner_radius_small)
-                / resources.getDimension(R.dimen.notification_corner_radius);
-        mRoundnessManager = new NotificationRoundnessManager(
-                new NotificationSectionsFeatureManager(new DeviceConfigProxy(), mContext),
-                mLogger,
-                mock(DumpManager.class),
-                mock(FeatureFlags.class));
-        allowTestableLooperAsMainThread();
-        NotificationTestHelper testHelper = new NotificationTestHelper(
-                mContext,
-                mDependency,
-                TestableLooper.get(this));
-        mFirst = testHelper.createRow();
-        mFirst.setHeadsUpAnimatingAwayListener(animatingAway
-                -> mRoundnessManager.updateView(mFirst, false));
-        mSecond = testHelper.createRow();
-        mSecond.setHeadsUpAnimatingAwayListener(animatingAway
-                -> mRoundnessManager.updateView(mSecond, false));
-        mRoundnessManager.setOnRoundingChangedCallback(mRoundnessCallback);
-        mRoundnessManager.setAnimatedChildren(mAnimatedChildren);
-        mRoundnessManager.updateRoundedChildren(new NotificationSection[]{
-                createSection(mFirst, mFirst),
-                createSection(null, null)
-        });
-        mRoundnessManager.setExpanded(1.0f, 1.0f);
-        mRoundnessManager.setShouldRoundPulsingViews(true);
-        reset(mRoundnessCallback);
-    }
-
-    @Test
-    public void testCallbackCalledWhenSecondChanged() {
-        mRoundnessManager.updateRoundedChildren(new NotificationSection[]{
-                createSection(mFirst, mSecond),
-                createSection(null, null)
-        });
-        verify(mRoundnessCallback, atLeast(1)).run();
-    }
-
-    @Test
-    public void testCallbackCalledWhenFirstChanged() {
-        mRoundnessManager.updateRoundedChildren(new NotificationSection[]{
-                createSection(mSecond, mFirst),
-                createSection(null, null)
-        });
-        verify(mRoundnessCallback, atLeast(1)).run();
-    }
-
-    @Test
-    public void testCallbackCalledWhenSecondSectionFirstChanged() {
-        mRoundnessManager.updateRoundedChildren(new NotificationSection[]{
-                createSection(mFirst, mFirst),
-                createSection(mSecond, null)
-        });
-        verify(mRoundnessCallback, atLeast(1)).run();
-    }
-
-    @Test
-    public void testCallbackCalledWhenSecondSectionLastChanged() {
-        mRoundnessManager.updateRoundedChildren(new NotificationSection[]{
-                createSection(mFirst, mFirst),
-                createSection(null, mSecond)
-        });
-        verify(mRoundnessCallback, atLeast(1)).run();
-    }
-
-    @Test
-    public void testCallbackNotCalledWhenFirstChangesSections() {
-        mRoundnessManager.updateRoundedChildren(new NotificationSection[]{
-                createSection(null, mFirst),
-                createSection(mFirst, null)
-        });
-        verify(mRoundnessCallback, never()).run();
-    }
-
-    @Test
-    public void testRoundnessSetOnLast() {
-        mRoundnessManager.updateRoundedChildren(new NotificationSection[]{
-                createSection(mFirst, mSecond),
-                createSection(null, null)
-        });
-        Assert.assertEquals(1.0f, mSecond.getBottomRoundness(), 0.0f);
-        Assert.assertEquals(mSmallRadiusRatio, mSecond.getTopRoundness(), 0.0f);
-    }
-
-    @Test
-    public void testRoundnessPulsing() throws Exception {
-        // Let's create a notification that's neither the first or last item of the stack,
-        // this way we'll ensure that it won't have any rounded corners by default.
-        mRoundnessManager.updateRoundedChildren(new NotificationSection[]{
-                createSection(mFirst, mSecond),
-                createSection(null, null)
-        });
-        NotificationTestHelper testHelper = new NotificationTestHelper(
-                mContext,
-                mDependency,
-                TestableLooper.get(this));
-        ExpandableNotificationRow row = testHelper.createRow();
-        NotificationEntry entry = mock(NotificationEntry.class);
-        when(entry.getRow()).thenReturn(row);
-
-        when(testHelper.getStatusBarStateController().isDozing()).thenReturn(true);
-        row.setHeadsUp(true);
-        mRoundnessManager.updateView(entry.getRow(), false);
-        Assert.assertEquals(1f, row.getBottomRoundness(), 0.0f);
-        Assert.assertEquals(1f, row.getTopRoundness(), 0.0f);
-
-        row.setHeadsUp(false);
-        mRoundnessManager.updateView(entry.getRow(), false);
-        Assert.assertEquals(mSmallRadiusRatio, row.getBottomRoundness(), 0.0f);
-        Assert.assertEquals(mSmallRadiusRatio, row.getTopRoundness(), 0.0f);
-    }
-
-    @Test
-    public void testRoundnessSetOnSecondSectionLast() {
-        mRoundnessManager.updateRoundedChildren(new NotificationSection[]{
-                createSection(mFirst, mFirst),
-                createSection(null, mSecond)
-        });
-        Assert.assertEquals(1.0f, mSecond.getBottomRoundness(), 0.0f);
-        Assert.assertEquals(mSmallRadiusRatio, mSecond.getTopRoundness(), 0.0f);
-    }
-
-    @Test
-    public void testRoundnessSetOnSecondSectionFirst() {
-        mRoundnessManager.updateRoundedChildren(new NotificationSection[]{
-                createSection(mFirst, mFirst),
-                createSection(mSecond, null)
-        });
-        Assert.assertEquals(mSmallRadiusRatio, mSecond.getBottomRoundness(), 0.0f);
-        Assert.assertEquals(1.0f, mSecond.getTopRoundness(), 0.0f);
-    }
-
-    @Test
-    public void testRoundnessSetOnNew() {
-        mRoundnessManager.updateRoundedChildren(new NotificationSection[]{
-                createSection(mFirst, null),
-                createSection(null, null)
-        });
-        Assert.assertEquals(mSmallRadiusRatio, mFirst.getBottomRoundness(), 0.0f);
-        Assert.assertEquals(1.0f, mFirst.getTopRoundness(), 0.0f);
-    }
-
-    @Test
-    public void testCompleteReplacement() {
-        mRoundnessManager.updateRoundedChildren(new NotificationSection[]{
-                createSection(mSecond, mSecond),
-                createSection(null, null)
-        });
-        Assert.assertEquals(mSmallRadiusRatio, mFirst.getBottomRoundness(), 0.0f);
-        Assert.assertEquals(mSmallRadiusRatio, mFirst.getTopRoundness(), 0.0f);
-    }
-
-    @Test
-    public void testNotCalledWhenRemoved() {
-        mFirst.setRemoved();
-        mRoundnessManager.updateRoundedChildren(new NotificationSection[]{
-                createSection(mSecond, mSecond),
-                createSection(null, null)
-        });
-        Assert.assertEquals(1.0f, mFirst.getBottomRoundness(), 0.0f);
-        Assert.assertEquals(1.0f, mFirst.getTopRoundness(), 0.0f);
-    }
-
-    @Test
-    public void testRoundedWhenPinnedAndCollapsed() {
-        mFirst.setPinned(true);
-        mRoundnessManager.setExpanded(0.0f /* expandedHeight */, 0.0f /* appearFraction */);
-        mRoundnessManager.updateRoundedChildren(new NotificationSection[]{
-                createSection(mSecond, mSecond),
-                createSection(null, null)
-        });
-        Assert.assertEquals(1.0f, mFirst.getBottomRoundness(), 0.0f);
-        Assert.assertEquals(1.0f, mFirst.getTopRoundness(), 0.0f);
-    }
-
-    @Test
-    public void testRoundedWhenGoingAwayAndCollapsed() {
-        mFirst.setHeadsUpAnimatingAway(true);
-        mRoundnessManager.setExpanded(0.0f /* expandedHeight */, 0.0f /* appearFraction */);
-        mRoundnessManager.updateRoundedChildren(new NotificationSection[]{
-                createSection(mSecond, mSecond),
-                createSection(null, null)
-        });
-        Assert.assertEquals(1.0f, mFirst.getBottomRoundness(), 0.0f);
-        Assert.assertEquals(1.0f, mFirst.getTopRoundness(), 0.0f);
-    }
-
-    @Test
-    public void testRoundedNormalRoundingWhenExpanded() {
-        mFirst.setHeadsUpAnimatingAway(true);
-        mRoundnessManager.setExpanded(1.0f /* expandedHeight */, 0.0f /* appearFraction */);
-        mRoundnessManager.updateRoundedChildren(new NotificationSection[]{
-                createSection(mSecond, mSecond),
-                createSection(null, null)
-        });
-        Assert.assertEquals(mSmallRadiusRatio, mFirst.getBottomRoundness(), 0.0f);
-        Assert.assertEquals(mSmallRadiusRatio, mFirst.getTopRoundness(), 0.0f);
-    }
-
-    @Test
-    public void testTrackingHeadsUpRoundedIfPushingUp() {
-        mRoundnessManager.setExpanded(1.0f /* expandedHeight */, -0.5f /* appearFraction */);
-        mRoundnessManager.setTrackingHeadsUp(mFirst);
-        mRoundnessManager.updateRoundedChildren(new NotificationSection[]{
-                createSection(mSecond, mSecond),
-                createSection(null, null)
-        });
-        Assert.assertEquals(1.0f, mFirst.getBottomRoundness(), 0.0f);
-        Assert.assertEquals(1.0f, mFirst.getTopRoundness(), 0.0f);
-    }
-
-    @Test
-    public void testTrackingHeadsUpPartiallyRoundedIfPushingDown() {
-        mRoundnessManager.setExpanded(1.0f /* expandedHeight */, 0.5f /* appearFraction */);
-        mRoundnessManager.setTrackingHeadsUp(mFirst);
-        mRoundnessManager.updateRoundedChildren(new NotificationSection[]{
-                createSection(mSecond, mSecond),
-                createSection(null, null)
-        });
-        Assert.assertEquals(0.5f, mFirst.getBottomRoundness(), 0.0f);
-        Assert.assertEquals(0.5f, mFirst.getTopRoundness(), 0.0f);
-    }
-
-    @Test
-    public void testRoundingUpdatedWhenAnimatingAwayTrue() {
-        mRoundnessManager.setExpanded(0.0f, 0.0f);
-        mRoundnessManager.updateRoundedChildren(new NotificationSection[]{
-                createSection(mSecond, mSecond),
-                createSection(null, null)
-        });
-        mFirst.setHeadsUpAnimatingAway(true);
-        Assert.assertEquals(1.0f, mFirst.getBottomRoundness(), 0.0f);
-        Assert.assertEquals(1.0f, mFirst.getTopRoundness(), 0.0f);
-    }
-
-
-    @Test
-    public void testRoundingUpdatedWhenAnimatingAwayFalse() {
-        mRoundnessManager.setExpanded(0.0f, 0.0f);
-        mRoundnessManager.updateRoundedChildren(new NotificationSection[]{
-                createSection(mSecond, mSecond),
-                createSection(null, null)
-        });
-        mFirst.setHeadsUpAnimatingAway(true);
-        mFirst.setHeadsUpAnimatingAway(false);
-        Assert.assertEquals(mSmallRadiusRatio, mFirst.getBottomRoundness(), 0.0f);
-        Assert.assertEquals(mSmallRadiusRatio, mFirst.getTopRoundness(), 0.0f);
-    }
-
-    @Test
-    public void testNoViewsFirstOrLastInSectionWhenSecondSectionEmpty() {
-        Assert.assertTrue(mFirst.isFirstInSection());
-        Assert.assertTrue(mFirst.isLastInSection());
-    }
-
-    @Test
-    public void testNoViewsFirstOrLastInSectionWhenFirstSectionEmpty() {
-        mRoundnessManager.updateRoundedChildren(new NotificationSection[]{
-                createSection(null, null),
-                createSection(mSecond, mSecond)
-        });
-        Assert.assertTrue(mSecond.isFirstInSection());
-        Assert.assertTrue(mSecond.isLastInSection());
-    }
-
-    @Test
-    public void testFirstAndLastViewsInSectionSetWhenBothSectionsNonEmpty() {
-        mRoundnessManager.updateRoundedChildren(new NotificationSection[]{
-                createSection(mFirst, mFirst),
-                createSection(mSecond, mSecond)
-        });
-        Assert.assertTrue(mFirst.isFirstInSection());
-        Assert.assertTrue(mFirst.isLastInSection());
-        Assert.assertTrue(mSecond.isFirstInSection());
-        Assert.assertTrue(mSecond.isLastInSection());
-    }
-
-    @Test
-    public void testLoggingOnRoundingUpdate() {
-        NotificationSection[] sections = new NotificationSection[]{
-                createSection(mFirst, mSecond),
-                createSection(null, null)
-        };
-        mRoundnessManager.updateRoundedChildren(sections);
-        verify(mLogger).onSectionCornersUpdated(sections, /*anyChanged=*/ true);
-        verify(mLogger, atLeast(1)).onCornersUpdated(eq(mFirst), anyBoolean(),
-                anyBoolean(), anyBoolean(), anyBoolean());
-        verify(mLogger, atLeast(1)).onCornersUpdated(eq(mSecond), anyBoolean(),
-                anyBoolean(), anyBoolean(), anyBoolean());
-    }
-
-    private NotificationSection createSection(ExpandableNotificationRow first,
-            ExpandableNotificationRow last) {
-        NotificationSection section = mock(NotificationSection.class);
-        when(section.getFirstVisibleChild()).thenReturn(first);
-        when(section.getLastVisibleChild()).thenReturn(last);
-        return section;
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
index 30da08e..f38881c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
@@ -96,8 +96,7 @@
                         mIncomingHeaderController,
                         mPeopleHeaderController,
                         mAlertingHeaderController,
-                        mSilentHeaderController,
-                        mFeatureFlag
+                        mSilentHeaderController
                 );
         // Required in order for the header inflation to work properly
         when(mNssl.generateLayoutParams(any(AttributeSet.class)))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelperTest.kt
index 81a3f12..45725ce 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelperTest.kt
@@ -6,7 +6,6 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.flags.FakeFeatureFlags
-import com.android.systemui.flags.Flags
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper
 import com.android.systemui.util.mockito.mock
 import junit.framework.Assert.assertEquals
@@ -30,14 +29,7 @@
             NotificationTestHelper(mContext, mDependency, TestableLooper.get(this))
     }
 
-    private fun notificationTargetsHelper(
-        notificationGroupCorner: Boolean = true,
-    ) =
-        NotificationTargetsHelper(
-            FakeFeatureFlags().apply {
-                set(Flags.USE_ROUNDNESS_SOURCETYPES, notificationGroupCorner)
-            }
-        )
+    private fun notificationTargetsHelper() = NotificationTargetsHelper(FakeFeatureFlags())
 
     @Test
     fun targetsForFirstNotificationInGroup() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
index 205cebd..2f1e372 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
@@ -34,8 +34,6 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shade.ShadeHeadsUpTracker;
@@ -82,7 +80,6 @@
     private KeyguardStateController mKeyguardStateController;
     private CommandQueue mCommandQueue;
     private NotificationRoundnessManager mNotificationRoundnessManager;
-    private FeatureFlags mFeatureFlag;
 
     @Before
     public void setUp() throws Exception {
@@ -103,9 +100,7 @@
         mKeyguardStateController = mock(KeyguardStateController.class);
         mCommandQueue = mock(CommandQueue.class);
         mNotificationRoundnessManager = mock(NotificationRoundnessManager.class);
-        mFeatureFlag = mock(FeatureFlags.class);
         when(mShadeViewController.getShadeHeadsUpTracker()).thenReturn(mShadeHeadsUpTracker);
-        when(mFeatureFlag.isEnabled(Flags.USE_ROUNDNESS_SOURCETYPES)).thenReturn(true);
         mHeadsUpAppearanceController = new HeadsUpAppearanceController(
                 mock(NotificationIconAreaController.class),
                 mHeadsUpManager,
@@ -118,7 +113,6 @@
                 mStackScrollerController,
                 mShadeViewController,
                 mNotificationRoundnessManager,
-                mFeatureFlag,
                 mHeadsUpStatusBarView,
                 new Clock(mContext, null),
                 Optional.of(mOperatorNameView));
@@ -202,7 +196,6 @@
                 mStackScrollerController,
                 mShadeViewController,
                 mNotificationRoundnessManager,
-                mFeatureFlag,
                 mHeadsUpStatusBarView,
                 new Clock(mContext, null),
                 Optional.empty());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 6be0e2d..e56f0d6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -84,6 +84,7 @@
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.unfold.SysUIUnfoldComponent;
 
 import com.google.common.truth.Truth;
@@ -151,13 +152,15 @@
     private WindowOnBackInvokedDispatcher mOnBackInvokedDispatcher;
     @Captor
     private ArgumentCaptor<OnBackInvokedCallback> mBackCallbackCaptor;
+    @Captor
+    private ArgumentCaptor<KeyguardStateController.Callback> mKeyguardStateControllerCallback;
 
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         when(mContainer.findViewById(anyInt())).thenReturn(mKeyguardMessageArea);
-        when(mKeyguardMessageAreaFactory.create(any(KeyguardMessageArea.class)))
+        when(mKeyguardMessageAreaFactory.create(any()))
                 .thenReturn(mKeyguardMessageAreaController);
         when(mBouncerView.getDelegate()).thenReturn(mBouncerViewDelegate);
         when(mBouncerViewDelegate.getBackCallback()).thenReturn(mBouncerViewDelegateBackCallback);
@@ -909,4 +912,26 @@
         // THEN the alternateBouncer doesn't hide
         verify(mAlternateBouncerInteractor, never()).hide();
     }
+
+    @Test
+    public void onDeviceUnlocked_hideAlternateBouncerAndClearMessageArea() {
+        reset(mKeyguardUpdateMonitor);
+        reset(mKeyguardMessageAreaController);
+
+        // GIVEN keyguard state controller callback is registered
+        verify(mKeyguardStateController).addCallback(mKeyguardStateControllerCallback.capture());
+
+        // GIVEN alternate bouncer state = not visible
+        when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(false);
+
+        // WHEN the device is unlocked
+        mKeyguardStateControllerCallback.getValue().onUnlockedChanged();
+
+        // THEN the false visibility state is propagated to the keyguardUpdateMonitor
+        verify(mKeyguardUpdateMonitor).setAlternateBouncerShowing(eq(false));
+
+        // THEN message area visibility updated to FALSE with empty message
+        verify(mKeyguardMessageAreaController).setIsVisible(eq(false));
+        verify(mKeyguardMessageAreaController).setMessage(eq(""));
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
index 3ec9690..bde05b9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
@@ -53,6 +53,7 @@
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import org.junit.After
 import org.junit.Before
 import org.junit.Test
@@ -92,13 +93,15 @@
     private val mobileMappings = FakeMobileMappingsProxy()
     private val subscriptionManagerProxy = FakeSubscriptionManagerProxy()
 
+    private val testDispatcher = UnconfinedTestDispatcher()
     private val scope = CoroutineScope(IMMEDIATE)
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
 
-        logFactory = TableLogBufferFactory(dumpManager, FakeSystemClock())
+        logFactory =
+            TableLogBufferFactory(dumpManager, FakeSystemClock(), mock(), testDispatcher, scope)
 
         // Never start in demo mode
         whenever(demoModeController.isInDemoMode).thenReturn(false)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt
index 37fac34..7573b28 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt
@@ -61,11 +61,18 @@
 internal class DemoMobileConnectionParameterizedTest(private val testCase: TestCase) :
     SysuiTestCase() {
 
-    private val logFactory = TableLogBufferFactory(mock(), FakeSystemClock())
-
     private val testDispatcher = UnconfinedTestDispatcher()
     private val testScope = TestScope(testDispatcher)
 
+    private val logFactory =
+        TableLogBufferFactory(
+            mock(),
+            FakeSystemClock(),
+            mock(),
+            testDispatcher,
+            testScope.backgroundScope,
+        )
+
     private val fakeNetworkEventFlow = MutableStateFlow<FakeNetworkEventModel?>(null)
     private val fakeWifiEventFlow = MutableStateFlow<FakeWifiEventModel?>(null)
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
index 1251dfa..efaf152 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
@@ -54,13 +54,20 @@
 @SmallTest
 class DemoMobileConnectionsRepositoryTest : SysuiTestCase() {
     private val dumpManager: DumpManager = mock()
-    private val logFactory = TableLogBufferFactory(dumpManager, FakeSystemClock())
 
     private val testDispatcher = UnconfinedTestDispatcher()
     private val testScope = TestScope(testDispatcher)
 
     private val fakeNetworkEventFlow = MutableStateFlow<FakeNetworkEventModel?>(null)
     private val fakeWifiEventFlow = MutableStateFlow<FakeWifiEventModel?>(null)
+    private val logFactory =
+        TableLogBufferFactory(
+            dumpManager,
+            FakeSystemClock(),
+            mock(),
+            testDispatcher,
+            testScope.backgroundScope,
+        )
 
     private lateinit var underTest: DemoMobileConnectionsRepository
     private lateinit var mobileDataSource: DemoModeMobileConnectionDataSource
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
index 9f77744..b701fbd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
@@ -66,7 +66,15 @@
     private val systemClock = FakeSystemClock()
     private val testDispatcher = UnconfinedTestDispatcher()
     private val testScope = TestScope(testDispatcher)
-    private val tableLogBuffer = TableLogBuffer(maxSize = 100, name = "TestName", systemClock)
+    private val tableLogBuffer =
+        TableLogBuffer(
+            maxSize = 100,
+            name = "TestName",
+            systemClock,
+            mock(),
+            testDispatcher,
+            testScope.backgroundScope,
+        )
     private val mobileFactory = mock<MobileConnectionRepositoryImpl.Factory>()
     private val carrierMergedFactory = mock<CarrierMergedConnectionRepository.Factory>()
 
@@ -294,7 +302,14 @@
     @Test
     fun factory_reusesLogBuffersForSameConnection() =
         testScope.runTest {
-            val realLoggerFactory = TableLogBufferFactory(mock(), FakeSystemClock())
+            val realLoggerFactory =
+                TableLogBufferFactory(
+                    mock(),
+                    FakeSystemClock(),
+                    mock(),
+                    testDispatcher,
+                    testScope.backgroundScope,
+                )
 
             val factory =
                 FullMobileConnectionRepository.Factory(
@@ -329,7 +344,14 @@
     @Test
     fun factory_reusesLogBuffersForSameSubIDevenIfCarrierMerged() =
         testScope.runTest {
-            val realLoggerFactory = TableLogBufferFactory(mock(), FakeSystemClock())
+            val realLoggerFactory =
+                TableLogBufferFactory(
+                    mock(),
+                    FakeSystemClock(),
+                    mock(),
+                    testDispatcher,
+                    testScope.backgroundScope,
+                )
 
             val factory =
                 FullMobileConnectionRepository.Factory(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
index c84c9c0..6e1ab58 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
@@ -61,6 +61,16 @@
     private val testDispatcher = UnconfinedTestDispatcher()
     private val testScope = TestScope(testDispatcher)
 
+    private val tableLogBuffer =
+        TableLogBuffer(
+            8,
+            "MobileIconsInteractorTest",
+            FakeSystemClock(),
+            mock(),
+            testDispatcher,
+            testScope.backgroundScope,
+        )
+
     @Mock private lateinit var carrierConfigTracker: CarrierConfigTracker
 
     @Before
@@ -687,16 +697,14 @@
     }
 
     companion object {
-        private val tableLogBuffer =
-            TableLogBuffer(8, "MobileIconsInteractorTest", FakeSystemClock())
 
         private const val SUB_1_ID = 1
         private val SUB_1 = SubscriptionModel(subscriptionId = SUB_1_ID)
-        private val CONNECTION_1 = FakeMobileConnectionRepository(SUB_1_ID, tableLogBuffer)
+        private val CONNECTION_1 = FakeMobileConnectionRepository(SUB_1_ID, mock())
 
         private const val SUB_2_ID = 2
         private val SUB_2 = SubscriptionModel(subscriptionId = SUB_2_ID)
-        private val CONNECTION_2 = FakeMobileConnectionRepository(SUB_2_ID, tableLogBuffer)
+        private val CONNECTION_2 = FakeMobileConnectionRepository(SUB_2_ID, mock())
 
         private const val SUB_3_ID = 3
         private val SUB_3_OPP =
@@ -705,7 +713,7 @@
                 isOpportunistic = true,
                 groupUuid = ParcelUuid(UUID.randomUUID()),
             )
-        private val CONNECTION_3 = FakeMobileConnectionRepository(SUB_3_ID, tableLogBuffer)
+        private val CONNECTION_3 = FakeMobileConnectionRepository(SUB_3_ID, mock())
 
         private const val SUB_4_ID = 4
         private val SUB_4_OPP =
@@ -714,6 +722,6 @@
                 isOpportunistic = true,
                 groupUuid = ParcelUuid(UUID.randomUUID()),
             )
-        private val CONNECTION_4 = FakeMobileConnectionRepository(SUB_4_ID, tableLogBuffer)
+        private val CONNECTION_4 = FakeMobileConnectionRepository(SUB_4_ID, mock())
     }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt
index 2c0a8fd..492e542 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt
@@ -21,13 +21,27 @@
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
 
-/** Fake implementation of [KeyguardRepository] */
+/** Fake implementation of [ShadeRepository] */
 class FakeShadeRepository : ShadeRepository {
 
     private val _shadeModel = MutableStateFlow(ShadeModel())
     override val shadeModel: Flow<ShadeModel> = _shadeModel
 
+    private val _qsExpansion = MutableStateFlow(0f)
+    override val qsExpansion = _qsExpansion
+
+    private val _udfpsTransitionToFullShadeProgress = MutableStateFlow(0f)
+    override val udfpsTransitionToFullShadeProgress = _udfpsTransitionToFullShadeProgress
+
     fun setShadeModel(model: ShadeModel) {
         _shadeModel.value = model
     }
+
+    override fun setQsExpansion(qsExpansion: Float) {
+        _qsExpansion.value = qsExpansion
+    }
+
+    override fun setUdfpsTransitionToFullShadeProgress(progress: Float) {
+        _udfpsTransitionToFullShadeProgress.value = progress
+    }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index a3b4a0f..e894f1c 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -490,7 +490,7 @@
                 mMainHandler, context,
                 new PolicyWarningUIController.NotificationController(context));
         mSecurityPolicy = new AccessibilitySecurityPolicy(policyWarningUIController, mContext,
-                this);
+                this, LocalServices.getService(PackageManagerInternal.class));
         mA11yWindowManager = new AccessibilityWindowManager(mLock, mMainHandler,
                 mWindowManagerService, this, mSecurityPolicy, this, mTraceManager);
         mA11yDisplayListener = new AccessibilityDisplayListener(mContext, mMainHandler);
@@ -1012,8 +1012,7 @@
                                 + Binder.getCallingPid() + " for device id " + deviceId
                                 + " with package names " + Arrays.toString(client.mPackageNames));
                     }
-                    return IntPair.of(mProxyManager.getStateLocked(deviceId,
-                                    mUiAutomationManager.isUiAutomationRunningLocked()),
+                    return IntPair.of(mProxyManager.getStateLocked(deviceId),
                             client.mLastSentRelevantEventTypes);
                 }
                 mGlobalClients.register(callback, client);
@@ -1028,8 +1027,7 @@
                                 + Binder.getCallingPid() + " for device id " + deviceId
                                 + " with package names " + Arrays.toString(client.mPackageNames));
                     }
-                    return IntPair.of(mProxyManager.getStateLocked(deviceId,
-                                    mUiAutomationManager.isUiAutomationRunningLocked()),
+                    return IntPair.of(mProxyManager.getStateLocked(deviceId),
                             client.mLastSentRelevantEventTypes);
                 }
                 userState.mUserClients.register(callback, client);
@@ -4024,9 +4022,8 @@
 
         final long identity = Binder.clearCallingIdentity();
         try {
-            mProxyManager.registerProxy(client, displayId, mContext,
-                    sIdCounter++, mMainHandler, mSecurityPolicy, this, getTraceManager(),
-                    mWindowManagerService);
+            mProxyManager.registerProxy(client, displayId, sIdCounter++, mSecurityPolicy,
+                    this, getTraceManager(), mWindowManagerService);
 
             synchronized (mLock) {
                 notifyClearAccessibilityCacheLocked();
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java b/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java
index 8865623..65c1873 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java
@@ -29,6 +29,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.pm.UserInfo;
@@ -99,6 +100,7 @@
 
     private final Context mContext;
     private final PackageManager mPackageManager;
+    private final PackageManagerInternal mPackageManagerInternal;
     private final UserManager mUserManager;
     private final AppOpsManager mAppOpsManager;
     private final AccessibilityUserManager mAccessibilityUserManager;
@@ -116,10 +118,12 @@
      */
     public AccessibilitySecurityPolicy(PolicyWarningUIController policyWarningUIController,
             @NonNull Context context,
-            @NonNull AccessibilityUserManager a11yUserManager) {
+            @NonNull AccessibilityUserManager a11yUserManager,
+            @NonNull PackageManagerInternal packageManagerInternal) {
         mContext = context;
         mAccessibilityUserManager = a11yUserManager;
         mPackageManager = mContext.getPackageManager();
+        mPackageManagerInternal = packageManagerInternal;
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
         mPolicyWarningUIController = policyWarningUIController;
@@ -513,12 +517,7 @@
     private boolean isValidPackageForUid(String packageName, int uid) {
         final long token = Binder.clearCallingIdentity();
         try {
-            // Since we treat calls from a profile as if made by its parent, using
-            // MATCH_ANY_USER to query the uid of the given package name.
-            return uid == mPackageManager.getPackageUidAsUser(
-                    packageName, PackageManager.MATCH_ANY_USER, UserHandle.getUserId(uid));
-        } catch (PackageManager.NameNotFoundException e) {
-            return false;
+            return mPackageManagerInternal.isSameApp(packageName, uid, UserHandle.getUserId(uid));
         } finally {
             Binder.restoreCallingIdentity(token);
         }
diff --git a/services/accessibility/java/com/android/server/accessibility/ProxyManager.java b/services/accessibility/java/com/android/server/accessibility/ProxyManager.java
index d417197..6dc8fb3 100644
--- a/services/accessibility/java/com/android/server/accessibility/ProxyManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/ProxyManager.java
@@ -61,7 +61,6 @@
  * proxy connection will belong to a separate user state.
  *
  * TODO(241117292): Remove or cut down during simultaneous user refactoring.
- * TODO(262244375): Add unit tests.
  */
 public class ProxyManager {
     private static final boolean DEBUG = false;
@@ -128,7 +127,7 @@
         RemoteCallbackList<IAccessibilityManagerClient> getCurrentUserClientsLocked();
     }
 
-    ProxyManager(Object lock, AccessibilityWindowManager awm,
+    public ProxyManager(Object lock, AccessibilityWindowManager awm,
             Context context, Handler mainHandler, UiAutomationManager uiAutomationManager,
             SystemSupport systemSupport) {
         mLock = lock;
@@ -144,9 +143,7 @@
      * Creates the service connection.
      */
     public void registerProxy(IAccessibilityServiceClient client, int displayId,
-            Context context,
-            int id, Handler mainHandler,
-            AccessibilitySecurityPolicy securityPolicy,
+            int id, AccessibilitySecurityPolicy securityPolicy,
             AbstractAccessibilityServiceConnection.SystemSupport systemSupport,
             AccessibilityTrace trace,
             WindowManagerInternal windowManagerInternal) throws RemoteException {
@@ -169,8 +166,8 @@
         info.setComponentName(new ComponentName(PROXY_COMPONENT_PACKAGE_NAME,
                 componentClassDisplayName));
         ProxyAccessibilityServiceConnection connection =
-                new ProxyAccessibilityServiceConnection(context, info.getComponentName(), info,
-                        id, mainHandler, mLock, securityPolicy, systemSupport, trace,
+                new ProxyAccessibilityServiceConnection(mContext, info.getComponentName(), info,
+                        id, mMainHandler, mLock, securityPolicy, systemSupport, trace,
                         windowManagerInternal,
                         mA11yWindowManager, displayId, deviceId);
 
@@ -263,7 +260,7 @@
      * When the connection is removed from tracking in ProxyManager, propagate changes to other a11y
      * system components like the input filter and IAccessibilityManagerClients.
      */
-    public void updateStateForRemovedDisplay(int displayId, int deviceId) {
+    private void updateStateForRemovedDisplay(int displayId, int deviceId) {
         mA11yWindowManager.stopTrackingDisplayProxy(displayId);
         // A11yInputFilter isn't thread-safe, so post on the system thread.
         mMainHandler.post(
@@ -360,8 +357,9 @@
     /**
      * If there is at least one proxy, accessibility is enabled.
      */
-    public int getStateLocked(int deviceId, boolean automationRunning) {
+    public int getStateLocked(int deviceId) {
         int clientState = 0;
+        final boolean automationRunning = mUiAutomationManager.isUiAutomationRunningLocked();
         if (automationRunning) {
             clientState |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED;
         }
@@ -387,7 +385,7 @@
     /**
      * If there is at least one proxy, accessibility is enabled.
      */
-    public int getStateForDisplayIdLocked(ProxyAccessibilityServiceConnection proxy) {
+    private int getStateForDisplayIdLocked(ProxyAccessibilityServiceConnection proxy) {
         int clientState = 0;
         if (proxy != null) {
             clientState |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED;
@@ -409,14 +407,14 @@
     /**
      * Gets the last state for a device.
      */
-    public int getLastSentStateLocked(int deviceId) {
+    private int getLastSentStateLocked(int deviceId) {
         return mLastStates.get(deviceId, 0);
     }
 
     /**
      * Sets the last state for a device.
      */
-    public void setLastStateLocked(int deviceId, int proxyState) {
+    private void setLastStateLocked(int deviceId, int proxyState) {
         mLastStates.put(deviceId, proxyState);
     }
 
@@ -429,7 +427,7 @@
      * Virtual Device, the app clients will get the aggregated event types for all proxy-ed displays
      * belonging to a VirtualDevice.
      */
-    public void updateRelevantEventTypesLocked(int deviceId) {
+    private void updateRelevantEventTypesLocked(int deviceId) {
         if (!isProxyedDeviceId(deviceId)) {
             return;
         }
@@ -452,7 +450,7 @@
     /**
      * Returns the relevant event types for a Client.
      */
-    int computeRelevantEventTypesLocked(AccessibilityManagerService.Client client) {
+    public int computeRelevantEventTypesLocked(AccessibilityManagerService.Client client) {
         int relevantEventTypes = 0;
         for (int i = 0; i < mProxyA11yServiceConnections.size(); i++) {
             final ProxyAccessibilityServiceConnection proxy =
@@ -578,9 +576,8 @@
     /**
      * Updates the states of the app AccessibilityManagers.
      */
-    public void scheduleUpdateProxyClientsIfNeededLocked(int deviceId) {
-        final int proxyState = getStateLocked(deviceId,
-                mUiAutomationManager.isUiAutomationRunningLocked());
+    private void scheduleUpdateProxyClientsIfNeededLocked(int deviceId) {
+        final int proxyState = getStateLocked(deviceId);
         if (DEBUG) {
             Slog.v(LOG_TAG, "State for device id " + deviceId + " is " + proxyState);
             Slog.v(LOG_TAG, "Last state for device id " + deviceId + " is "
@@ -606,7 +603,7 @@
      *
      * @see AccessibilityManager.AccessibilityServicesStateChangeListener
      */
-    public void scheduleNotifyProxyClientsOfServicesStateChangeLocked(int deviceId) {
+    private void scheduleNotifyProxyClientsOfServicesStateChangeLocked(int deviceId) {
         if (DEBUG) {
             Slog.v(LOG_TAG, "Notify services state change at device id " + deviceId);
         }
@@ -625,7 +622,7 @@
     /**
      * Updates the focus appearance of AccessibilityManagerClients.
      */
-    public void updateFocusAppearanceLocked(int deviceId) {
+    private void updateFocusAppearanceLocked(int deviceId) {
         if (DEBUG) {
             Slog.v(LOG_TAG, "Update proxy focus appearance at device id " + deviceId);
         }
@@ -764,7 +761,7 @@
     /**
      * Sets a Client device id if the app uid belongs to the virtual device.
      */
-    public void updateDeviceIdsIfNeededLocked(int deviceId) {
+    private void updateDeviceIdsIfNeededLocked(int deviceId) {
         final RemoteCallbackList<IAccessibilityManagerClient> userClients =
                 mSystemSupport.getCurrentUserClientsLocked();
         final RemoteCallbackList<IAccessibilityManagerClient> globalClients =
@@ -777,7 +774,7 @@
     /**
      * Updates the device ids of IAccessibilityManagerClients if needed.
      */
-    public void updateDeviceIdsIfNeededLocked(int deviceId,
+    private void updateDeviceIdsIfNeededLocked(int deviceId,
             @NonNull RemoteCallbackList<IAccessibilityManagerClient> clients) {
         final VirtualDeviceManagerInternal localVdm = getLocalVdm();
         if (localVdm == null) {
@@ -809,14 +806,17 @@
         }
     }
 
-    void setAccessibilityInputFilter(AccessibilityInputFilter filter) {
+    /**
+     * Sets the input filter for enabling and disabling features for proxy displays.
+     */
+    public void setAccessibilityInputFilter(AccessibilityInputFilter filter) {
         if (DEBUG) {
             Slog.v(LOG_TAG, "Set proxy input filter to " + filter);
         }
         mA11yInputFilter = filter;
     }
 
-    VirtualDeviceManagerInternal getLocalVdm() {
+    private VirtualDeviceManagerInternal getLocalVdm() {
         if (mLocalVdm == null) {
             mLocalVdm =  LocalServices.getService(VirtualDeviceManagerInternal.class);
         }
diff --git a/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java b/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
index a13df47..9747579 100644
--- a/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
+++ b/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
@@ -36,6 +36,7 @@
 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 
 import com.android.internal.R;
+import com.android.internal.accessibility.util.AccessibilityUtils;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ScreenshotHelper;
@@ -302,8 +303,10 @@
                 case AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT:
                     return takeScreenshot();
                 case AccessibilityService.GLOBAL_ACTION_KEYCODE_HEADSETHOOK:
-                    sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HEADSETHOOK,
-                            InputDevice.SOURCE_KEYBOARD);
+                    if (!AccessibilityUtils.interceptHeadsetHookForActiveCall(mContext)) {
+                        sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HEADSETHOOK,
+                                InputDevice.SOURCE_KEYBOARD);
+                    }
                     return true;
                 case AccessibilityService.GLOBAL_ACTION_DPAD_UP:
                     sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_UP,
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index bc5d645..ac77043 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -16,13 +16,18 @@
 
 package com.android.server.autofill;
 
+import static com.android.server.autofill.Helper.sDebug;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.assist.AssistStructure;
 import android.app.assist.AssistStructure.ViewNode;
 import android.app.assist.AssistStructure.WindowNode;
 import android.content.ComponentName;
+import android.content.Context;
+import android.hardware.display.DisplayManager;
 import android.metrics.LogMaker;
+import android.os.UserManager;
 import android.service.autofill.Dataset;
 import android.service.autofill.InternalSanitizer;
 import android.service.autofill.SaveInfo;
@@ -30,6 +35,7 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
+import android.view.Display;
 import android.view.View;
 import android.view.WindowManager;
 import android.view.autofill.AutofillId;
@@ -37,6 +43,7 @@
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.ArrayUtils;
+import com.android.server.utils.Slogf;
 
 import java.io.PrintWriter;
 import java.util.ArrayDeque;
@@ -281,6 +288,38 @@
         return true;
     }
 
+    /**
+     * Gets a context with the proper display id.
+     *
+     * <p>For most cases it will return the provided context, but on devices that
+     * {@link UserManager#isVisibleBackgroundUsersEnabled() support visible background users}, it
+     * will return a context with the display pased as parameter.
+     */
+    static Context getDisplayContext(Context context, int displayId) {
+        if (!UserManager.isVisibleBackgroundUsersEnabled()) {
+            return context;
+        }
+        if (context.getDisplayId() == displayId) {
+            if (sDebug) {
+                Slogf.d(TAG, "getDisplayContext(): context %s already has displayId %d", context,
+                        displayId);
+            }
+            return context;
+        }
+        if (sDebug) {
+            Slogf.d(TAG, "Creating context for display %d", displayId);
+        }
+        Display display = context.getSystemService(DisplayManager.class).getDisplay(displayId);
+        if (display == null) {
+            Slogf.wtf(TAG, "Could not get context with displayId %d, Autofill operations will "
+                    + "probably fail)", displayId);
+            return context;
+        }
+
+        return context.createDisplayContext(display);
+    }
+
+
     private interface ViewNodeFilter {
         boolean matches(ViewNode node);
     }
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 3ab5bca..f83d734 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -164,10 +164,12 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.ArrayUtils;
+import com.android.server.LocalServices;
 import com.android.server.autofill.ui.AutoFillUI;
 import com.android.server.autofill.ui.InlineFillUi;
 import com.android.server.autofill.ui.PendingUi;
 import com.android.server.inputmethod.InputMethodManagerInternal;
+import com.android.server.wm.ActivityTaskManagerInternal;
 
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
@@ -214,7 +216,12 @@
     private final AutofillManagerServiceImpl mService;
     private final Handler mHandler;
     private final AutoFillUI mUi;
-    @NonNull private final Context mContext;
+
+    /**
+     * Context associated with the session, it has the same {@link Context#getDisplayId() displayId}
+     * of the activity being autofilled.
+     */
+    private final Context mContext;
 
     private final MetricsLogger mMetricsLogger = new MetricsLogger();
 
@@ -1352,7 +1359,9 @@
         mHasCallback = hasCallback;
         mUiLatencyHistory = uiLatencyHistory;
         mWtfHistory = wtfHistory;
-        mContext = context;
+        int displayId = LocalServices.getService(ActivityTaskManagerInternal.class)
+                .getDisplayId(activityToken);
+        mContext = Helper.getDisplayContext(context, displayId);
         mComponentName = componentName;
         mCompatMode = compatMode;
         mSessionState = STATE_ACTIVE;
@@ -3401,7 +3410,7 @@
                 final long saveUiDisplayStartTimestamp = SystemClock.elapsedRealtime();
                 getUiForShowing().showSaveUi(serviceLabel, serviceIcon,
                         mService.getServicePackageName(), saveInfo, this,
-                        mComponentName, this, userId, mPendingSaveUi, isUpdate, mCompatMode,
+                        mComponentName, this, mContext,  mPendingSaveUi, isUpdate, mCompatMode,
                         response.getShowSaveDialogIcon());
                 mSaveEventLogger.maybeSetLatencySaveUiDisplayMillis(
                     SystemClock.elapsedRealtime()- saveUiDisplayStartTimestamp);
@@ -4272,7 +4281,7 @@
 
         getUiForShowing().showFillUi(filledId, response, filterText,
                 mService.getServicePackageName(), mComponentName,
-                targetLabel, targetIcon, this, userId, id, mCompatMode);
+                targetLabel, targetIcon, this, mContext, id, mCompatMode);
 
         synchronized (mLock) {
             mPresentationStatsEventLogger.maybeSetCountShown(
@@ -5453,6 +5462,7 @@
         pw.print(prefix); pw.print("uid: "); pw.println(uid);
         pw.print(prefix); pw.print("taskId: "); pw.println(taskId);
         pw.print(prefix); pw.print("flags: "); pw.println(mFlags);
+        pw.print(prefix); pw.print("displayId: "); pw.println(mContext.getDisplayId());
         pw.print(prefix); pw.print("state: "); pw.println(sessionStateAsString(mSessionState));
         pw.print(prefix); pw.print("mComponentName: "); pw.println(mComponentName);
         pw.print(prefix); pw.print("mActivityToken: "); pw.println(mActivityToken);
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index cfd66f1..b3cbe45 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -23,7 +23,6 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UserIdInt;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -53,6 +52,7 @@
 import com.android.server.UiModeManagerInternal;
 import com.android.server.UiThread;
 import com.android.server.autofill.Helper;
+import com.android.server.utils.Slogf;
 
 import java.io.PrintWriter;
 
@@ -198,6 +198,7 @@
      * @param serviceIcon icon of autofill service
      * @param callback identifier for the caller
      * @param userId the user associated wit the session
+     * @param context context with the proper state (like display id) to show the UI
      * @param sessionId id of the autofill session
      * @param compatMode whether the app is being autofilled in compatibility mode.
      */
@@ -205,11 +206,11 @@
             @Nullable String filterText, @Nullable String servicePackageName,
             @NonNull ComponentName componentName, @NonNull CharSequence serviceLabel,
             @NonNull Drawable serviceIcon, @NonNull AutoFillUiCallback callback,
-            @UserIdInt int userId, int sessionId, boolean compatMode) {
+            @NonNull Context context, int sessionId, boolean compatMode) {
         if (sDebug) {
             final int size = filterText == null ? 0 : filterText.length();
-            Slog.d(TAG, "showFillUi(): id=" + focusedId + ", filter=" + size + " chars, userId="
-                    + userId);
+            Slogf.d(TAG, "showFillUi(): id=%s, filter=%d chars, displayId=%d", focusedId, size,
+                    context.getDisplayId());
         }
         final LogMaker log = Helper
                 .newLogMaker(MetricsEvent.AUTOFILL_FILL_UI, componentName, servicePackageName,
@@ -224,10 +225,8 @@
                 return;
             }
             hideAllUiThread(callback);
-            mFillUi = new FillUi(mContext, userId, response, focusedId,
-                    filterText, mOverlayControl, serviceLabel, serviceIcon,
-                    mUiModeMgr.isNightMode(),
-                    new FillUi.Callback() {
+            mFillUi = new FillUi(context, response, focusedId, filterText, mOverlayControl,
+                    serviceLabel, serviceIcon, mUiModeMgr.isNightMode(), new FillUi.Callback() {
                 @Override
                 public void onResponsePicked(FillResponse response) {
                     log.setType(MetricsEvent.TYPE_DETAIL);
@@ -325,12 +324,12 @@
     public void showSaveUi(@NonNull CharSequence serviceLabel, @NonNull Drawable serviceIcon,
             @Nullable String servicePackageName, @NonNull SaveInfo info,
             @NonNull ValueFinder valueFinder, @NonNull ComponentName componentName,
-            @NonNull AutoFillUiCallback callback, @UserIdInt int userId,
+            @NonNull AutoFillUiCallback callback, @NonNull Context context,
             @NonNull PendingUi pendingSaveUi, boolean isUpdate, boolean compatMode,
             boolean showServiceIcon) {
         if (sVerbose) {
-            Slog.v(TAG, "showSaveUi(update=" + isUpdate + ") for " + componentName.toShortString()
-                    + " and user " + userId + ": " + info);
+            Slogf.v(TAG, "showSaveUi(update=%b) for %s and display %d: %s", isUpdate,
+                    componentName.toShortString(), context.getDisplayId(), info);
         }
         int numIds = 0;
         numIds += info.getRequiredIds() == null ? 0 : info.getRequiredIds().length;
@@ -350,7 +349,7 @@
             }
             hideAllUiThread(callback);
             mSaveUiCallback = callback;
-            mSaveUi = new SaveUi(mContext, userId, pendingSaveUi, serviceLabel, serviceIcon,
+            mSaveUi = new SaveUi(context, pendingSaveUi, serviceLabel, serviceIcon,
                     servicePackageName, componentName, info, valueFinder, mOverlayControl,
                     new SaveUi.OnSaveListener() {
                 @Override
diff --git a/services/autofill/java/com/android/server/autofill/ui/DisplayHelper.java b/services/autofill/java/com/android/server/autofill/ui/DisplayHelper.java
deleted file mode 100644
index 5353480..0000000
--- a/services/autofill/java/com/android/server/autofill/ui/DisplayHelper.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * 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.autofill.ui;
-
-import static com.android.server.autofill.Helper.sDebug;
-
-import android.annotation.UserIdInt;
-import android.content.Context;
-import android.hardware.display.DisplayManager;
-import android.os.UserManager;
-import android.view.Display;
-
-import com.android.server.LocalServices;
-import com.android.server.pm.UserManagerInternal;
-import com.android.server.utils.Slogf;
-
-/**
- * Helper for display-related needs.
- */
-final class DisplayHelper {
-
-    private static final String TAG = "AutofillDisplayHelper";
-
-    private static final UserManagerInternal sUmi = LocalServices
-            .getService(UserManagerInternal.class);
-
-    /**
-     * Gets a context with the proper display id set for the given user.
-     *
-     * <p>For most cases it will return the provided context, but on devices that
-     * {@link UserManager#isVisibleBackgroundUsersEnabled() support visible background users}, it
-     * will return a context with the display the user started visible on.
-     */
-    static Context getDisplayContext(Context context, @UserIdInt int userId) {
-        if (!UserManager.isVisibleBackgroundUsersEnabled()) {
-            return context;
-        }
-        int displayId = sUmi.getMainDisplayAssignedToUser(userId);
-        if (sDebug) {
-            Slogf.d(TAG, "Creating context for display %d for user %d", displayId, userId);
-        }
-        Display display = context.getSystemService(DisplayManager.class).getDisplay(displayId);
-        if (display == null) {
-            Slogf.wtf(TAG, "Could not get display with id %d (which is associated with user %d; "
-                    + "FillUi operations will probably fail", displayId, userId);
-            return context;
-        }
-
-        return context.createDisplayContext(display);
-    }
-
-    private DisplayHelper() {
-        throw new UnsupportedOperationException("Contains only static methods");
-    }
-}
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index b651ae59..129ce72 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -22,7 +22,6 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UserIdInt;
 import android.content.Context;
 import android.content.IntentSender;
 import android.content.pm.PackageManager;
@@ -61,6 +60,7 @@
 import com.android.server.UiThread;
 import com.android.server.autofill.AutofillManagerService;
 import com.android.server.autofill.Helper;
+import com.android.server.utils.Slogf;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -134,14 +134,15 @@
         return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
     }
 
-    FillUi(@NonNull Context systemContext, @UserIdInt int userId, @NonNull FillResponse response,
+    FillUi(@NonNull Context context, @NonNull FillResponse response,
             @NonNull AutofillId focusedViewId, @Nullable String filterText,
             @NonNull OverlayControl overlayControl, @NonNull CharSequence serviceLabel,
             @NonNull Drawable serviceIcon, boolean nightMode, @NonNull Callback callback) {
-        if (sVerbose) Slog.v(TAG, "nightMode: " + nightMode);
+        if (sVerbose) {
+            Slogf.v(TAG, "nightMode: %b displayId: %d", nightMode, context.getDisplayId());
+        }
         mThemeId = nightMode ? THEME_ID_DARK : THEME_ID_LIGHT;
         mCallback = callback;
-        Context context = DisplayHelper.getDisplayContext(systemContext, userId);
         mFullScreen = isFullScreen(context);
         mContext = new ContextThemeWrapper(context, mThemeId);
 
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index aec0bdf..1204259 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -21,7 +21,6 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UserIdInt;
 import android.app.Dialog;
 import android.app.PendingIntent;
 import android.content.ComponentName;
@@ -71,6 +70,7 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.server.UiThread;
 import com.android.server.autofill.Helper;
+import com.android.server.utils.Slogf;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -173,14 +173,15 @@
 
     private boolean mDestroyed;
 
-    SaveUi(@NonNull Context systemContext, @UserIdInt int userId, @NonNull PendingUi pendingUi,
+    SaveUi(@NonNull Context context, @NonNull PendingUi pendingUi,
            @NonNull CharSequence serviceLabel, @NonNull Drawable serviceIcon,
            @Nullable String servicePackageName, @NonNull ComponentName componentName,
            @NonNull SaveInfo info, @NonNull ValueFinder valueFinder,
            @NonNull OverlayControl overlayControl, @NonNull OnSaveListener listener,
            boolean nightMode, boolean isUpdate, boolean compatMode, boolean showServiceIcon) {
-        Context context = DisplayHelper.getDisplayContext(systemContext, userId);
-        if (sVerbose) Slog.v(TAG, "nightMode: " + nightMode);
+        if (sVerbose) {
+            Slogf.v(TAG, "nightMode: %b displayId: %d", nightMode, context.getDisplayId());
+        }
         mThemeId = nightMode ? THEME_ID_DARK : THEME_ID_LIGHT;
         mPendingUi = pendingUi;
         mListener = new OneActionThenDestroyListener(listener);
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index df3c95b..678d582 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -3866,7 +3866,7 @@
         if (UserHandle.isCore(callingUid)) {
             return;
         }
-        final int callingUserId = UserHandle.getCallingUserId();
+        final int callingUserId = UserHandle.getUserId(callingUid);
         if (callingUserId == userId
                 || !mAm.mUserController.isSameProfileGroup(callingUserId, userId)) {
             return;
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index d140403..6360e2a 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -167,7 +167,7 @@
                     .onMalformedInput(CodingErrorAction.REPLACE)
                     .onUnmappableCharacter(CodingErrorAction.REPLACE)
                     .replaceWith("?");
-    private static final int MAX_LOW_POWER_STATS_SIZE = 16384;
+    private static final int MAX_LOW_POWER_STATS_SIZE = 32768;
     private static final int POWER_STATS_QUERY_TIMEOUT_MILLIS = 2000;
     private static final String EMPTY = "Empty";
 
diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
index 0767218..5c68e67 100644
--- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
@@ -242,8 +242,7 @@
      */
     @Nullable
     public BroadcastRecord enqueueOrReplaceBroadcast(@NonNull BroadcastRecord record,
-            int recordIndex, boolean wouldBeSkipped,
-            @NonNull BroadcastConsumer deferredStatesApplyConsumer) {
+            int recordIndex, @NonNull BroadcastConsumer deferredStatesApplyConsumer) {
         // When updateDeferredStates() has already applied a deferred state to
         // all pending items, apply to this new broadcast too
         if (mLastDeferredStates && record.deferUntilActive
@@ -252,8 +251,7 @@
         }
 
         if (record.isReplacePending()) {
-            final BroadcastRecord replacedBroadcastRecord = replaceBroadcast(record, recordIndex,
-                    wouldBeSkipped);
+            final BroadcastRecord replacedBroadcastRecord = replaceBroadcast(record, recordIndex);
             if (replacedBroadcastRecord != null) {
                 return replacedBroadcastRecord;
             }
@@ -264,14 +262,13 @@
         SomeArgs newBroadcastArgs = SomeArgs.obtain();
         newBroadcastArgs.arg1 = record;
         newBroadcastArgs.argi1 = recordIndex;
-        newBroadcastArgs.argi2 = (wouldBeSkipped ? 1 : 0);
 
         // Cross-broadcast prioritization policy:  some broadcasts might warrant being
         // issued ahead of others that are already pending, for example if this new
         // broadcast is in a different delivery class or is tied to a direct user interaction
         // with implicit responsiveness expectations.
         getQueueForBroadcast(record).addLast(newBroadcastArgs);
-        onBroadcastEnqueued(record, recordIndex, wouldBeSkipped);
+        onBroadcastEnqueued(record, recordIndex);
         return null;
     }
 
@@ -285,10 +282,9 @@
      *         wasn't any broadcast that was replaced.
      */
     @Nullable
-    private BroadcastRecord replaceBroadcast(@NonNull BroadcastRecord record, int recordIndex,
-            boolean wouldBeSkipped) {
+    private BroadcastRecord replaceBroadcast(@NonNull BroadcastRecord record, int recordIndex) {
         final ArrayDeque<SomeArgs> queue = getQueueForBroadcast(record);
-        return replaceBroadcastInQueue(queue, record, recordIndex, wouldBeSkipped);
+        return replaceBroadcastInQueue(queue, record, recordIndex);
     }
 
     /**
@@ -302,15 +298,13 @@
      */
     @Nullable
     private BroadcastRecord replaceBroadcastInQueue(@NonNull ArrayDeque<SomeArgs> queue,
-            @NonNull BroadcastRecord record, int recordIndex,
-            boolean wouldBeSkipped) {
+            @NonNull BroadcastRecord record, int recordIndex) {
         final Iterator<SomeArgs> it = queue.descendingIterator();
         final Object receiver = record.receivers.get(recordIndex);
         while (it.hasNext()) {
             final SomeArgs args = it.next();
             final BroadcastRecord testRecord = (BroadcastRecord) args.arg1;
             final int testRecordIndex = args.argi1;
-            final boolean testWouldBeSkipped = (args.argi2 == 1);
             final Object testReceiver = testRecord.receivers.get(testRecordIndex);
             if ((record.callingUid == testRecord.callingUid)
                     && (record.userId == testRecord.userId)
@@ -320,10 +314,9 @@
                 // Exact match found; perform in-place swap
                 args.arg1 = record;
                 args.argi1 = recordIndex;
-                args.argi2 = (wouldBeSkipped ? 1 : 0);
                 record.copyEnqueueTimeFrom(testRecord);
-                onBroadcastDequeued(testRecord, testRecordIndex, testWouldBeSkipped);
-                onBroadcastEnqueued(record, recordIndex, wouldBeSkipped);
+                onBroadcastDequeued(testRecord, testRecordIndex);
+                onBroadcastEnqueued(record, recordIndex);
                 return testRecord;
             }
         }
@@ -383,13 +376,12 @@
             final SomeArgs args = it.next();
             final BroadcastRecord record = (BroadcastRecord) args.arg1;
             final int recordIndex = args.argi1;
-            final boolean recordWouldBeSkipped = (args.argi2 == 1);
             if (predicate.test(record, recordIndex)) {
                 consumer.accept(record, recordIndex);
                 if (andRemove) {
                     args.recycle();
                     it.remove();
-                    onBroadcastDequeued(record, recordIndex, recordWouldBeSkipped);
+                    onBroadcastDequeued(record, recordIndex);
                 } else {
                     // Even if we're leaving broadcast in queue, it may have
                     // been mutated in such a way to change our runnable time
@@ -539,12 +531,11 @@
         final SomeArgs next = removeNextBroadcast();
         mActive = (BroadcastRecord) next.arg1;
         mActiveIndex = next.argi1;
-        final boolean wouldBeSkipped = (next.argi2 == 1);
         mActiveCountSinceIdle++;
         mActiveViaColdStart = false;
         mActiveWasStopped = false;
         next.recycle();
-        onBroadcastDequeued(mActive, mActiveIndex, wouldBeSkipped);
+        onBroadcastDequeued(mActive, mActiveIndex);
     }
 
     /**
@@ -561,8 +552,7 @@
     /**
      * Update summary statistics when the given record has been enqueued.
      */
-    private void onBroadcastEnqueued(@NonNull BroadcastRecord record, int recordIndex,
-            boolean wouldBeSkipped) {
+    private void onBroadcastEnqueued(@NonNull BroadcastRecord record, int recordIndex) {
         mCountEnqueued++;
         if (record.deferUntilActive) {
             mCountDeferred++;
@@ -594,8 +584,7 @@
         if (record.callerInstrumented) {
             mCountInstrumented++;
         }
-        if (!wouldBeSkipped
-                && (record.receivers.get(recordIndex) instanceof ResolveInfo)) {
+        if (record.receivers.get(recordIndex) instanceof ResolveInfo) {
             mCountManifest++;
         }
         invalidateRunnableAt();
@@ -604,8 +593,7 @@
     /**
      * Update summary statistics when the given record has been dequeued.
      */
-    private void onBroadcastDequeued(@NonNull BroadcastRecord record, int recordIndex,
-            boolean wouldBeSkipped) {
+    private void onBroadcastDequeued(@NonNull BroadcastRecord record, int recordIndex) {
         mCountEnqueued--;
         if (record.deferUntilActive) {
             mCountDeferred--;
@@ -637,8 +625,7 @@
         if (record.callerInstrumented) {
             mCountInstrumented--;
         }
-        if (!wouldBeSkipped
-                && (record.receivers.get(recordIndex) instanceof ResolveInfo)) {
+        if (record.receivers.get(recordIndex) instanceof ResolveInfo) {
             mCountManifest--;
         }
         invalidateRunnableAt();
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
index 8735f8a..96e1523 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@@ -606,24 +606,18 @@
             final BroadcastProcessQueue queue = getOrCreateProcessQueue(
                     getReceiverProcessName(receiver), getReceiverUid(receiver));
 
-            boolean wouldBeSkipped = false;
-            if (receiver instanceof ResolveInfo) {
-                // If the app is running but would not have been started if the process weren't
-                // running, we're going to deliver the broadcast but mark that it's not a manifest
-                // broadcast that would have started the app. This allows BroadcastProcessQueue to
-                // defer the broadcast as though it were a normal runtime receiver.
-                wouldBeSkipped = (mSkipPolicy.shouldSkipMessage(r, receiver) != null);
-                if (wouldBeSkipped && queue.app == null && !queue.getActiveViaColdStart()) {
-                    // Skip receiver if there's no running app, the app is not being started, and
-                    // the app wouldn't be launched for this broadcast
-                    setDeliveryState(null, null, r, i, receiver, BroadcastRecord.DELIVERY_SKIPPED,
-                            "skipped by policy to avoid cold start");
-                    continue;
-                }
+            // If this receiver is going to be skipped, skip it now itself and don't even enqueue
+            // it.
+            final boolean wouldBeSkipped = (mSkipPolicy.shouldSkipMessage(r, receiver) != null);
+            if (wouldBeSkipped) {
+                setDeliveryState(null, null, r, i, receiver, BroadcastRecord.DELIVERY_SKIPPED,
+                        "skipped by policy at enqueue");
+                continue;
             }
+
             enqueuedBroadcast = true;
             final BroadcastRecord replacedBroadcast = queue.enqueueOrReplaceBroadcast(
-                    r, i, wouldBeSkipped, mBroadcastConsumerDeferApply);
+                    r, i, mBroadcastConsumerDeferApply);
             if (replacedBroadcast != null) {
                 replacedBroadcasts.add(replacedBroadcast);
             }
diff --git a/services/core/java/com/android/server/broadcastradio/RadioServiceUserController.java b/services/core/java/com/android/server/broadcastradio/RadioServiceUserController.java
index 38b3233..4b847a2 100644
--- a/services/core/java/com/android/server/broadcastradio/RadioServiceUserController.java
+++ b/services/core/java/com/android/server/broadcastradio/RadioServiceUserController.java
@@ -39,18 +39,24 @@
      */
     public static boolean isCurrentOrSystemUser() {
         int callingUser = Binder.getCallingUserHandle().getIdentifier();
+        return callingUser == getCurrentUser() || callingUser == UserHandle.USER_SYSTEM;
+    }
+
+    /**
+     * Get current foreground user for Broadcast Radio Service
+     *
+     * @return foreground user id.
+     */
+    public static int getCurrentUser() {
         final long identity = Binder.clearCallingIdentity();
+        int userId = UserHandle.USER_NULL;
         try {
-            int currentUser = ActivityManager.getCurrentUser();
-            if (callingUser != currentUser && callingUser != UserHandle.USER_SYSTEM) {
-                return false;
-            }
-            return true;
+            userId = ActivityManager.getCurrentUser();
         } catch (RuntimeException e) {
             // Activity manager not running, nothing we can do assume user 0.
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
-        return false;
+        return userId;
     }
 }
diff --git a/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java b/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java
index 132fb8e..7c87c6c 100644
--- a/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java
+++ b/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java
@@ -36,11 +36,13 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.util.ArraySet;
 import android.util.IndentingPrintWriter;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.broadcastradio.RadioServiceUserController;
 import com.android.server.utils.Slogf;
 
 import java.util.ArrayList;
@@ -419,8 +421,13 @@
 
     @GuardedBy("mLock")
     private void fanoutAidlCallbackLocked(AidlCallbackRunnable runnable) {
+        int currentUserId = RadioServiceUserController.getCurrentUser();
         List<TunerSession> deadSessions = null;
         for (int i = 0; i < mAidlTunerSessions.size(); i++) {
+            if (mAidlTunerSessions.valueAt(i).mUserId != currentUserId
+                    && mAidlTunerSessions.valueAt(i).mUserId != UserHandle.USER_SYSTEM) {
+                continue;
+            }
             try {
                 runnable.run(mAidlTunerSessions.valueAt(i).mCallback,
                         mAidlTunerSessions.valueAt(i).getUid());
diff --git a/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java b/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java
index 0a3823f..beff7bd 100644
--- a/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java
+++ b/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java
@@ -46,6 +46,7 @@
 
     private final RadioLogger mLogger;
     private final RadioModule mModule;
+    final int mUserId;
     final android.hardware.radio.ITunerCallback mCallback;
     private final int mUid;
     private final IBroadcastRadio mService;
@@ -65,6 +66,7 @@
             android.hardware.radio.ITunerCallback callback) {
         mModule = Objects.requireNonNull(radioModule, "radioModule cannot be null");
         mService = Objects.requireNonNull(service, "service cannot be null");
+        mUserId = Binder.getCallingUserHandle().getIdentifier();
         mCallback = Objects.requireNonNull(callback, "callback cannot be null");
         mUid = Binder.getCallingUid();
         mLogger = new RadioLogger(TAG, TUNER_EVENT_LOGGER_QUEUE_SIZE);
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
index 59a8154..7b5cb898 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
@@ -38,12 +38,14 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.util.IndentingPrintWriter;
 import android.util.MutableInt;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.broadcastradio.RadioServiceUserController;
 
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -374,8 +376,13 @@
 
     @GuardedBy("mLock")
     private void fanoutAidlCallbackLocked(AidlCallbackRunnable runnable) {
+        int currentUserId = RadioServiceUserController.getCurrentUser();
         List<TunerSession> deadSessions = null;
         for (TunerSession tunerSession : mAidlTunerSessions) {
+            if (tunerSession.mUserId != currentUserId && tunerSession.mUserId
+                    != UserHandle.USER_SYSTEM) {
+                continue;
+            }
             try {
                 runnable.run(tunerSession.mCallback);
             } catch (DeadObjectException ex) {
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
index 204b964..1efc4a5 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
@@ -26,6 +26,7 @@
 import android.hardware.radio.ProgramList;
 import android.hardware.radio.ProgramSelector;
 import android.hardware.radio.RadioManager;
+import android.os.Binder;
 import android.os.RemoteException;
 import android.util.ArrayMap;
 import android.util.IndentingPrintWriter;
@@ -52,6 +53,7 @@
 
     private final RadioModule mModule;
     private final ITunerSession mHwSession;
+    final int mUserId;
     final android.hardware.radio.ITunerCallback mCallback;
 
     @GuardedBy("mLock")
@@ -68,6 +70,7 @@
             @NonNull android.hardware.radio.ITunerCallback callback) {
         mModule = Objects.requireNonNull(module);
         mHwSession = Objects.requireNonNull(hwSession);
+        mUserId = Binder.getCallingUserHandle().getIdentifier();
         mCallback = Objects.requireNonNull(callback);
         mEventLogger = new RadioEventLogger(TAG, TUNER_EVENT_LOGGER_QUEUE_SIZE);
     }
diff --git a/services/core/java/com/android/server/cpu/CpuMonitorService.java b/services/core/java/com/android/server/cpu/CpuMonitorService.java
index df8cfad..7ea2c1b 100644
--- a/services/core/java/com/android/server/cpu/CpuMonitorService.java
+++ b/services/core/java/com/android/server/cpu/CpuMonitorService.java
@@ -653,8 +653,17 @@
             }
 
             public int getAverageAvailableCpuFreqPercent() {
-                return (int) ((totalNormalizedAvailableCpuFreqKHz * 100.0)
+                int percent = (int) ((totalNormalizedAvailableCpuFreqKHz * 100.0)
                         / totalOnlineMaxCpuFreqKHz);
+                if (percent < 0) {
+                    // TODO(b/279478586): This case should never happen. But this case happens
+                    // rarely on certain hardware, which indicates a deeper issue. Once this
+                    // issue is reproduced, use this log to debug the issue and fix it.
+                    Slogf.wtf(TAG, "Computed negative CPU availability percent(%d) for %s ",
+                            percent, toString());
+                    return 0;
+                }
+                return percent;
             }
 
             @Override
diff --git a/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java b/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java
index a3f8c4d..7574de8 100644
--- a/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java
+++ b/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java
@@ -437,6 +437,7 @@
      * persist the nit value, the nit value for the default display will be loaded.
      */
     private void loadNitBasedBrightnessSetting() {
+        float currentBrightnessSetting = Float.NaN;
         if (mDisplayId == Display.DEFAULT_DISPLAY && mPersistBrightnessNitsForDefaultDisplay) {
             float brightnessNitsForDefaultDisplay =
                     mBrightnessSetting.getBrightnessNitsForDefaultDisplay();
@@ -445,15 +446,17 @@
                         brightnessNitsForDefaultDisplay);
                 if (BrightnessUtils.isValidBrightnessValue(brightnessForDefaultDisplay)) {
                     mBrightnessSetting.setBrightness(brightnessForDefaultDisplay);
-                    synchronized (mLock) {
-                        mCurrentScreenBrightness = brightnessForDefaultDisplay;
-                    }
-                    return;
+                    currentBrightnessSetting = brightnessForDefaultDisplay;
                 }
             }
         }
+
+        if (Float.isNaN(currentBrightnessSetting)) {
+            currentBrightnessSetting = getScreenBrightnessSetting();
+        }
+
         synchronized (mLock) {
-            mCurrentScreenBrightness = getScreenBrightnessSetting();
+            mCurrentScreenBrightness = currentBrightnessSetting;
         }
     }
 }
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 7a51126..377b8cf 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -395,8 +395,8 @@
         synchronized (mLock) {
             final boolean consentGranted =
                     consentResult == RECORD_CONTENT_DISPLAY || consentResult == RECORD_CONTENT_TASK;
-            if (consentGranted && projection == null || !isCurrentProjection(
-                    projection.asBinder())) {
+            if (consentGranted && !isCurrentProjection(
+                    projection == null ? null : projection.asBinder())) {
                 Slog.v(TAG, "Reusing token: Ignore consent result of " + consentResult + " for a "
                         + "token that isn't current");
                 return;
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 402fb30..9b1a80be 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -1120,12 +1120,12 @@
                     return shortcutOverridesInfo;
                 }
 
-                List<String> packagesToOverride =
+                Map<String, String> packagesToOverride =
                         DevicePolicyCache.getInstance().getLauncherShortcutOverrides();
-                for (String packageName : packagesToOverride) {
+                for (Map.Entry<String, String> packageNames : packagesToOverride.entrySet()) {
                     Intent intent = new Intent(Intent.ACTION_MAIN)
                             .addCategory(Intent.CATEGORY_LAUNCHER)
-                            .setPackage(packageName);
+                            .setPackage(packageNames.getValue());
 
                     List<LauncherActivityInfoInternal> possibleShortcutOverrides =
                             queryIntentLauncherActivities(
@@ -1135,7 +1135,8 @@
                             );
 
                     if (!possibleShortcutOverrides.isEmpty()) {
-                        shortcutOverridesInfo.put(packageName, possibleShortcutOverrides.get(0));
+                        shortcutOverridesInfo.put(packageNames.getKey(),
+                                possibleShortcutOverrides.get(0));
                     }
                 }
                 return shortcutOverridesInfo;
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index b669ba2..84a9888 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -1716,6 +1716,11 @@
         if (si == null) {
             return;
         }
+
+        if (isCallerSystem()) {
+            return; // no check
+        }
+
         if (!Objects.equals(callerPackage, si.getPackage())) {
             android.util.EventLog.writeEvent(0x534e4554, "109824443", -1, "");
             throw new SecurityException("Shortcut package name mismatch");
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 51872b3..98d2d3d 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -803,6 +803,20 @@
     protected WallpaperData mLastLockWallpaper;
     private IWallpaperManagerCallback mKeyguardListener;
     private boolean mWaitingForUnlock;
+
+    /**
+     * Flag set to true after reboot if the home wallpaper is waiting for the device to be unlocked.
+     * This happens for wallpapers that are not direct-boot aware; they can only be rendered after
+     * the user unlocks the device for the first time after a reboot. In the meantime, the default
+     * wallpaper is shown instead.
+     */
+    private boolean mHomeWallpaperWaitingForUnlock;
+
+    /**
+     * Flag set to true after reboot if the lock wallpaper is waiting for the device to be unlocked.
+     */
+    private boolean mLockWallpaperWaitingForUnlock;
+
     private boolean mShuttingDown;
 
     /**
@@ -1790,7 +1804,23 @@
     public void onUnlockUser(final int userId) {
         synchronized (mLock) {
             if (mCurrentUserId == userId) {
-                if (mWaitingForUnlock) {
+                if (mIsLockscreenLiveWallpaperEnabled) {
+                    if (mHomeWallpaperWaitingForUnlock) {
+                        final WallpaperData systemWallpaper =
+                                getWallpaperSafeLocked(userId, FLAG_SYSTEM);
+                        switchWallpaper(systemWallpaper, null);
+                        // TODO(b/278261563): call notifyCallbacksLocked inside switchWallpaper
+                        notifyCallbacksLocked(systemWallpaper);
+                    }
+                    if (mLockWallpaperWaitingForUnlock) {
+                        final WallpaperData lockWallpaper =
+                                getWallpaperSafeLocked(userId, FLAG_LOCK);
+                        switchWallpaper(lockWallpaper, null);
+                        notifyCallbacksLocked(lockWallpaper);
+                    }
+                }
+
+                if (mWaitingForUnlock && !mIsLockscreenLiveWallpaperEnabled) {
                     // the desired wallpaper is not direct-boot aware, load it now
                     final WallpaperData systemWallpaper =
                             getWallpaperSafeLocked(userId, FLAG_SYSTEM);
@@ -1845,13 +1875,23 @@
                 }
                 mCurrentUserId = userId;
                 systemWallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
-                final WallpaperData tmpLockWallpaper = mLockWallpaperMap.get(userId);
-                lockWallpaper = tmpLockWallpaper == null ? systemWallpaper : tmpLockWallpaper;
+
+                if (mIsLockscreenLiveWallpaperEnabled) {
+                    lockWallpaper = systemWallpaper.mWhich == (FLAG_LOCK | FLAG_SYSTEM)
+                            ? systemWallpaper : getWallpaperSafeLocked(userId, FLAG_LOCK);
+                } else {
+                    final WallpaperData tmpLockWallpaper = mLockWallpaperMap.get(userId);
+                    lockWallpaper = tmpLockWallpaper == null ? systemWallpaper : tmpLockWallpaper;
+                }
+
                 // Not started watching yet, in case wallpaper data was loaded for other reasons.
                 if (systemWallpaper.wallpaperObserver == null) {
                     systemWallpaper.wallpaperObserver = new WallpaperObserver(systemWallpaper);
                     systemWallpaper.wallpaperObserver.startWatching();
                 }
+                if (mIsLockscreenLiveWallpaperEnabled && lockWallpaper != systemWallpaper)  {
+                    switchWallpaper(lockWallpaper, null);
+                }
                 switchWallpaper(systemWallpaper, reply);
             }
 
@@ -1870,6 +1910,11 @@
     void switchWallpaper(WallpaperData wallpaper, IRemoteCallback reply) {
         synchronized (mLock) {
             mWaitingForUnlock = false;
+            if (mIsLockscreenLiveWallpaperEnabled) {
+                if ((wallpaper.mWhich & FLAG_SYSTEM) != 0) mHomeWallpaperWaitingForUnlock = false;
+                if ((wallpaper.mWhich & FLAG_LOCK) != 0) mLockWallpaperWaitingForUnlock = false;
+            }
+
             final ComponentName cname = wallpaper.wallpaperComponent != null ?
                     wallpaper.wallpaperComponent : wallpaper.nextWallpaperComponent;
             if (!bindWallpaperComponentLocked(cname, true, false, wallpaper, reply)) {
@@ -1882,6 +1927,11 @@
                 } catch (RemoteException ignored) {
                 }
 
+                if (mIsLockscreenLiveWallpaperEnabled) {
+                    onSwitchWallpaperFailLocked(wallpaper, reply, si);
+                    return;
+                }
+
                 if (si == null) {
                     Slog.w(TAG, "Failure starting previous wallpaper; clearing");
                     clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, reply);
@@ -1899,6 +1949,43 @@
         }
     }
 
+    /**
+     * Fallback method if a wallpaper fails to load on boot or after a user switch.
+     * Only called if mIsLockscreenLiveWallpaperEnabled is true.
+     */
+    private void onSwitchWallpaperFailLocked(
+            WallpaperData wallpaper, IRemoteCallback reply, ServiceInfo serviceInfo) {
+
+        if (serviceInfo == null) {
+            Slog.w(TAG, "Failure starting previous wallpaper; clearing");
+
+            if (wallpaper.mWhich == (FLAG_LOCK | FLAG_SYSTEM)) {
+                clearWallpaperLocked(false, FLAG_SYSTEM, wallpaper.userId, null);
+                clearWallpaperLocked(false, FLAG_LOCK, wallpaper.userId, reply);
+            } else {
+                clearWallpaperLocked(false, wallpaper.mWhich, wallpaper.userId, reply);
+            }
+            return;
+        }
+        Slog.w(TAG, "Wallpaper isn't direct boot aware; using fallback until unlocked");
+        // We might end up persisting the current wallpaper data
+        // while locked, so pretend like the component was actually
+        // bound into place
+        wallpaper.wallpaperComponent = wallpaper.nextWallpaperComponent;
+        final WallpaperData fallback = new WallpaperData(wallpaper.userId, wallpaper.mWhich);
+
+        // files from the previous static wallpaper may still be stored in memory.
+        // delete them in order to show the default wallpaper.
+        if (wallpaper.wallpaperFile.exists()) {
+            wallpaper.wallpaperFile.delete();
+            wallpaper.cropFile.delete();
+        }
+
+        bindWallpaperComponentLocked(mImageWallpaper, true, false, fallback, reply);
+        if ((wallpaper.mWhich & FLAG_SYSTEM) != 0) mHomeWallpaperWaitingForUnlock = true;
+        if ((wallpaper.mWhich & FLAG_LOCK) != 0) mLockWallpaperWaitingForUnlock = true;
+    }
+
     @Override
     public void clearWallpaper(String callingPackage, int which, int userId) {
         if (DEBUG) Slog.v(TAG, "clearWallpaper");
diff --git a/services/core/java/com/android/server/wm/AbsAppSnapshotController.java b/services/core/java/com/android/server/wm/AbsAppSnapshotController.java
index 32f7b96..5c929a9 100644
--- a/services/core/java/com/android/server/wm/AbsAppSnapshotController.java
+++ b/services/core/java/com/android/server/wm/AbsAppSnapshotController.java
@@ -239,7 +239,17 @@
             }
             return null;
         }
-        source.getBounds(mTmpRect);
+        mTmpRect.setEmpty();
+        if (source.mTransitionController.inFinishingTransition(source)) {
+            final Transition.ChangeInfo changeInfo = source.mTransitionController
+                    .mFinishingTransition.mChanges.get(source);
+            if (changeInfo != null) {
+                mTmpRect.set(changeInfo.mAbsoluteBounds);
+            }
+        }
+        if (mTmpRect.isEmpty()) {
+            source.getBounds(mTmpRect);
+        }
         mTmpRect.offsetTo(0, 0);
         SurfaceControl[] excludeLayers;
         final WindowState imeWindow = source.getDisplayContent().mInputMethodWindow;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index f843b7c..78c066b 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -5296,6 +5296,10 @@
             if (isCollecting) {
                 mTransitionController.collect(this);
             } else {
+                // Failsafe to make sure that we show any activities that were incorrectly hidden
+                // during a transition. If this vis-change is a result of finishing, ignore it.
+                // Finish should only ever commit visibility=false, so we can check full containment
+                // rather than just direct membership.
                 inFinishingTransition = mTransitionController.inFinishingTransition(this);
                 if (!inFinishingTransition && !mDisplayContent.isSleeping()) {
                     Slog.e(TAG, "setVisibility=" + visible
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 4949ebc..3f4a775 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -755,4 +755,10 @@
 
     /** Unregister a task stack listener so that it stops receiving callbacks. */;
     public abstract void unregisterTaskStackListener(ITaskStackListener listener);
+
+    /**
+     * Gets the id of the display the activity was launched on.
+     * @param token The activity token.
+     */
+    public abstract int getDisplayId(IBinder token);
 }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index b377032..1f4606b 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -5816,6 +5816,18 @@
         }
 
         @Override
+        public int getDisplayId(IBinder token) {
+            synchronized (mGlobalLock) {
+                ActivityRecord r = ActivityRecord.forTokenLocked(token);
+                if (r == null) {
+                    throw new IllegalArgumentException(
+                            "setFocusedActivity: No activity record matching token=" + token);
+                }
+                return r.getDisplayId();
+            }
+        }
+
+        @Override
         public void registerScreenObserver(ScreenObserver observer) {
             mScreenObservers.add(observer);
         }
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 747819e9..ce43628 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -1882,6 +1882,12 @@
 
         static final int DECOR_TYPES = Type.displayCutout() | Type.navigationBars();
 
+        /**
+         * The types that may affect display configuration. This excludes cutout because it is
+         * known from display info.
+         */
+        static final int CONFIG_TYPES = Type.statusBars() | Type.navigationBars();
+
         private final DisplayContent mDisplayContent;
         private final Info[] mInfoForRotation = new Info[4];
         final Info mTmpInfo = new Info();
@@ -1921,7 +1927,7 @@
         final DecorInsets.Info newInfo = mDecorInsets.mTmpInfo;
         newInfo.update(mDisplayContent, rotation, dw, dh);
         final DecorInsets.Info currentInfo = getDecorInsetsInfo(rotation, dw, dh);
-        if (newInfo.mNonDecorFrame.equals(currentInfo.mNonDecorFrame)) {
+        if (newInfo.mConfigFrame.equals(currentInfo.mConfigFrame)) {
             return false;
         }
         mDecorInsets.invalidate();
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index a5e652c..a3d233d 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -123,6 +123,7 @@
 
     public final boolean isDefaultDisplay;
     private final boolean mSupportAutoRotation;
+    private final boolean mAllowRotationResolver;
     private final int mLidOpenRotation;
     private final int mCarDockRotation;
     private final int mDeskDockRotation;
@@ -272,6 +273,8 @@
 
         mSupportAutoRotation =
                 mContext.getResources().getBoolean(R.bool.config_supportAutoRotation);
+        mAllowRotationResolver =
+                mContext.getResources().getBoolean(R.bool.config_allowRotationResolver);
         mLidOpenRotation = readRotation(R.integer.config_lidOpenRotation);
         mCarDockRotation = readRotation(R.integer.config_carDockRotation);
         mDeskDockRotation = readRotation(R.integer.config_deskDockRotation);
@@ -2041,7 +2044,8 @@
 
         @Override
         public boolean isRotationResolverEnabled() {
-            return mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE
+            return mAllowRotationResolver
+                    && mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE
                     && mCameraRotationMode == CAMERA_ROTATION_ENABLED
                     && !mService.mPowerManager.isPowerSaveMode();
         }
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index b879d1a..eb639b6 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -362,15 +362,8 @@
 
     private void invokeAnimationCancelled(String reason) {
         ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "cancelAnimation(): reason=%s", reason);
-        final boolean isKeyguardOccluded = mDisplayContent.isKeyguardOccluded();
-
         try {
-            EventLogTags.writeWmSetKeyguardOccluded(
-                    isKeyguardOccluded ? 1 : 0,
-                    0 /* animate */,
-                    0 /* transit */,
-                    "onAnimationCancelled");
-            mRemoteAnimationAdapter.getRunner().onAnimationCancelled(isKeyguardOccluded);
+            mRemoteAnimationAdapter.getRunner().onAnimationCancelled();
         } catch (RemoteException e) {
             Slog.e(TAG, "Failed to notify cancel", e);
         }
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index abc9f8a..d531ad1 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -244,6 +244,16 @@
     private IContainerFreezer mContainerFreezer = null;
     private final SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
 
+    /**
+     * {@code true} if some other operation may have caused the originally-recorded state (in
+     * mChanges) to be dirty. This is usually due to finishTransition being called mid-collect;
+     * and, the reason that finish can alter the "start" state of other transitions is because
+     * setVisible(false) is deferred until then.
+     * Instead of adding this conditional, we could re-check always; but, this situation isn't
+     * common so it'd be wasted work.
+     */
+    boolean mPriorVisibilityMightBeDirty = false;
+
     final TransitionController.Logger mLogger = new TransitionController.Logger();
 
     /** Whether this transition was forced to play early (eg for a SLEEP signal). */
@@ -966,28 +976,30 @@
         mController.mFinishingTransition = this;
 
         if (mTransientHideTasks != null && !mTransientHideTasks.isEmpty()) {
-            // Record all the now-hiding activities so that they are committed after
-            // recalculating visibilities. We just use mParticipants because we can and it will
-            // ensure proper reporting of `isInFinishTransition`.
-            for (int i = 0; i < mTransientHideTasks.size(); ++i) {
-                mTransientHideTasks.get(i).forAllActivities(r -> {
-                    // Only check leaf-tasks that were collected
-                    if (!mParticipants.contains(r.getTask())) return;
-                    // Only concern ourselves with anything that can become invisible
-                    if (!r.isVisible()) return;
-                    mParticipants.add(r);
-                });
-            }
             // The transient hide tasks could be occluded now, e.g. returning to home. So trigger
             // the update to make the activities in the tasks invisible-requested, then the next
             // step can continue to commit the visibility.
             mController.mAtm.mRootWindowContainer.ensureActivitiesVisible(null /* starting */,
                     0 /* configChanges */, true /* preserveWindows */);
+            // Record all the now-hiding activities so that they are committed. Just use
+            // mParticipants because we can avoid a new list this way.
+            for (int i = 0; i < mTransientHideTasks.size(); ++i) {
+                // Only worry about tasks that were actually hidden. Otherwise, we could end-up
+                // committing visibility for activity-level changes that aren't part of this
+                // transition.
+                if (mTransientHideTasks.get(i).isVisibleRequested()) continue;
+                mTransientHideTasks.get(i).forAllActivities(r -> {
+                    // Only check leaf-tasks that were collected
+                    if (!mParticipants.contains(r.getTask())) return;
+                    mParticipants.add(r);
+                });
+            }
         }
 
         boolean hasParticipatedDisplay = false;
         boolean hasVisibleTransientLaunch = false;
         boolean enterAutoPip = false;
+        boolean committedSomeInvisible = false;
         // Commit all going-invisible containers
         for (int i = 0; i < mParticipants.size(); ++i) {
             final WindowContainer<?> participant = mParticipants.valueAt(i);
@@ -1023,6 +1035,7 @@
                         }
                         ar.commitVisibility(false /* visible */, false /* performLayout */,
                                 true /* fromTransition */);
+                        committedSomeInvisible = true;
                     } else {
                         enterAutoPip = true;
                     }
@@ -1081,6 +1094,9 @@
                 }
             }
         }
+        if (committedSomeInvisible) {
+            mController.onCommittedInvisibles();
+        }
 
         if (hasVisibleTransientLaunch) {
             // Notify the change about the transient-below task if entering auto-pip.
@@ -1293,6 +1309,9 @@
         // leftover order changes.
         collectOrderChanges(mController.mWaitingTransitions.isEmpty());
 
+        if (mPriorVisibilityMightBeDirty) {
+            updatePriorVisibility();
+        }
         // Resolve the animating targets from the participants.
         mTargets = calculateTargets(mParticipants, mChanges);
         // Check whether the participants were animated from back navigation.
@@ -1806,6 +1825,20 @@
         }
     }
 
+    private void updatePriorVisibility() {
+        for (int i = 0; i < mChanges.size(); ++i) {
+            final ChangeInfo chg = mChanges.valueAt(i);
+            // For task/activity, recalculate the current "real" visibility.
+            if (chg.mContainer.asActivityRecord() == null && chg.mContainer.asTask() == null) {
+                continue;
+            }
+            // This ONLY works in the visible -> invisible case (and is only needed for this case)
+            // because commitVisible(false) is deferred until finish.
+            if (!chg.mVisible) continue;
+            chg.mVisible = chg.mContainer.isVisible();
+        }
+    }
+
     /**
      * Under some conditions (eg. all visible targets within a parent container are transitioning
      * the same way) the transition can be "promoted" to the parent container. This means an
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index b0feefe..7950eda 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -408,9 +408,9 @@
         return false;
     }
 
-    /** Returns {@code true} if the `wc` is a participant of the finishing transition. */
+    /** Returns {@code true} if the finishing transition contains `wc`. */
     boolean inFinishingTransition(WindowContainer<?> wc) {
-        return mFinishingTransition != null && mFinishingTransition.mParticipants.contains(wc);
+        return mFinishingTransition != null && mFinishingTransition.isInTransition(wc);
     }
 
     /** @return {@code true} if a transition is running */
@@ -827,6 +827,16 @@
         }
     }
 
+    /** Called by {@link Transition#finishTransition} if it committed invisible to any activities */
+    void onCommittedInvisibles() {
+        if (mCollectingTransition != null) {
+            mCollectingTransition.mPriorVisibilityMightBeDirty = true;
+        }
+        for (int i = mWaitingTransitions.size() - 1; i >= 0; --i) {
+            mWaitingTransitions.get(i).mPriorVisibilityMightBeDirty = true;
+        }
+    }
+
     private void validateStates() {
         for (int i = 0; i < mStateValidators.size(); ++i) {
             mStateValidators.get(i).run();
@@ -964,6 +974,7 @@
         if (sync) {
             info.setFlags(info.getFlags() | TransitionInfo.FLAG_SYNC);
         }
+        transition.mAnimationTrack = track;
         info.setTrack(track);
         mTrackCount = Math.max(mTrackCount, track + 1);
     }
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index f4a1765d..510e675 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -3839,7 +3839,8 @@
             // This can still happen if WMCore starts a new transition when there is ongoing
             // sync transaction from Shell. Please file a bug if it happens.
             throw new IllegalStateException("Can't sync on 2 groups simultaneously"
-                    + " currentSyncId=" + mSyncGroup.mSyncId + " newSyncId=" + group.mSyncId);
+                    + " currentSyncId=" + mSyncGroup.mSyncId + " newSyncId=" + group.mSyncId
+                    + " wc=" + this);
         }
         mSyncGroup = group;
     }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 40b8274..6cb6d9d 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1831,7 +1831,7 @@
 
             boolean needToSendNewConfiguration =
                     win.isVisibleRequestedOrAdding() && displayContent.updateOrientation();
-            if (win.providesNonDecorInsets()) {
+            if (win.providesDisplayDecorInsets()) {
                 needToSendNewConfiguration |= displayPolicy.updateDecorInsetsInfo();
             }
             if (needToSendNewConfiguration) {
@@ -2274,7 +2274,7 @@
                         & WindowManager.LayoutParams.SYSTEM_UI_VISIBILITY_CHANGED) != 0) {
                     win.mLayoutNeeded = true;
                 }
-                if (layoutChanged && win.providesNonDecorInsets()) {
+                if (layoutChanged && win.providesDisplayDecorInsets()) {
                     configChanged = displayPolicy.updateDecorInsetsInfo();
                 }
                 if (win.mActivityRecord != null && ((flagChanges & FLAG_SHOW_WHEN_LOCKED) != 0
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 2920652..6f07b77 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1834,13 +1834,13 @@
         return (mPolicyVisibility & POLICY_VISIBILITY_ALL) == POLICY_VISIBILITY_ALL;
     }
 
-    boolean providesNonDecorInsets() {
+    boolean providesDisplayDecorInsets() {
         if (mInsetsSourceProviders == null) {
             return false;
         }
         for (int i = mInsetsSourceProviders.size() - 1; i >= 0; i--) {
             final InsetsSource source = mInsetsSourceProviders.valueAt(i).getSource();
-            if (source.getType() == WindowInsets.Type.navigationBars()) {
+            if ((source.getType() & DisplayPolicy.DecorInsets.CONFIG_TYPES) != 0) {
                 return true;
             }
         }
@@ -2507,13 +2507,13 @@
             }
 
             // Check if window provides non decor insets before clearing its provided insets.
-            final boolean windowProvidesNonDecorInsets = providesNonDecorInsets();
+            final boolean windowProvidesDisplayDecorInsets = providesDisplayDecorInsets();
 
             removeImmediately();
             // Removing a visible window may affect the display orientation so just update it if
             // needed. Also recompute configuration if it provides screen decor insets.
             boolean needToSendNewConfiguration = wasVisible && displayContent.updateOrientation();
-            if (windowProvidesNonDecorInsets) {
+            if (windowProvidesDisplayDecorInsets) {
                 needToSendNewConfiguration |=
                         displayContent.getDisplayPolicy().updateDecorInsetsInfo();
             }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java
index 80100a9..c681b88 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java
@@ -19,13 +19,13 @@
 import android.app.admin.DevicePolicyCache;
 import android.app.admin.DevicePolicyManager;
 import android.os.UserHandle;
+import android.util.ArrayMap;
 import android.util.IndentingPrintWriter;
 import android.util.SparseIntArray;
 
 import com.android.internal.annotations.GuardedBy;
 
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Map;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
@@ -55,8 +55,7 @@
     private final SparseIntArray mPermissionPolicy = new SparseIntArray();
 
     @GuardedBy("mLock")
-    private List<String> mLauncherShortcutOverrides =
-            new ArrayList<>();
+    private ArrayMap<String, String> mLauncherShortcutOverrides = new ArrayMap<>();
 
 
     /** Maps to {@code ActiveAdmin.mAdminCanGrantSensorsPermissions}. */
@@ -130,18 +129,20 @@
     }
 
     @Override
-    public List<String> getLauncherShortcutOverrides() {
+    public Map<String, String> getLauncherShortcutOverrides() {
         synchronized (mLock) {
-            return new ArrayList<>(mLauncherShortcutOverrides);
+            return new ArrayMap<>(mLauncherShortcutOverrides);
         }
     }
 
     /**
-     * Sets a list of packages for which shortcuts should be replaced by their badged version.
+     * Sets a map of packages names to package names, for which all launcher shortcuts which
+     * match a key package name should be modified to launch the corresponding value package
+     * name in the managed profile. The overridden shortcut should be badged accordingly.
      */
-    public void setLauncherShortcutOverrides(List<String> launcherShortcutOverrides) {
+    public void setLauncherShortcutOverrides(ArrayMap<String, String> launcherShortcutOverrides) {
         synchronized (mLock) {
-            mLauncherShortcutOverrides = new ArrayList<>(launcherShortcutOverrides);
+            mLauncherShortcutOverrides = new ArrayMap<>(launcherShortcutOverrides);
         }
     }
 
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
index 415440b..cf49dcf 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
@@ -130,12 +130,11 @@
     <V> void setLocalPolicy(
             @NonNull PolicyDefinition<V> policyDefinition,
             @NonNull EnforcingAdmin enforcingAdmin,
-            @NonNull PolicyValue<V> value,
+            @Nullable PolicyValue<V> value,
             int userId,
             boolean skipEnforcePolicy) {
         Objects.requireNonNull(policyDefinition);
         Objects.requireNonNull(enforcingAdmin);
-        Objects.requireNonNull(value);
 
         synchronized (mLock) {
             PolicyState<V> localPolicyState = getLocalPolicyStateLocked(policyDefinition, userId);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 22f684b..a35f34d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -80,6 +80,7 @@
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_WINDOWS;
 import static android.Manifest.permission.MANAGE_DEVICE_POLICY_WIPE_DATA;
 import static android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS;
+import static android.Manifest.permission.MASTER_CLEAR;
 import static android.Manifest.permission.QUERY_ADMIN_POLICY;
 import static android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY;
 import static android.Manifest.permission.SET_TIME;
@@ -7552,9 +7553,9 @@
         boolean calledByProfileOwnerOnOrgOwnedDevice =
                 isProfileOwnerOfOrganizationOwnedDevice(caller.getUserId());
         if (isPolicyEngineForFinanceFlagEnabled()) {
-            EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
+            EnforcingAdmin enforcingAdmin = enforcePermissionsAndGetEnforcingAdmin(
                     /*admin=*/ null,
-                    /*permission= */ MANAGE_DEVICE_POLICY_WIPE_DATA,
+                    /*permission=*/ new String[]{MANAGE_DEVICE_POLICY_WIPE_DATA, MASTER_CLEAR},
                     USES_POLICY_WIPE_DATA,
                     caller.getPackageName(),
                     factoryReset ? UserHandle.USER_ALL : getAffectedUser(calledOnParentInstance));
@@ -7576,12 +7577,13 @@
                 admin = getActiveAdminWithPolicyForUidLocked(/* who= */ null,
                         DeviceAdminInfo.USES_POLICY_WIPE_DATA, caller.getUid());
             }
+            Preconditions.checkCallAuthorization(
+                    (admin != null) || hasCallingOrSelfPermission(permission.MASTER_CLEAR),
+                    "No active admin for user %d and caller %d does not hold MASTER_CLEAR "
+                            + "permission",
+                    caller.getUserId(), caller.getUid());
         }
 
-        Preconditions.checkCallAuthorization(
-                (admin != null) || hasCallingOrSelfPermission(permission.MASTER_CLEAR),
-                "No active admin for user %d and caller %d does not hold MASTER_CLEAR permission",
-                caller.getUserId(), caller.getUid());
         checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_WIPE_DATA);
 
         if (TextUtils.isEmpty(wipeReasonForUser)) {
@@ -7721,7 +7723,7 @@
     }
 
     private void clearLauncherShortcutOverrides() {
-        mPolicyCache.setLauncherShortcutOverrides(new ArrayList<>());
+        mPolicyCache.setLauncherShortcutOverrides(new ArrayMap<>());
     }
 
     private void updateTelephonyCrossProfileIntentFilters(int parentUserId, int profileUserId,
@@ -7836,15 +7838,14 @@
             } else {
                 // Explicit behaviour
                 if (factoryReset) {
-                    // TODO(b/254031494) Replace with new factory reset permission checks
-                    if (!isPermissionCheckFlagEnabled()) {
-                        boolean hasPermission = isDeviceOwnerUserId(userId)
-                                || (isOrganizationOwnedDeviceWithManagedProfile()
-                                && calledOnParentInstance);
-                        Preconditions.checkCallAuthorization(hasPermission,
-                                "Admin %s does not have permission to factory reset the device.",
-                                userId);
-                    }
+                    EnforcingAdmin enforcingAdmin = enforcePermissionsAndGetEnforcingAdmin(
+                            /*admin=*/ null,
+                            /*permission=*/ new String[]{MANAGE_DEVICE_POLICY_WIPE_DATA,
+                                    MASTER_CLEAR},
+                            USES_POLICY_WIPE_DATA,
+                            adminPackage,
+                            factoryReset ? UserHandle.USER_ALL :
+                                    getAffectedUser(calledOnParentInstance));
                     wipeDevice = true;
                 } else {
                     Preconditions.checkCallAuthorization(!isSystemUser,
@@ -12214,17 +12215,22 @@
         }
 
         synchronized (getLockObject()) {
-            ActiveAdmin admin;
-            if (isPermissionCheckFlagEnabled()) {
-                admin = enforcePermissionAndGetEnforcingAdmin(
-                        who, MANAGE_DEVICE_POLICY_INPUT_METHODS,
-                        caller.getPackageName(), userId).getActiveAdmin();
+            if (isPolicyEngineForFinanceFlagEnabled()) {
+                EnforcingAdmin admin = getEnforcingAdminForCaller(who, callerPackageName);
+                mDevicePolicyEngine.setLocalPolicy(
+                        PolicyDefinition.PERMITTED_INPUT_METHODS,
+                        admin,
+                        packageList == null
+                                ? null
+                                : new StringSetPolicyValue(new HashSet<>(packageList)),
+                        userId);
             } else {
-                admin = getParentOfAdminIfRequired(
-                        getProfileOwnerOrDeviceOwnerLocked(caller.getUserId()), calledOnParentInstance);
+                ActiveAdmin admin = getParentOfAdminIfRequired(
+                        getProfileOwnerOrDeviceOwnerLocked(caller.getUserId()),
+                        calledOnParentInstance);
+                admin.permittedInputMethods = packageList;
+                saveSettingsLocked(caller.getUserId());
             }
-            admin.permittedInputMethods = packageList;
-            saveSettingsLocked(caller.getUserId());
         }
 
         DevicePolicyEventLogger
@@ -12272,19 +12278,18 @@
         }
 
         synchronized (getLockObject()) {
-            ActiveAdmin admin;
-            if (isPermissionCheckFlagEnabled()) {
+            if (isPolicyEngineForFinanceFlagEnabled()) {
                 int affectedUser = calledOnParentInstance ? getProfileParentId(
                         caller.getUserId()) : caller.getUserId();
-                admin = enforcePermissionAndGetEnforcingAdmin(
-                        who, MANAGE_DEVICE_POLICY_INPUT_METHODS, caller.getPackageName(),
-                        affectedUser).getActiveAdmin();
+                Set<String> policy = mDevicePolicyEngine.getResolvedPolicy(
+                        PolicyDefinition.PERMITTED_INPUT_METHODS, affectedUser);
+                return policy == null ? null : new ArrayList<>(policy);
             } else {
-                admin = getParentOfAdminIfRequired(
+                ActiveAdmin admin = getParentOfAdminIfRequired(
                         getProfileOwnerOrDeviceOwnerLocked(
                                 caller.getUserId()), calledOnParentInstance);
+                return admin.permittedInputMethods;
             }
-            return admin.permittedInputMethods;
         }
     }
 
@@ -12302,37 +12307,45 @@
     }
 
     private @Nullable List<String> getPermittedInputMethodsUnchecked(@UserIdInt int userId) {
-        synchronized (getLockObject()) {
-            List<String> result = null;
-            // Only device or profile owners can have permitted lists set.
-            List<ActiveAdmin> admins = getActiveAdminsForAffectedUserInclPermissionBasedAdminLocked(userId);
-            for (ActiveAdmin admin: admins) {
-                List<String> fromAdmin = admin.permittedInputMethods;
-                if (fromAdmin != null) {
-                    if (result == null) {
-                        result = new ArrayList<String>(fromAdmin);
-                    } else {
-                        result.retainAll(fromAdmin);
-                    }
-                }
-            }
-
-            // If we have a permitted list add all system input methods.
-            if (result != null) {
-                List<InputMethodInfo> imes = InputMethodManagerInternal
-                        .get().getInputMethodListAsUser(userId);
-                if (imes != null) {
-                    for (InputMethodInfo ime : imes) {
-                        ServiceInfo serviceInfo = ime.getServiceInfo();
-                        ApplicationInfo applicationInfo = serviceInfo.applicationInfo;
-                        if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
-                            result.add(serviceInfo.packageName);
+        List<String> result = null;
+        if (isPolicyEngineForFinanceFlagEnabled()) {
+            Set<String> policy = mDevicePolicyEngine.getResolvedPolicy(
+                    PolicyDefinition.PERMITTED_INPUT_METHODS, userId);
+            result = policy == null ? null : new ArrayList<>(policy);
+        } else {
+            synchronized (getLockObject()) {
+                // Only device or profile owners can have permitted lists set.
+                List<ActiveAdmin> admins =
+                        getActiveAdminsForAffectedUserInclPermissionBasedAdminLocked(
+                                userId);
+                for (ActiveAdmin admin : admins) {
+                    List<String> fromAdmin = admin.permittedInputMethods;
+                    if (fromAdmin != null) {
+                        if (result == null) {
+                            result = new ArrayList<String>(fromAdmin);
+                        } else {
+                            result.retainAll(fromAdmin);
                         }
                     }
                 }
             }
-            return result;
         }
+
+        // If we have a permitted list add all system input methods.
+        if (result != null) {
+            List<InputMethodInfo> imes = InputMethodManagerInternal
+                    .get().getInputMethodListAsUser(userId);
+            if (imes != null) {
+                for (InputMethodInfo ime : imes) {
+                    ServiceInfo serviceInfo = ime.getServiceInfo();
+                    ApplicationInfo applicationInfo = serviceInfo.applicationInfo;
+                    if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+                        result.add(serviceInfo.packageName);
+                    }
+                }
+            }
+        }
+        return result;
     }
 
     @Override
@@ -12347,17 +12360,38 @@
                 String.format(NOT_SYSTEM_CALLER_MSG,
                         "query if an input method is disabled by admin"));
 
-        synchronized (getLockObject()) {
-            ActiveAdmin admin = getParentOfAdminIfRequired(
-                    getActiveAdminUncheckedLocked(who, userHandle), calledOnParentInstance);
-            if (admin == null) {
-                return false;
+        if (isPolicyEngineForFinanceFlagEnabled()) {
+            int affectedUser = calledOnParentInstance ? getProfileParentId(userHandle) : userHandle;
+            Map<EnforcingAdmin, PolicyValue<Set<String>>> policies =
+                    mDevicePolicyEngine.getLocalPoliciesSetByAdmins(
+                            PolicyDefinition.PERMITTED_INPUT_METHODS, affectedUser);
+            EnforcingAdmin admin = null;
+            for (EnforcingAdmin a : policies.keySet()) {
+                if (a.getPackageName().equals(who.getPackageName())) {
+                    if (policies.get(a).getValue() == null) {
+                        return true;
+                    } else {
+                        return checkPackagesInPermittedListOrSystem(
+                                Collections.singletonList(packageName),
+                                new ArrayList<>(policies.get(a).getValue()), affectedUser);
+                    }
+                }
             }
-            if (admin.permittedInputMethods == null) {
-                return true;
+            // Admin didn't set a policy
+            return false;
+        } else {
+            synchronized (getLockObject()) {
+                ActiveAdmin admin = getParentOfAdminIfRequired(
+                        getActiveAdminUncheckedLocked(who, userHandle), calledOnParentInstance);
+                if (admin == null) {
+                    return false;
+                }
+                if (admin.permittedInputMethods == null) {
+                    return true;
+                }
+                return checkPackagesInPermittedListOrSystem(Collections.singletonList(packageName),
+                        admin.permittedInputMethods, userHandle);
             }
-            return checkPackagesInPermittedListOrSystem(Collections.singletonList(packageName),
-                    admin.permittedInputMethods, userHandle);
         }
     }
 
@@ -21613,7 +21647,7 @@
         }
         copyAccount(targetUser, sourceUser, accountToMigrate, callerPackage);
         if (!keepAccountMigrated) {
-            removeAccount(accountToMigrate);
+            removeAccount(accountToMigrate, sourceUserId);
         }
     }
 
@@ -21657,9 +21691,10 @@
                 .write();
     }
 
-    private void removeAccount(Account account) {
-        final AccountManager accountManager =
-                mContext.getSystemService(AccountManager.class);
+    private void removeAccount(Account account, @UserIdInt int sourceUserId) {
+        final AccountManager accountManager = mContext.createContextAsUser(
+                        UserHandle.of(sourceUserId), /* flags= */ 0)
+                .getSystemService(AccountManager.class);
         final AccountManagerFuture<Bundle> bundle = accountManager.removeAccount(account,
                 null, null /* callback */, null /* handler */);
         try {
@@ -23191,6 +23226,28 @@
     }
 
     /**
+     * Checks if the calling process has been granted permission to apply a device policy on a
+     * specific user.  Only one permission provided in the list needs to be granted to pass this
+     * check.
+     * The given permissions will be checked along with their associated cross-user permissions if
+     * they exist and the target user is different to the calling user.
+     * Returns an {@link EnforcingAdmin} for the caller.
+     *
+     * @param admin the component name of the admin.
+     * @param callerPackageName The package name of the calling application.
+     * @param permissions The names of the permissions being checked.
+     * @param deviceAdminPolicy The userId of the user which the caller needs permission to act on.
+     * @throws SecurityException if the caller has not been granted the given permission,
+     * the associated cross-user permission if the caller's user is different to the target user.
+     */
+    private EnforcingAdmin enforcePermissionsAndGetEnforcingAdmin(@Nullable ComponentName admin,
+            String[] permissions, int deviceAdminPolicy, String callerPackageName,
+            int targetUserId) {
+        enforcePermissions(permissions, deviceAdminPolicy, callerPackageName, targetUserId);
+        return getEnforcingAdminForCaller(admin, callerPackageName);
+    }
+
+    /**
      * Checks whether the calling process has been granted permission to query a device policy on
      * a specific user.
      * The given permission will be checked along with its associated cross-user permission if it
@@ -23236,12 +23293,13 @@
 
     /**
      * Checks if the calling process has been granted permission to apply a device policy on a
-     * specific user.
-     * The given permission will be checked along with its associated cross-user permission if it
-     * exists and the target user is different to the calling user.
+     * specific user. Only one permission provided in the list needs to be granted to pass this
+     * check.
+     * The given permissions will be checked along with their associated cross-user permissions if
+     * they exists and the target user is different to the calling user.
      *
      * @param callerPackageName The package name  of the calling application.
-     * @param permission The name of the permission being checked.
+     * @param permissions The names of the permissions being checked.
      * @param targetUserId The userId of the user which the caller needs permission to act on.
      * @throws SecurityException if the caller has not been granted the given permission,
      * the associated cross-user permission if the caller's user is different to the target user.
@@ -23306,6 +23364,27 @@
     }
 
     /**
+     * Checks if the calling process has been granted permission to apply a device policy on a
+     * specific user.
+     * The given permission will be checked along with its associated cross-user permission if it
+     * exists and the target user is different to the calling user.
+     *
+     * @param callerPackageName The package name  of the calling application.
+     * @param adminPolicy The admin policy that should grant holders permission.
+     * @param permission The name of the permission being checked.
+     * @param targetUserId The userId of the user which the caller needs permission to act on.
+     * @throws SecurityException if the caller has not been granted the given permission,
+     * the associated cross-user permission if the caller's user is different to the target user.
+     */
+    private void enforcePermissions(String[] permissions, int adminPolicy,
+            String callerPackageName, int targetUserId) throws SecurityException {
+        if (hasAdminPolicy(adminPolicy, callerPackageName)) {
+            return;
+        }
+        enforcePermissions(permissions, callerPackageName, targetUserId);
+    }
+
+    /**
      * Checks whether the calling process has been granted permission to query a device policy on
      * a specific user.
      * The given permission will be checked along with its associated cross-user permission if it
@@ -23432,7 +23511,8 @@
         // Check for non-DPC active admins.
         admin = getActiveAdminForCaller(who, caller);
         if (admin != null) {
-            return EnforcingAdmin.createDeviceAdminEnforcingAdmin(who, userId, admin);
+            return EnforcingAdmin.createDeviceAdminEnforcingAdmin(admin.info.getComponent(), userId,
+                    admin);
         }
         admin = getUserData(userId).createOrGetPermissionBasedAdmin(userId);
         return  EnforcingAdmin.createEnforcingAdmin(caller.getPackageName(), userId, admin);
@@ -23720,15 +23800,14 @@
 
     private void updateDialerAndSmsManagedShortcutsOverrideCache(
             String defaultDialerPackageName, String defaultSmsPackageName) {
-
-        List<String> shortcutOverrides = new ArrayList<>();
+        ArrayMap<String, String> shortcutOverrides = new ArrayMap<>();
 
         if (defaultDialerPackageName != null) {
-            shortcutOverrides.add(defaultDialerPackageName);
+            shortcutOverrides.put(defaultDialerPackageName, defaultDialerPackageName);
         }
 
         if (defaultSmsPackageName != null) {
-            shortcutOverrides.add(defaultSmsPackageName);
+            shortcutOverrides.put(defaultSmsPackageName, defaultSmsPackageName);
         }
         mPolicyCache.setLauncherShortcutOverrides(shortcutOverrides);
     }
@@ -23793,6 +23872,7 @@
     public DevicePolicyState getDevicePolicyState() {
         Preconditions.checkCallAuthorization(
                 hasCallingOrSelfPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS));
+
         return mInjector.binderWithCleanCallingIdentity(mDevicePolicyEngine::getDevicePolicyState);
     }
 
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
index 638596b..43a2c9b 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
@@ -308,6 +308,13 @@
                         DevicePolicyIdentifiers.ACCOUNT_MANAGEMENT_DISABLED_POLICY, accountType));
     }
 
+    static PolicyDefinition<Set<String>> PERMITTED_INPUT_METHODS = new PolicyDefinition<>(
+            new NoArgsPolicyKey(DevicePolicyIdentifiers.PERMITTED_INPUT_METHODS_POLICY),
+            new MostRecent<>(),
+            POLICY_FLAG_LOCAL_ONLY_POLICY,
+            (Set<String> value, Context context, Integer userId, PolicyKey policyKey) -> true,
+            new StringSetPolicySerializer());
+
     private static final Map<String, PolicyDefinition<?>> POLICY_DEFINITIONS = new HashMap<>();
     private static Map<String, Integer> USER_RESTRICTION_FLAGS = new HashMap<>();
 
@@ -333,6 +340,8 @@
                 GENERIC_APPLICATION_HIDDEN);
         POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.ACCOUNT_MANAGEMENT_DISABLED_POLICY,
                 GENERIC_ACCOUNT_MANAGEMENT_DISABLED);
+        POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.PERMITTED_INPUT_METHODS_POLICY,
+                PERMITTED_INPUT_METHODS);
 
         // User Restriction Policies
         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_MODIFY_ACCOUNTS, /* flags= */ 0);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyState.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyState.java
index 741f209..dd4c6af 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyState.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyState.java
@@ -67,9 +67,8 @@
     /**
      * Returns {@code true} if the resolved policy has changed, {@code false} otherwise.
      */
-    boolean addPolicy(@NonNull EnforcingAdmin admin, @NonNull PolicyValue<V> policy) {
+    boolean addPolicy(@NonNull EnforcingAdmin admin, @Nullable PolicyValue<V> policy) {
         Objects.requireNonNull(admin);
-        Objects.requireNonNull(policy);
 
         //LinkedHashMap doesn't update the insertion order of existing keys, removing the existing
         // key will cause it to update.
@@ -89,9 +88,9 @@
      * Returns {@code true} if the resolved policy has changed, {@code false} otherwise.
      */
     boolean addPolicy(
-            @NonNull EnforcingAdmin admin, @NonNull PolicyValue<V> policy,
+            @NonNull EnforcingAdmin admin, @Nullable PolicyValue<V> policy,
             LinkedHashMap<EnforcingAdmin, PolicyValue<V>> globalPoliciesSetByAdmins) {
-        mPoliciesSetByAdmins.put(Objects.requireNonNull(admin), Objects.requireNonNull(policy));
+        mPoliciesSetByAdmins.put(Objects.requireNonNull(admin), policy);
 
         return resolvePolicy(globalPoliciesSetByAdmins);
     }
@@ -210,10 +209,12 @@
         for (EnforcingAdmin admin : mPoliciesSetByAdmins.keySet()) {
             serializer.startTag(/* namespace= */ null, TAG_ADMIN_POLICY_ENTRY);
 
-            serializer.startTag(/* namespace= */ null, TAG_POLICY_VALUE_ENTRY);
-            mPolicyDefinition.savePolicyValueToXml(
-                    serializer, mPoliciesSetByAdmins.get(admin).getValue());
-            serializer.endTag(/* namespace= */ null, TAG_POLICY_VALUE_ENTRY);
+            if (mPoliciesSetByAdmins.get(admin) != null) {
+                serializer.startTag(/* namespace= */ null, TAG_POLICY_VALUE_ENTRY);
+                mPolicyDefinition.savePolicyValueToXml(
+                        serializer, mPoliciesSetByAdmins.get(admin).getValue());
+                serializer.endTag(/* namespace= */ null, TAG_POLICY_VALUE_ENTRY);
+            }
 
             serializer.startTag(/* namespace= */ null, TAG_ENFORCING_ADMIN_ENTRY);
             admin.saveToXml(serializer);
@@ -250,7 +251,7 @@
                                 break;
                         }
                     }
-                    if (admin != null && value != null) {
+                    if (admin != null) {
                         policiesSetByAdmins.put(admin, value);
                     } else {
                         Log.e(TAG, "Error Parsing TAG_ADMIN_POLICY_ENTRY");
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index a5adf3f..f1d4de9 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -54,6 +54,7 @@
 import static com.android.server.SystemTimeZone.TIME_ZONE_CONFIDENCE_HIGH;
 import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_ALLOW_LIST;
 import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_COMPAT;
+import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_LISTENER;
 import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_NOT_APPLICABLE;
 import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_PERMISSION;
 import static com.android.server.alarm.Alarm.EXACT_ALLOW_REASON_POLICY_PERMISSION;
@@ -2728,6 +2729,66 @@
     }
 
     @Test
+    public void exactListenerBinderCallWithoutPermissionWithoutAllowlist() throws RemoteException {
+        mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
+        mockChangeEnabled(AlarmManager.ENABLE_USE_EXACT_ALARM, true);
+
+        mockScheduleExactAlarmState(false);
+        mockUseExactAlarmState(false);
+        when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(false);
+
+        final IAlarmListener listener = getNewListener(() -> {});
+        mBinder.set(TEST_CALLING_PACKAGE, ELAPSED_REALTIME_WAKEUP, 1234, WINDOW_EXACT, 0,
+                0, null, listener, "test-tag", null, null);
+
+        verify(mService, never()).hasUseExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID);
+        verify(mService, never()).hasScheduleExactAlarmInternal(TEST_CALLING_PACKAGE,
+                TEST_CALLING_UID);
+        verify(mDeviceIdleInternal, never()).isAppOnWhitelist(anyInt());
+
+        final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
+        verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
+                isNull(), eq(listener), eq("test-tag"), eq(FLAG_STANDALONE), isNull(), isNull(),
+                eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture(),
+                eq(EXACT_ALLOW_REASON_LISTENER));
+
+        final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
+        final int type = idleOptions.getTemporaryAppAllowlistType();
+        assertEquals(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, type);
+    }
+
+    @Test
+    public void exactAllowWhileIdleListenerBinderCallWithoutPermissionWithoutAllowlist()
+            throws RemoteException {
+        mockChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION, true);
+        mockChangeEnabled(AlarmManager.ENABLE_USE_EXACT_ALARM, true);
+
+        mockScheduleExactAlarmState(false);
+        mockUseExactAlarmState(false);
+        when(mDeviceIdleInternal.isAppOnWhitelist(anyInt())).thenReturn(false);
+
+        final IAlarmListener listener = getNewListener(() -> {});
+        mBinder.set(TEST_CALLING_PACKAGE, ELAPSED_REALTIME_WAKEUP, 1234, WINDOW_EXACT, 0,
+                FLAG_ALLOW_WHILE_IDLE, null, listener, "test-tag", null, null);
+
+        verify(mService, never()).hasUseExactAlarmInternal(TEST_CALLING_PACKAGE, TEST_CALLING_UID);
+        verify(mService, never()).hasScheduleExactAlarmInternal(TEST_CALLING_PACKAGE,
+                TEST_CALLING_UID);
+        verify(mDeviceIdleInternal, never()).isAppOnWhitelist(anyInt());
+
+        final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
+        verify(mService).setImpl(eq(ELAPSED_REALTIME_WAKEUP), eq(1234L), eq(WINDOW_EXACT), eq(0L),
+                isNull(), eq(listener), eq("test-tag"),
+                eq(FLAG_STANDALONE | FLAG_ALLOW_WHILE_IDLE_COMPAT), isNull(), isNull(),
+                eq(TEST_CALLING_UID), eq(TEST_CALLING_PACKAGE), bundleCaptor.capture(),
+                eq(EXACT_ALLOW_REASON_LISTENER));
+
+        final BroadcastOptions idleOptions = new BroadcastOptions(bundleCaptor.getValue());
+        final int type = idleOptions.getTemporaryAppAllowlistType();
+        assertEquals(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED, type);
+    }
+
+    @Test
     public void inexactAllowWhileIdleBinderCall() throws RemoteException {
         // Both permission and power exemption status don't matter for these alarms.
         // We only want to test that the flags and idleOptions are correct.
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
index 3fb7fb4..acfea85 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
@@ -40,6 +40,7 @@
 import static com.android.server.am.BroadcastQueueTest.getUidForPackage;
 import static com.android.server.am.BroadcastQueueTest.makeManifestReceiver;
 import static com.android.server.am.BroadcastQueueTest.withPriority;
+import static com.android.server.am.BroadcastRecord.isReceiverEquals;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -49,13 +50,16 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 
 import android.annotation.NonNull;
@@ -116,6 +120,7 @@
     TestLooperManager mLooper;
 
     BroadcastConstants mConstants;
+    private BroadcastSkipPolicy mSkipPolicy;
     BroadcastQueueModernImpl mImpl;
 
     BroadcastProcessQueue mHead;
@@ -139,29 +144,18 @@
         mConstants.DELAY_NORMAL_MILLIS = 10_000;
         mConstants.DELAY_CACHED_MILLIS = 120_000;
 
-        final BroadcastSkipPolicy emptySkipPolicy = new BroadcastSkipPolicy(mAms) {
-            public boolean shouldSkip(BroadcastRecord r, Object o) {
-                // Ignored
-                return false;
-            }
-            public String shouldSkipMessage(BroadcastRecord r, Object o) {
-                // Ignored
-                return null;
-            }
-            public boolean disallowBackgroundStart(BroadcastRecord r) {
-                // Ignored
-                return false;
-            }
-        };
+        mSkipPolicy = spy(new BroadcastSkipPolicy(mAms));
+        doReturn(null).when(mSkipPolicy).shouldSkipMessage(any(), any());
+        doReturn(false).when(mSkipPolicy).disallowBackgroundStart(any());
+
         final BroadcastHistory emptyHistory = new BroadcastHistory(mConstants) {
             public void addBroadcastToHistoryLocked(BroadcastRecord original) {
                 // Ignored
             }
         };
 
-
         mImpl = new BroadcastQueueModernImpl(mAms, mHandlerThread.getThreadHandler(),
-            mConstants, mConstants, emptySkipPolicy, emptyHistory);
+            mConstants, mConstants, mSkipPolicy, emptyHistory);
 
         doReturn(1L).when(mQueue1).getRunnableAt();
         doReturn(2L).when(mQueue2).getRunnableAt();
@@ -256,17 +250,12 @@
 
     private void enqueueOrReplaceBroadcast(BroadcastProcessQueue queue,
             BroadcastRecord record, int recordIndex) {
-        enqueueOrReplaceBroadcast(queue, record, recordIndex, false, 42_000_000L);
+        enqueueOrReplaceBroadcast(queue, record, recordIndex, 42_000_000L);
     }
 
     private void enqueueOrReplaceBroadcast(BroadcastProcessQueue queue,
             BroadcastRecord record, int recordIndex, long enqueueTime) {
-        enqueueOrReplaceBroadcast(queue, record, recordIndex, false, enqueueTime);
-    }
-
-    private void enqueueOrReplaceBroadcast(BroadcastProcessQueue queue,
-            BroadcastRecord record, int recordIndex, boolean wouldBeSkipped, long enqueueTime) {
-        queue.enqueueOrReplaceBroadcast(record, recordIndex, wouldBeSkipped, (r, i) -> {
+        queue.enqueueOrReplaceBroadcast(record, recordIndex, (r, i) -> {
             throw new UnsupportedOperationException();
         });
         record.enqueueTime = enqueueTime;
@@ -1199,6 +1188,42 @@
         assertEquals(ProcessList.SCHED_GROUP_DEFAULT, queue.getPreferredSchedulingGroupLocked());
     }
 
+    @Test
+    public void testSkipPolicy_atEnqueueTime() throws Exception {
+        final Intent userPresent = new Intent(Intent.ACTION_USER_PRESENT);
+        final Object greenReceiver = makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN);
+        final Object redReceiver = makeManifestReceiver(PACKAGE_RED, CLASS_RED);
+
+        final BroadcastRecord userPresentRecord = makeBroadcastRecord(userPresent,
+                List.of(greenReceiver, redReceiver));
+
+        final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK);
+        final BroadcastRecord timeTickRecord = makeBroadcastRecord(timeTick,
+                List.of(greenReceiver, redReceiver));
+
+        doAnswer(invocation -> {
+            final BroadcastRecord r = invocation.getArgument(0);
+            final Object o = invocation.getArgument(1);
+            if (userPresent.getAction().equals(r.intent.getAction())
+                    && isReceiverEquals(o, greenReceiver)) {
+                return "receiver skipped by test";
+            }
+            return null;
+        }).when(mSkipPolicy).shouldSkipMessage(any(BroadcastRecord.class), any());
+
+        mImpl.enqueueBroadcastLocked(userPresentRecord);
+        mImpl.enqueueBroadcastLocked(timeTickRecord);
+
+        final BroadcastProcessQueue greenQueue = mImpl.getProcessQueue(PACKAGE_GREEN,
+                getUidForPackage(PACKAGE_GREEN));
+        // There should be only one broadcast for green process as the other would have
+        // been skipped.
+        verifyPendingRecords(greenQueue, List.of(timeTick));
+        final BroadcastProcessQueue redQueue = mImpl.getProcessQueue(PACKAGE_RED,
+                getUidForPackage(PACKAGE_RED));
+        verifyPendingRecords(redQueue, List.of(userPresent, timeTick));
+    }
+
     private Intent createPackageChangedIntent(int uid, List<String> componentNameList) {
         final Intent packageChangedIntent = new Intent(Intent.ACTION_PACKAGE_CHANGED);
         packageChangedIntent.putExtra(Intent.EXTRA_UID, uid);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
index 96eca71..8cfc150 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
@@ -281,8 +281,8 @@
     @Test
     public void testRegisterProxy() throws Exception {
         mA11yms.registerProxyForDisplay(mMockServiceClient, TEST_DISPLAY);
-        verify(mProxyManager).registerProxy(eq(mMockServiceClient), eq(TEST_DISPLAY),
-                eq(mTestableContext), anyInt(), any(), eq(mMockSecurityPolicy),
+        verify(mProxyManager).registerProxy(eq(mMockServiceClient), eq(TEST_DISPLAY), anyInt(),
+                eq(mMockSecurityPolicy),
                 eq(mA11yms), eq(mA11yms.getTraceManager()),
                 eq(mMockWindowManagerService));
     }
@@ -295,7 +295,7 @@
 
         assertThrows(SecurityException.class,
                 () -> mA11yms.registerProxyForDisplay(mMockServiceClient, TEST_DISPLAY));
-        verify(mProxyManager, never()).registerProxy(any(), anyInt(), any(), anyInt(), any(), any(),
+        verify(mProxyManager, never()).registerProxy(any(), anyInt(), anyInt(), any(),
                 any(), any(), any());
     }
 
@@ -307,7 +307,7 @@
 
         assertThrows(SecurityException.class,
                 () -> mA11yms.registerProxyForDisplay(mMockServiceClient, TEST_DISPLAY));
-        verify(mProxyManager, never()).registerProxy(any(), anyInt(), any(), anyInt(), any(), any(),
+        verify(mProxyManager, never()).registerProxy(any(), anyInt(), anyInt(), any(),
                 any(), any(), any());
     }
 
@@ -316,7 +316,7 @@
     public void testRegisterProxyForDefaultDisplay() throws Exception {
         assertThrows(IllegalArgumentException.class,
                 () -> mA11yms.registerProxyForDisplay(mMockServiceClient, Display.DEFAULT_DISPLAY));
-        verify(mProxyManager, never()).registerProxy(any(), anyInt(), any(), anyInt(), any(), any(),
+        verify(mProxyManager, never()).registerProxy(any(), anyInt(), anyInt(), any(),
                 any(), any(), any());
     }
 
@@ -325,7 +325,7 @@
     public void testRegisterProxyForInvalidDisplay() throws Exception {
         assertThrows(IllegalArgumentException.class,
                 () -> mA11yms.registerProxyForDisplay(mMockServiceClient, Display.INVALID_DISPLAY));
-        verify(mProxyManager, never()).registerProxy(any(), anyInt(), any(), anyInt(), any(), any(),
+        verify(mProxyManager, never()).registerProxy(any(), anyInt(), anyInt(), any(),
                 any(), any(), any());
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java
index eb6670e..8f0d014 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilitySecurityPolicyTest.java
@@ -146,7 +146,7 @@
     @Mock
     private PolicyWarningUIController mPolicyWarningUIController;
     @Mock
-    private PackageManagerInternal mPackageManagerInternal;
+    private PackageManagerInternal mMockPackageManagerInternal;
 
     @Before
     public void setUp() {
@@ -158,7 +158,8 @@
                 R.dimen.accessibility_focus_highlight_stroke_width, 1);
 
         mA11ySecurityPolicy = new AccessibilitySecurityPolicy(
-                mPolicyWarningUIController, mContext, mMockA11yUserManager);
+                mPolicyWarningUIController, mContext, mMockA11yUserManager,
+                mMockPackageManagerInternal);
         mA11ySecurityPolicy.setSendingNonA11yToolNotificationLocked(true);
         mA11ySecurityPolicy.setAccessibilityWindowManager(mMockA11yWindowManager);
         mA11ySecurityPolicy.setAppWidgetManager(mMockAppWidgetManager);
@@ -237,8 +238,8 @@
     @Test
     public void resolveValidReportedPackage_uidAndPkgNameMatched_returnPkgName()
             throws PackageManager.NameNotFoundException {
-        when(mMockPackageManager.getPackageUidAsUser(PACKAGE_NAME,
-                PackageManager.MATCH_ANY_USER, TEST_USER_ID)).thenReturn(APP_UID);
+        when(mMockPackageManagerInternal.isSameApp(PACKAGE_NAME, APP_UID, TEST_USER_ID))
+                .thenReturn(true);
 
         assertEquals(mA11ySecurityPolicy.resolveValidReportedPackageLocked(
                 PACKAGE_NAME, APP_UID, TEST_USER_ID, APP_PID),
@@ -257,8 +258,8 @@
 
         when(mMockAppWidgetManager.getHostedWidgetPackages(widgetHostUid))
                 .thenReturn(widgetPackages);
-        when(mMockPackageManager.getPackageUidAsUser(hostPackageName, TEST_USER_ID))
-                .thenReturn(widgetHostUid);
+        when(mMockPackageManagerInternal.isSameApp(hostPackageName, widgetHostUid, TEST_USER_ID))
+                .thenReturn(true);
 
         assertEquals(mA11ySecurityPolicy.resolveValidReportedPackageLocked(
                 widgetPackageName, widgetHostUid, TEST_USER_ID, widgetHostPid),
@@ -272,8 +273,8 @@
         final String[] uidPackages = {PACKAGE_NAME, PACKAGE_NAME2};
         when(mMockPackageManager.getPackagesForUid(APP_UID))
                 .thenReturn(uidPackages);
-        when(mMockPackageManager.getPackageUidAsUser(invalidPackageName, TEST_USER_ID))
-                .thenThrow(PackageManager.NameNotFoundException.class);
+        when(mMockPackageManagerInternal.isSameApp(invalidPackageName, APP_UID, TEST_USER_ID))
+                .thenReturn(false);
         when(mMockAppWidgetManager.getHostedWidgetPackages(APP_UID))
                 .thenReturn(new ArraySet<>());
         mContext.getTestablePermissions().setPermission(
@@ -292,8 +293,8 @@
         final String[] uidPackages = {PACKAGE_NAME};
         when(mMockPackageManager.getPackagesForUid(APP_UID))
                 .thenReturn(uidPackages);
-        when(mMockPackageManager.getPackageUidAsUser(wantedPackageName, TEST_USER_ID))
-                .thenReturn(wantedUid);
+        when(mMockPackageManagerInternal.isSameApp(wantedPackageName, wantedUid, TEST_USER_ID))
+                .thenReturn(true);
         when(mMockAppWidgetManager.getHostedWidgetPackages(APP_UID))
                 .thenReturn(new ArraySet<>());
         mContext.getTestablePermissions().setPermission(
@@ -312,8 +313,8 @@
         final String[] uidPackages = {PACKAGE_NAME};
         when(mMockPackageManager.getPackagesForUid(APP_UID))
                 .thenReturn(uidPackages);
-        when(mMockPackageManager.getPackageUidAsUser(wantedPackageName, TEST_USER_ID))
-                .thenReturn(wantedUid);
+        when(mMockPackageManagerInternal.isSameApp(wantedPackageName, wantedUid, TEST_USER_ID))
+                .thenReturn(true);
         when(mMockAppWidgetManager.getHostedWidgetPackages(APP_UID))
                 .thenReturn(new ArraySet<>());
         mContext.getTestablePermissions().setPermission(
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/ProxyAccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/ProxyAccessibilityServiceConnectionTest.java
index dd44a79..6ac3658 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/ProxyAccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/ProxyAccessibilityServiceConnectionTest.java
@@ -29,12 +29,14 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.res.Resources;
+import android.graphics.Color;
 import android.os.Handler;
 import android.view.accessibility.AccessibilityEvent;
 
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -79,12 +81,15 @@
     WindowManagerInternal mMockWindowManagerInternal;
     ProxyAccessibilityServiceConnection mProxyConnection;
     AccessibilityServiceInfo mAccessibilityServiceInfo;
+    private int mFocusStrokeWidthDefaultValue;
+    private int mFocusColorDefaultValue;
 
     @Before
     public void setup() {
         final Resources resources = getInstrumentation().getContext().getResources();
         MockitoAnnotations.initMocks(this);
         when(mMockContext.getResources()).thenReturn(resources);
+        when(mMockSecurityPolicy.checkAccessibilityAccess(any())).thenReturn(true);
 
         mAccessibilityServiceInfo = new AccessibilityServiceInfo();
         mProxyConnection = new ProxyAccessibilityServiceConnection(mMockContext, COMPONENT_NAME,
@@ -92,10 +97,13 @@
                         getInstrumentation().getContext().getMainLooper()),
                 mMockLock, mMockSecurityPolicy, mMockSystemSupport, mMockA11yTrace,
                 mMockWindowManagerInternal, mMockA11yWindowManager, DISPLAY_ID, DEVICE_ID);
+
+        mFocusStrokeWidthDefaultValue = mProxyConnection.getFocusStrokeWidthLocked();
+        mFocusColorDefaultValue = mProxyConnection.getFocusColorLocked();
     }
 
     @Test
-    public void testSetInstalledAndEnabledServices_clientChanged() {
+    public void testSetInstalledAndEnabledServices_updateInfos_notifiesSystemOfProxyChange() {
         final List<AccessibilityServiceInfo> infos = new ArrayList<>();
         final AccessibilityServiceInfo info1 = new AccessibilityServiceInfo();
         infos.add(info1);
@@ -106,6 +114,17 @@
     }
 
     @Test
+    public void testSetFocusAppearance_updateAppearance_notifiesSystemOfProxyChange() {
+        final int updatedWidth = mFocusStrokeWidthDefaultValue + 10;
+        final int updatedColor = mFocusColorDefaultValue
+                == Color.BLUE ? Color.RED : Color.BLUE;
+
+        mProxyConnection.setFocusAppearance(updatedWidth, updatedColor);
+
+        verify(mMockSystemSupport).onProxyChanged(DEVICE_ID);
+    }
+
+    @Test
     public void testSetInstalledAndEnabledServices_returnList() {
         final List<AccessibilityServiceInfo> infos = new ArrayList<>();
         final AccessibilityServiceInfo info1 = new AccessibilityServiceInfo();
@@ -196,7 +215,7 @@
     }
 
     @Test
-    public void testSetServiceInfo_setIllegalOperationExceptionThrown_() {
+    public void testSetServiceInfo_setIllegalOperationExceptionThrown() {
         UnsupportedOperationException thrown =
                 assertThrows(
                         UnsupportedOperationException.class,
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/ProxyManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/ProxyManagerTest.java
new file mode 100644
index 0000000..6c7b995
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/ProxyManagerTest.java
@@ -0,0 +1,527 @@
+/*
+ * 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.accessibility;
+
+import static com.android.server.accessibility.ProxyAccessibilityServiceConnectionTest.INTERACTIVE_UI_TIMEOUT_100MS;
+import static com.android.server.accessibility.ProxyAccessibilityServiceConnectionTest.INTERACTIVE_UI_TIMEOUT_200MS;
+import static com.android.server.accessibility.ProxyAccessibilityServiceConnectionTest.NON_INTERACTIVE_UI_TIMEOUT_100MS;
+import static com.android.server.accessibility.ProxyAccessibilityServiceConnectionTest.NON_INTERACTIVE_UI_TIMEOUT_200MS;
+import static com.android.server.accessibility.ProxyManager.PROXY_COMPONENT_CLASS_NAME;
+import static com.android.server.accessibility.ProxyManager.PROXY_COMPONENT_PACKAGE_NAME;
+
+import static org.junit.Assert.fail;
+
+import android.accessibilityservice.AccessibilityGestureEvent;
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.accessibilityservice.AccessibilityTrace;
+import android.accessibilityservice.IAccessibilityServiceClient;
+import android.accessibilityservice.IAccessibilityServiceConnection;
+import android.accessibilityservice.MagnificationConfig;
+import android.companion.virtual.IVirtualDeviceManager;
+import android.companion.virtual.VirtualDeviceManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Region;
+import android.os.IBinder;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.util.ArraySet;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.IAccessibilityManagerClient;
+import android.view.inputmethod.EditorInfo;
+
+import com.android.internal.R;
+import com.android.internal.inputmethod.IAccessibilityInputMethodSession;
+import com.android.internal.inputmethod.IAccessibilityInputMethodSessionCallback;
+import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection;
+import com.android.internal.util.IntPair;
+import com.android.server.LocalServices;
+import com.android.server.accessibility.test.MessageCapturingHandler;
+import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
+import com.android.server.wm.WindowManagerInternal;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.InstrumentationRegistry;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Tests for ProxyManager.
+ */
+public class ProxyManagerTest {
+    private static final int DISPLAY_ID = 1000;
+    private static final int DISPLAY_2_ID = 1001;
+    private static final int DEVICE_ID = 10;
+    private static final int STREAMED_CALLING_UID = 9876;
+
+    @Mock private Context mMockContext;
+    @Mock private AccessibilitySecurityPolicy mMockSecurityPolicy;
+    @Mock private AccessibilityWindowManager mMockA11yWindowManager;
+    @Mock private ProxyManager.SystemSupport mMockProxySystemSupport;
+    @Mock private AbstractAccessibilityServiceConnection.SystemSupport mMockConnectionSystemSupport;
+    @Mock private AccessibilityTrace mMockA11yTrace;
+    @Mock private WindowManagerInternal mMockWindowManagerInternal;
+    @Mock private IAccessibilityServiceClient mMockAccessibilityServiceClient;
+    @Mock private IBinder mMockServiceAsBinder;
+    @Mock private VirtualDeviceManagerInternal mMockVirtualDeviceManagerInternal;
+    @Mock private IVirtualDeviceManager mMockIVirtualDeviceManager;
+
+    private int mFocusStrokeWidthDefaultValue;
+    private int mFocusColorDefaultValue;
+
+    private MessageCapturingHandler mMessageCapturingHandler  = new MessageCapturingHandler(null);
+    private ProxyManager mProxyManager;
+
+    @Before
+    public void setup() throws RemoteException {
+        MockitoAnnotations.initMocks(this);
+        final Resources resources = InstrumentationRegistry.getContext().getResources();
+
+        mFocusStrokeWidthDefaultValue =
+                resources.getDimensionPixelSize(R.dimen.accessibility_focus_highlight_stroke_width);
+        mFocusColorDefaultValue = resources.getColor(R.color.accessibility_focus_highlight_color);
+        when(mMockContext.getResources()).thenReturn(resources);
+
+        when(mMockVirtualDeviceManagerInternal.getDeviceIdsForUid(anyInt())).thenReturn(
+                new ArraySet(Set.of(DEVICE_ID)));
+        LocalServices.removeServiceForTest(VirtualDeviceManagerInternal.class);
+        LocalServices.addService(VirtualDeviceManagerInternal.class,
+                mMockVirtualDeviceManagerInternal);
+
+        when(mMockIVirtualDeviceManager.getDeviceIdForDisplayId(anyInt())).thenReturn(DEVICE_ID);
+        final VirtualDeviceManager virtualDeviceManager =
+                new VirtualDeviceManager(mMockIVirtualDeviceManager, mMockContext);
+        when(mMockContext.getSystemServiceName(VirtualDeviceManager.class)).thenReturn(
+                Context.VIRTUAL_DEVICE_SERVICE);
+        when(mMockContext.getSystemService(VirtualDeviceManager.class))
+                .thenReturn(virtualDeviceManager);
+
+        when(mMockA11yTrace.isA11yTracingEnabled()).thenReturn(false);
+
+        final RemoteCallbackList<IAccessibilityManagerClient> userClients =
+                new RemoteCallbackList<>();
+        final RemoteCallbackList<IAccessibilityManagerClient> globalClients =
+                new RemoteCallbackList<>();
+        when(mMockProxySystemSupport.getCurrentUserClientsLocked()).thenReturn(userClients);
+        when(mMockProxySystemSupport.getGlobalClientsLocked()).thenReturn(globalClients);
+
+        when(mMockAccessibilityServiceClient.asBinder()).thenReturn(mMockServiceAsBinder);
+
+        mProxyManager = new ProxyManager(new Object(), mMockA11yWindowManager, mMockContext,
+                mMessageCapturingHandler, new UiAutomationManager(new Object()),
+                mMockProxySystemSupport);
+    }
+
+    @After
+    public void tearDown() {
+        mMessageCapturingHandler.removeAllMessages();
+    }
+
+    /**
+     * Tests that the proxy’s backing AccessibilityServiceClient is initialized when registering a
+     * proxy.
+     */
+    @Test
+    public void registerProxy_always_connectsServiceClient() throws RemoteException {
+        registerProxy(DISPLAY_ID);
+        verify(mMockAccessibilityServiceClient).init(any(), anyInt(), any());
+    }
+
+    /** Tests that unregistering a proxy removes its display from tracking. */
+    @Test
+    public void unregisterProxy_always_stopsTrackingDisplay() {
+        registerProxy(DISPLAY_ID);
+
+        mProxyManager.unregisterProxy(DISPLAY_ID);
+
+        verify(mMockA11yWindowManager).stopTrackingDisplayProxy(DISPLAY_ID);
+        assertThat(mProxyManager.isProxyedDisplay(DISPLAY_ID)).isFalse();
+    }
+    /**
+     * Tests that unregistering a proxied display of a virtual device, where that virtual device
+     * owned only that one proxied display, removes the device from tracking.
+     */
+    @Test
+    public void unregisterProxy_deviceAssociatedWithSingleDisplay_stopsTrackingDevice() {
+        registerProxy(DISPLAY_ID);
+
+        mProxyManager.unregisterProxy(DISPLAY_ID);
+
+        assertThat(mProxyManager.isProxyedDeviceId(DEVICE_ID)).isFalse();
+        verify(mMockProxySystemSupport).removeDeviceIdLocked(DEVICE_ID);
+    }
+
+    /**
+     * Tests that unregistering a proxied display of a virtual device, where that virtual device
+     * owns more than one proxied display, does not remove the device from tracking.
+     */
+    @Test
+    public void unregisterProxy_deviceAssociatedWithMultipleDisplays_tracksRemainingProxy() {
+        registerProxy(DISPLAY_ID);
+        registerProxy(DISPLAY_2_ID);
+
+        mProxyManager.unregisterProxy(DISPLAY_ID);
+
+        assertThat(mProxyManager.isProxyedDeviceId(DEVICE_ID)).isTrue();
+        verify(mMockProxySystemSupport, never()).removeDeviceIdLocked(DEVICE_ID);
+    }
+
+    /**
+     * Tests that changing a proxy, e.g. registering/unregistering a proxy or updating its service
+     * info, notifies the apps being streamed and AccessibilityManagerService.
+     */
+    @Test
+    public void testOnProxyChanged_always_propagatesChange() {
+        registerProxy(DISPLAY_ID);
+        mMessageCapturingHandler.sendAllMessages();
+
+        mProxyManager.onProxyChanged(DEVICE_ID);
+
+        // Messages to notify IAccessibilityManagerClients should be posted.
+        assertThat(mMessageCapturingHandler.hasMessages()).isTrue();
+
+        verify(mMockProxySystemSupport).updateWindowsForAccessibilityCallbackLocked();
+        verify(mMockProxySystemSupport).notifyClearAccessibilityCacheLocked();
+    }
+
+    /**
+     * Tests that getting the first device id for an app uid, such as when an app queries for
+     * device-specific state, returns the right device id.
+     */
+    @Test
+    public void testGetFirstDeviceForUid_streamedAppQueriesState_getsHostDeviceId() {
+        registerProxy(DISPLAY_ID);
+        assertThat(mProxyManager.getFirstDeviceIdForUidLocked(STREAMED_CALLING_UID))
+                .isEqualTo(DEVICE_ID);
+    }
+
+    /**
+     * Tests that the app client state retrieved for a device reflects that touch exploration is
+     * enabled since a proxy info has requested touch exploration.
+     */
+    @Test
+    public void testGetClientState_proxyWantsTouchExploration_returnsTouchExplorationEnabled() {
+        registerProxy(DISPLAY_ID);
+
+        final AccessibilityServiceInfo secondDisplayInfo = new AccessibilityServiceInfo();
+        secondDisplayInfo.flags |= AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE;
+        AccessibilityServiceClientImpl client = new AccessibilityServiceClientImpl(
+                secondDisplayInfo);
+        registerProxy(DISPLAY_2_ID, client);
+
+        final int deviceClientState = mProxyManager.getStateLocked(DEVICE_ID);
+        assertThat((deviceClientState
+                & AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED) != 0).isTrue();
+    }
+
+    /**
+     * Tests that the highest interactive and non-interactive timeout is returned if there are
+     * multiple proxied displays belonging to a device.
+     */
+    @Test
+    public void testGetRecommendedTimeout_multipleProxies_returnsHighestTimeout() {
+        final AccessibilityServiceInfo firstDisplayInfo = new AccessibilityServiceInfo();
+        firstDisplayInfo.setInteractiveUiTimeoutMillis(INTERACTIVE_UI_TIMEOUT_100MS);
+        firstDisplayInfo.setNonInteractiveUiTimeoutMillis(NON_INTERACTIVE_UI_TIMEOUT_200MS);
+
+        final AccessibilityServiceInfo secondDisplayInfo = new AccessibilityServiceInfo();
+        secondDisplayInfo.setInteractiveUiTimeoutMillis(INTERACTIVE_UI_TIMEOUT_200MS);
+        secondDisplayInfo.setNonInteractiveUiTimeoutMillis(NON_INTERACTIVE_UI_TIMEOUT_100MS);
+
+        registerProxy(DISPLAY_ID, new AccessibilityServiceClientImpl(firstDisplayInfo));
+        registerProxy(DISPLAY_2_ID, new AccessibilityServiceClientImpl(secondDisplayInfo));
+
+        final long timeout = mProxyManager.getRecommendedTimeoutMillisLocked(DEVICE_ID);
+        final int interactiveTimeout = IntPair.first(timeout);
+        final int nonInteractiveTimeout = IntPair.second(timeout);
+
+        assertThat(interactiveTimeout).isEqualTo(INTERACTIVE_UI_TIMEOUT_200MS);
+        assertThat(nonInteractiveTimeout).isEqualTo(NON_INTERACTIVE_UI_TIMEOUT_200MS);
+    }
+    /**
+     * Tests that getting the installed and enabled services returns the info of the registered
+     * proxy. (The component name reflects the display id.)
+     */
+    @Test
+    public void testGetInstalledAndEnabledServices_defaultInfo_returnsInfoForDisplayId() {
+        final AccessibilityServiceInfo info = new AccessibilityServiceInfo();
+        registerProxy(DISPLAY_ID, new AccessibilityServiceClientImpl(info));
+        final List<AccessibilityServiceInfo> installedAndEnabledServices =
+                mProxyManager.getInstalledAndEnabledServiceInfosLocked(
+                        AccessibilityServiceInfo.FEEDBACK_ALL_MASK, DEVICE_ID);
+        assertThat(installedAndEnabledServices.size()).isEqualTo(1);
+        AccessibilityServiceInfo proxyInfo = installedAndEnabledServices.get(0);
+
+        assertThat(proxyInfo.getComponentName()).isEqualTo(new ComponentName(
+                PROXY_COMPONENT_PACKAGE_NAME, PROXY_COMPONENT_CLASS_NAME + DISPLAY_ID));
+    }
+
+    /**
+     * Tests that the app client state retrieved for a device reflects that accessibility is
+     * enabled.
+     */
+    @Test
+    public void testGetClientState_always_returnsAccessibilityEnabled() {
+        registerProxy(DISPLAY_ID);
+
+        final int deviceClientState = mProxyManager.getStateLocked(DEVICE_ID);
+        assertThat((deviceClientState
+                & AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED) != 0).isTrue();
+    }
+
+    /**
+     * Tests that the manager can retrieve interactive windows if a proxy sets
+     * AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS.
+     */
+    @Test
+    public void testCanRetrieveInteractiveWindows_atLeastOneProxyWantsWindows_returnsTrue() {
+        registerProxy(DISPLAY_ID);
+
+        final AccessibilityServiceInfo secondDisplayInfo = new AccessibilityServiceInfo();
+        secondDisplayInfo.flags |= AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS;
+        registerProxy(DISPLAY_2_ID, new AccessibilityServiceClientImpl(secondDisplayInfo));
+
+        assertThat(mProxyManager.canRetrieveInteractiveWindowsLocked()).isTrue();
+    }
+
+    /**
+     * Tests that getting service interfaces to interrupt when AccessibilityManager#interrupt
+     * returns the registered proxy interface.
+     */
+    @Test
+    public void testGetServiceInterfacesForInterrupt_defaultProxy_returnsProxyInterface() {
+        registerProxy(DISPLAY_ID);
+        final List<IAccessibilityServiceClient> interfacesToInterrupt = new ArrayList<>();
+        mProxyManager.addServiceInterfacesLocked(interfacesToInterrupt, DEVICE_ID);
+
+        assertThat(interfacesToInterrupt.size()).isEqualTo(1);
+        assertThat(interfacesToInterrupt.get(0).asBinder()).isEqualTo(mMockServiceAsBinder);
+    }
+
+    /** Tests that the default timeout (0) is returned when the proxy is registered. */
+    @Test
+    public void getRecommendedTimeout_defaultProxyInfo_getsDefaultTimeout() {
+        registerProxy(DISPLAY_ID);
+        final long timeout = mProxyManager.getRecommendedTimeoutMillisLocked(DEVICE_ID);
+        final int interactiveTimeout = IntPair.first(timeout);
+        final int nonInteractiveTimeout = IntPair.second(timeout);
+
+        assertThat(interactiveTimeout).isEqualTo(0);
+        assertThat(nonInteractiveTimeout).isEqualTo(0);
+    }
+
+    /** Tests that the manager returns the updated timeout when the proxy’s timeout is updated. */
+    @Test
+    public void getRecommendedTimeout_updateTimeout_getsUpdatedTimeout() {
+        registerProxy(DISPLAY_ID);
+
+        mProxyManager.updateTimeoutsIfNeeded(NON_INTERACTIVE_UI_TIMEOUT_100MS,
+                INTERACTIVE_UI_TIMEOUT_200MS);
+
+        final long updatedTimeout = mProxyManager.getRecommendedTimeoutMillisLocked(DEVICE_ID);
+        final int updatedInteractiveTimeout = IntPair.first(updatedTimeout);
+        final int updatedNonInteractiveTimeout = IntPair.second(updatedTimeout);
+
+        assertThat(updatedInteractiveTimeout).isEqualTo(INTERACTIVE_UI_TIMEOUT_200MS);
+        assertThat(updatedNonInteractiveTimeout).isEqualTo(NON_INTERACTIVE_UI_TIMEOUT_100MS);
+    }
+
+    /** Tests that the system’s default focus color is returned. */
+    @Test
+    public void testGetFocusColor_defaultProxy_getsDefaultSystemColor() {
+        registerProxy(DISPLAY_ID);
+        final int focusColor = mProxyManager.getFocusColorLocked(DEVICE_ID);
+        assertThat(focusColor).isEqualTo(mFocusColorDefaultValue);
+    }
+
+    /** Tests that the system’s default focus stroke width is returned. */
+    @Test
+    public void testGetFocusStrokeWidth_defaultProxy_getsDefaultSystemWidth() {
+        registerProxy(DISPLAY_ID);
+        final int focusStrokeWidth = mProxyManager.getFocusStrokeWidthLocked(DEVICE_ID);
+        assertThat(focusStrokeWidth).isEqualTo(mFocusStrokeWidthDefaultValue);
+    }
+
+    private void registerProxy(int displayId) {
+        try {
+            mProxyManager.registerProxy(mMockAccessibilityServiceClient, displayId, anyInt(),
+                    mMockSecurityPolicy, mMockConnectionSystemSupport,
+                    mMockA11yTrace, mMockWindowManagerInternal);
+        } catch (RemoteException e) {
+            fail("Failed to register proxy " + e);
+        }
+    }
+
+    private void registerProxy(int displayId, AccessibilityServiceClientImpl serviceClient) {
+        try {
+            mProxyManager.registerProxy(serviceClient, displayId, anyInt(),
+                    mMockSecurityPolicy, mMockConnectionSystemSupport,
+                    mMockA11yTrace, mMockWindowManagerInternal);
+        } catch (RemoteException e) {
+            fail("Failed to register proxy " + e);
+        }
+    }
+
+    /**
+     * IAccessibilityServiceClient implementation.
+     * A proxy connection does not populate non-default AccessibilityServiceInfo values until the
+     * proxy is connected in A11yDisplayProxy#onServiceConnected. For tests that check for
+     * non-default values, populate immediately in this testing class, since a real Service is not
+     * being used and connected.
+     */
+    static class AccessibilityServiceClientImpl extends IAccessibilityServiceClient.Stub {
+        List<AccessibilityServiceInfo> mInstalledAndEnabledServices;
+
+        AccessibilityServiceClientImpl(AccessibilityServiceInfo
+                installedAndEnabledService) {
+            mInstalledAndEnabledServices = List.of(installedAndEnabledService);
+        }
+
+        @Override
+        public void init(IAccessibilityServiceConnection connection, int connectionId,
+                IBinder windowToken) throws RemoteException {
+            connection.setInstalledAndEnabledServices(mInstalledAndEnabledServices);
+        }
+
+        @Override
+        public void onAccessibilityEvent(AccessibilityEvent event, boolean serviceWantsEvent)
+                throws RemoteException {
+
+        }
+
+        @Override
+        public void onInterrupt() throws RemoteException {
+
+        }
+
+        @Override
+        public void onGesture(AccessibilityGestureEvent gestureEvent) throws RemoteException {
+
+        }
+
+        @Override
+        public void clearAccessibilityCache() throws RemoteException {
+
+        }
+
+        @Override
+        public void onKeyEvent(KeyEvent event, int sequence) throws RemoteException {
+
+        }
+
+        @Override
+        public void onMagnificationChanged(int displayId, Region region, MagnificationConfig config)
+                throws RemoteException {
+
+        }
+
+        @Override
+        public void onMotionEvent(MotionEvent event) throws RemoteException {
+
+        }
+
+        @Override
+        public void onTouchStateChanged(int displayId, int state) throws RemoteException {
+
+        }
+
+        @Override
+        public void onSoftKeyboardShowModeChanged(int showMode) throws RemoteException {
+
+        }
+
+        @Override
+        public void onPerformGestureResult(int sequence, boolean completedSuccessfully)
+                throws RemoteException {
+
+        }
+
+        @Override
+        public void onFingerprintCapturingGesturesChanged(boolean capturing)
+                throws RemoteException {
+
+        }
+
+        @Override
+        public void onFingerprintGesture(int gesture) throws RemoteException {
+
+        }
+
+        @Override
+        public void onAccessibilityButtonClicked(int displayId) throws RemoteException {
+
+        }
+
+        @Override
+        public void onAccessibilityButtonAvailabilityChanged(boolean available)
+                throws RemoteException {
+
+        }
+
+        @Override
+        public void onSystemActionsChanged() throws RemoteException {
+
+        }
+
+        @Override
+        public void createImeSession(IAccessibilityInputMethodSessionCallback callback)
+                throws RemoteException {
+
+        }
+
+        @Override
+        public void setImeSessionEnabled(IAccessibilityInputMethodSession session, boolean enabled)
+                throws RemoteException {
+
+        }
+
+        @Override
+        public void bindInput() throws RemoteException {
+
+        }
+
+        @Override
+        public void unbindInput() throws RemoteException {
+
+        }
+
+        @Override
+        public void startInput(IRemoteAccessibilityInputConnection connection,
+                EditorInfo editorInfo, boolean restarting) throws RemoteException {
+
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java b/services/tests/servicestests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java
index d7b12e0..e6d3bbc 100644
--- a/services/tests/servicestests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java
@@ -19,10 +19,13 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
@@ -66,25 +69,27 @@
     @Mock
     private HandlerExecutor mBrightnessChangeExecutor;
 
+    private final DisplayBrightnessController.Injector mInjector = new
+            DisplayBrightnessController.Injector() {
+        @Override
+        DisplayBrightnessStrategySelector getDisplayBrightnessStrategySelector(
+                Context context, int displayId) {
+            return mDisplayBrightnessStrategySelector;
+        }
+    };
+
     private DisplayBrightnessController mDisplayBrightnessController;
 
     @Before
     public void before() {
         MockitoAnnotations.initMocks(this);
         when(mContext.getResources()).thenReturn(mResources);
-        DisplayBrightnessController.Injector injector = new DisplayBrightnessController.Injector() {
-            @Override
-            DisplayBrightnessStrategySelector getDisplayBrightnessStrategySelector(
-                    Context context, int displayId) {
-                return mDisplayBrightnessStrategySelector;
-            }
-        };
         when(mBrightnessSetting.getBrightness()).thenReturn(Float.NaN);
         when(mBrightnessSetting.getBrightnessNitsForDefaultDisplay()).thenReturn(-1f);
         when(mResources.getBoolean(
                 com.android.internal.R.bool.config_persistBrightnessNitsForDefaultDisplay))
                 .thenReturn(true);
-        mDisplayBrightnessController = new DisplayBrightnessController(mContext, injector,
+        mDisplayBrightnessController = new DisplayBrightnessController(mContext, mInjector,
                 DISPLAY_ID, DEFAULT_BRIGHTNESS, mBrightnessSetting, mOnBrightnessChangeRunnable,
                 mBrightnessChangeExecutor);
     }
@@ -257,27 +262,6 @@
     }
 
     @Test
-    public void testBrightnessNitsForDefaultDisplay() {
-        float brightness = 0.3f;
-        float nits = 500;
-        AutomaticBrightnessController automaticBrightnessController =
-                mock(AutomaticBrightnessController.class);
-        when(automaticBrightnessController.convertToFloatScale(nits)).thenReturn(brightness);
-        when(mBrightnessSetting.getBrightnessNitsForDefaultDisplay()).thenReturn(nits);
-
-        mDisplayBrightnessController.setAutomaticBrightnessController(
-                automaticBrightnessController);
-        assertEquals(brightness, mDisplayBrightnessController.getCurrentBrightness(),
-                /* delta= */ 0);
-
-        float newBrightness = 0.5f;
-        float newNits = 700;
-        when(automaticBrightnessController.convertToNits(newBrightness)).thenReturn(newNits);
-        mDisplayBrightnessController.setBrightness(newBrightness);
-        verify(mBrightnessSetting).setBrightnessNitsForDefaultDisplay(newNits);
-    }
-
-    @Test
     public void testConvertToNits() {
         final float brightness = 0.5f;
         final float nits = 300;
@@ -330,4 +314,48 @@
         mDisplayBrightnessController.stop();
         verify(mBrightnessSetting).unregisterListener(brightnessSettingListener);
     }
+
+    @Test
+    public void testLoadNitBasedBrightnessSetting() {
+        // When the nits value is valid, the brightness is set from the old default display nits
+        // value
+        float nits = 200f;
+        float brightness = 0.3f;
+        AutomaticBrightnessController automaticBrightnessController =
+                mock(AutomaticBrightnessController.class);
+        when(automaticBrightnessController.convertToFloatScale(nits)).thenReturn(brightness);
+        when(mBrightnessSetting.getBrightnessNitsForDefaultDisplay()).thenReturn(nits);
+        mDisplayBrightnessController.setAutomaticBrightnessController(
+                automaticBrightnessController);
+        verify(mBrightnessSetting).setBrightness(brightness);
+        assertEquals(brightness, mDisplayBrightnessController.getCurrentBrightness(), 0.01f);
+        clearInvocations(automaticBrightnessController, mBrightnessSetting);
+
+        // When the nits value is invalid, the brightness is resumed from where it was last set
+        nits = -1;
+        brightness = 0.4f;
+        when(automaticBrightnessController.convertToFloatScale(nits)).thenReturn(brightness);
+        when(mBrightnessSetting.getBrightnessNitsForDefaultDisplay()).thenReturn(nits);
+        when(mBrightnessSetting.getBrightness()).thenReturn(brightness);
+        mDisplayBrightnessController.setAutomaticBrightnessController(
+                automaticBrightnessController);
+        verify(mBrightnessSetting, never()).setBrightness(brightness);
+        assertEquals(brightness, mDisplayBrightnessController.getCurrentBrightness(), 0.01f);
+        clearInvocations(automaticBrightnessController, mBrightnessSetting);
+
+        // When the display is a non-default display, the brightness is resumed from where it was
+        // last set
+        int nonDefaultDisplayId = 1;
+        mDisplayBrightnessController = new DisplayBrightnessController(mContext, mInjector,
+                nonDefaultDisplayId, DEFAULT_BRIGHTNESS, mBrightnessSetting,
+                mOnBrightnessChangeRunnable, mBrightnessChangeExecutor);
+        brightness = 0.5f;
+        when(mBrightnessSetting.getBrightness()).thenReturn(brightness);
+        mDisplayBrightnessController.setAutomaticBrightnessController(
+                automaticBrightnessController);
+        assertEquals(brightness, mDisplayBrightnessController.getCurrentBrightness(), 0.01f);
+        verifyZeroInteractions(automaticBrightnessController);
+        verify(mBrightnessSetting, never()).getBrightnessNitsForDefaultDisplay();
+        verify(mBrightnessSetting, never()).setBrightness(brightness);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
index 5751db0..275533f 100644
--- a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
@@ -446,6 +446,25 @@
     }
 
     @Test
+    public void testSetUserReviewGrantedConsentResult_projectionNull_consentNotGranted()
+            throws Exception {
+        MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
+        projection.start(mIMediaProjectionCallback);
+        assertThat(mService.isCurrentProjection(projection)).isTrue();
+        doReturn(true).when(mWindowManagerInternal).setContentRecordingSession(
+                any(ContentRecordingSession.class));
+        // Some other token.
+        final IMediaProjection otherProjection = null;
+        // Waiting for user to review consent.
+        mService.setContentRecordingSession(mWaitingDisplaySession);
+        mService.setUserReviewGrantedConsentResult(RECORD_CANCEL, otherProjection);
+
+        // Display result is ignored; only the first session is set.
+        verify(mWindowManagerInternal, times(1)).setContentRecordingSession(
+                eq(mWaitingDisplaySession));
+    }
+
+    @Test
     public void testSetUserReviewGrantedConsentResult_noVirtualDisplay() throws Exception {
         MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
         projection.start(mIMediaProjectionCallback);
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 0033e3e..cb984f8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -851,7 +851,7 @@
                     }
 
                     @Override
-                    public void onAnimationCancelled(boolean isKeyguardOccluded) {
+                    public void onAnimationCancelled() {
                     }
                 }, 0, 0));
         activity.updateOptionsLocked(opts);
@@ -3124,7 +3124,7 @@
                 .setSystemDecorations(true).build();
         // Add a decor insets provider window.
         final WindowState navbar = createNavBarWithProvidedInsets(squareDisplay);
-        assertTrue(navbar.providesNonDecorInsets()
+        assertTrue(navbar.providesDisplayDecorInsets()
                 && squareDisplay.getDisplayPolicy().updateDecorInsetsInfo());
         squareDisplay.sendNewConfiguration();
         final Task task = new TaskBuilder(mSupervisor).setDisplay(squareDisplay).build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
index 6d13124..169968c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
@@ -87,7 +87,7 @@
         }
 
         @Override
-        public void onAnimationCancelled(boolean isKeyguardOccluded) {
+        public void onAnimationCancelled() {
         }
 
         @Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index 0ae579b..a11079b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -735,7 +735,7 @@
         }
 
         @Override
-        public void onAnimationCancelled(boolean isKeyguardOccluded) throws RemoteException {
+        public void onAnimationCancelled() throws RemoteException {
             mFinishedCallback = null;
         }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index 59cc4f5..ba8c94d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -549,7 +549,7 @@
         }
 
         @Override
-        public void onAnimationCancelled(boolean isKeyguardOccluded) {
+        public void onAnimationCancelled() {
             mCancelled = true;
         }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java
index 06b4ad9..7b4392b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java
@@ -50,7 +50,6 @@
 import android.util.Log;
 import android.view.IWindowManager;
 
-import androidx.test.filters.FlakyTest;
 import androidx.test.filters.MediumTest;
 
 import com.android.server.am.AssistDataRequester;
@@ -155,7 +154,6 @@
     }
 
     @Test
-    @FlakyTest(bugId = 130388718)
     public void testRequestData() throws Exception {
         setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
                 CALLER_ASSIST_SCREENSHOT_ALLOWED);
@@ -263,7 +261,6 @@
     }
 
     @Test
-    @FlakyTest(bugId = 130388718)
     public void testNoFetchScreenshots_expectNoScreenshotCallbacks() throws Exception {
         setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
                 CALLER_ASSIST_SCREENSHOT_ALLOWED);
@@ -275,7 +272,6 @@
     }
 
     @Test
-    @FlakyTest(bugId = 130388718)
     public void testDisallowAssistScreenshot_expectNullScreenshotCallback() throws Exception {
         setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
                 !CALLER_ASSIST_SCREENSHOT_ALLOWED);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index c8fdee0..353a8ec 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -45,6 +45,8 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
@@ -298,20 +300,27 @@
 
     @Test
     public void testUpdateDisplayConfigurationByDecor() {
+        doReturn(NO_CUTOUT).when(mDisplayContent).calculateDisplayCutoutForRotation(anyInt());
         final WindowState navbar = createNavBarWithProvidedInsets(mDisplayContent);
         final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy();
         final DisplayInfo di = mDisplayContent.getDisplayInfo();
         final int prevScreenHeightDp = mDisplayContent.getConfiguration().screenHeightDp;
-        assertTrue(navbar.providesNonDecorInsets() && displayPolicy.updateDecorInsetsInfo());
+        assertTrue(navbar.providesDisplayDecorInsets() && displayPolicy.updateDecorInsetsInfo());
         assertEquals(NAV_BAR_HEIGHT, displayPolicy.getDecorInsetsInfo(di.rotation,
                 di.logicalWidth, di.logicalHeight).mConfigInsets.bottom);
         mDisplayContent.sendNewConfiguration();
         assertNotEquals(prevScreenHeightDp, mDisplayContent.getConfiguration().screenHeightDp);
-        assertFalse(navbar.providesNonDecorInsets() && displayPolicy.updateDecorInsetsInfo());
+        assertFalse(navbar.providesDisplayDecorInsets() && displayPolicy.updateDecorInsetsInfo());
 
         navbar.removeIfPossible();
         assertEquals(0, displayPolicy.getDecorInsetsInfo(di.rotation, di.logicalWidth,
                 di.logicalHeight).mNonDecorInsets.bottom);
+
+        final WindowState statusBar = createStatusBarWithProvidedInsets(mDisplayContent);
+        assertTrue(statusBar.providesDisplayDecorInsets()
+                && displayPolicy.updateDecorInsetsInfo());
+        assertEquals(STATUS_BAR_HEIGHT, displayPolicy.getDecorInsetsInfo(di.rotation,
+                di.logicalWidth, di.logicalHeight).mConfigInsets.top);
     }
 
     @SetupWindows(addWindows = { W_NAVIGATION_BAR, W_INPUT_METHOD })
diff --git a/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java b/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java
index 027f903..8cf2776 100644
--- a/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java
@@ -27,7 +27,6 @@
 import android.os.SystemClock;
 import android.platform.test.annotations.Presubmit;
 
-import androidx.test.filters.FlakyTest;
 import androidx.test.filters.MediumTest;
 
 import org.junit.After;
@@ -110,7 +109,6 @@
     }
 
     @Test
-    @FlakyTest(bugId = 131005232)
     public void testProcessOneItem_Flush() throws Exception {
         mFactory.setExpectedProcessedItemNumber(1);
         mListener.setExpectedOnPreProcessItemCallbackTimes(1);
@@ -162,7 +160,6 @@
     }
 
     @Test
-    @FlakyTest(bugId = 128526085)
     public void testProcessTwoItems_OneAfterAnother() throws Exception {
         // First item
         mFactory.setExpectedProcessedItemNumber(1);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
index 0db983c..c4d03be 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
@@ -37,7 +37,6 @@
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
 
-import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
 
 import com.android.server.wm.RefreshRatePolicy.FrameRateVote;
@@ -53,7 +52,6 @@
 @SmallTest
 @Presubmit
 @RunWith(WindowTestRunner.class)
-@FlakyTest
 public class RefreshRatePolicyTest extends WindowTestsBase {
     private static final int HI_MODE_ID = 1;
     private static final float HI_REFRESH_RATE = 90;
diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index eb26415..11d9629 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -211,7 +211,7 @@
         mController.goodToGo(TRANSIT_OLD_ACTIVITY_OPEN);
 
         adapter.onAnimationCancelled(mMockLeash);
-        verify(mMockRunner).onAnimationCancelled(anyBoolean());
+        verify(mMockRunner).onAnimationCancelled();
     }
 
     @Test
@@ -227,7 +227,7 @@
         mClock.fastForward(10500);
         mHandler.timeAdvance();
 
-        verify(mMockRunner).onAnimationCancelled(anyBoolean());
+        verify(mMockRunner).onAnimationCancelled();
         verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_APP_TRANSITION),
                 eq(adapter));
     }
@@ -248,12 +248,12 @@
             mClock.fastForward(10500);
             mHandler.timeAdvance();
 
-            verify(mMockRunner, never()).onAnimationCancelled(anyBoolean());
+            verify(mMockRunner, never()).onAnimationCancelled();
 
             mClock.fastForward(52500);
             mHandler.timeAdvance();
 
-            verify(mMockRunner).onAnimationCancelled(anyBoolean());
+            verify(mMockRunner).onAnimationCancelled();
             verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_APP_TRANSITION),
                     eq(adapter));
         } finally {
@@ -265,7 +265,7 @@
     public void testZeroAnimations() throws Exception {
         mController.goodToGo(TRANSIT_OLD_NONE);
         verify(mMockRunner, never()).onAnimationStart(anyInt(), any(), any(), any(), any());
-        verify(mMockRunner).onAnimationCancelled(anyBoolean());
+        verify(mMockRunner).onAnimationCancelled();
     }
 
     @Test
@@ -275,7 +275,7 @@
                 new Point(50, 100), null, new Rect(50, 100, 150, 150), null, false);
         mController.goodToGo(TRANSIT_OLD_ACTIVITY_OPEN);
         verify(mMockRunner, never()).onAnimationStart(anyInt(), any(), any(), any(), any());
-        verify(mMockRunner).onAnimationCancelled(anyBoolean());
+        verify(mMockRunner).onAnimationCancelled();
     }
 
     @Test
@@ -317,7 +317,7 @@
         win.mActivityRecord.removeImmediately();
         mController.goodToGo(TRANSIT_OLD_ACTIVITY_OPEN);
         verify(mMockRunner, never()).onAnimationStart(anyInt(), any(), any(), any(), any());
-        verify(mMockRunner).onAnimationCancelled(anyBoolean());
+        verify(mMockRunner).onAnimationCancelled();
         verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_APP_TRANSITION),
                 eq(adapter));
     }
@@ -575,7 +575,7 @@
 
             // Cancel the wallpaper window animator and ensure the runner is not canceled
             wallpaperWindowToken.cancelAnimation();
-            verify(mMockRunner, never()).onAnimationCancelled(anyBoolean());
+            verify(mMockRunner, never()).onAnimationCancelled();
         } finally {
             mDisplayContent.mOpeningApps.clear();
         }
diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
index ff753f2..339162a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
@@ -98,7 +98,6 @@
         mFinishCallbackLatch.countDown();
     }
 
-    @FlakyTest(bugId = 144611135)
     @Test
     public void testAnimation() throws Exception {
         mSurfaceAnimationRunner
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
index 790b154..453e468 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
@@ -52,7 +52,6 @@
 import android.view.ViewGroup;
 import android.widget.LinearLayout;
 
-import androidx.test.filters.FlakyTest;
 import androidx.test.filters.MediumTest;
 
 import org.junit.After;
@@ -319,7 +318,6 @@
     };
 
     @Presubmit
-    @FlakyTest(bugId = 150409355)
     @Test
     public void testNotifyTaskRequestedOrientationChanged() throws Exception {
         final ArrayBlockingQueue<int[]> taskIdAndOrientationQueue = new ArrayBlockingQueue<>(10);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index a1ddd57..ad606cb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -1112,7 +1112,7 @@
                     }
 
                     @Override
-                    public void onAnimationCancelled(boolean isKeyguardOccluded) {
+                    public void onAnimationCancelled() {
                     }
                 }, 0, 0, false);
         adapter.setCallingPidUid(123, 456);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerThumbnailTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerThumbnailTest.java
index 0b1b877..2ae1172 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerThumbnailTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerThumbnailTest.java
@@ -26,7 +26,6 @@
 import android.hardware.HardwareBuffer;
 import android.platform.test.annotations.Presubmit;
 
-import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
@@ -55,7 +54,6 @@
     }
 
     @Test
-    @FlakyTest(bugId = 131005232)
     public void testDestroy_nullsSurface() {
         final WindowContainerThumbnail t = buildThumbnail();
         assertNotNull(t.getSurfaceControl());
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 07244a4..a63807d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -471,6 +471,17 @@
         return navbar;
     }
 
+    WindowState createStatusBarWithProvidedInsets(DisplayContent dc) {
+        final WindowState statusBar = createWindow(null, TYPE_STATUS_BAR, dc, "statusBar");
+        final Binder owner = new Binder();
+        statusBar.mAttrs.providedInsets = new InsetsFrameProvider[] {
+                new InsetsFrameProvider(owner, 0, WindowInsets.Type.statusBars())
+                        .setInsetsSize(Insets.of(0, STATUS_BAR_HEIGHT, 0, 0))
+        };
+        dc.getDisplayPolicy().addWindowLw(statusBar, statusBar.mAttrs);
+        return statusBar;
+    }
+
     WindowState createAppWindow(Task task, int type, String name) {
         final ActivityRecord activity = createNonAttachedActivityRecord(task.getDisplayContent());
         task.addChild(activity, 0);
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
index 10b7952..ba17884 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
@@ -584,15 +584,34 @@
     }
 
     /**
+     * Returns true only if there is a terminal whose subtype and terminal type are the same as
+     * the given values.
      * @hide
      */
-    public boolean hasAudioTerminal(int subType) {
+    public boolean hasAudioTerminal(int subType, int terminalType) {
         for (UsbDescriptor descriptor : mDescriptors) {
-            if (descriptor instanceof UsbACInterface) {
-                if (((UsbACInterface) descriptor).getSubclass()
-                        == UsbDescriptor.AUDIO_AUDIOCONTROL
-                        && ((UsbACInterface) descriptor).getSubtype()
-                        == subType) {
+            if (descriptor instanceof UsbACTerminal) {
+                if (((UsbACTerminal) descriptor).getSubclass() == UsbDescriptor.AUDIO_AUDIOCONTROL
+                        && ((UsbACTerminal) descriptor).getSubtype() == subType
+                        && ((UsbACTerminal) descriptor).getTerminalType() == terminalType) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns true only if there is an interface whose subtype is the same as the given one and
+     * terminal type is different from the given one.
+     * @hide
+     */
+    public boolean hasAudioTerminalExcludeType(int subType, int excludedTerminalType) {
+        for (UsbDescriptor descriptor : mDescriptors) {
+            if (descriptor instanceof UsbACTerminal) {
+                if (((UsbACTerminal) descriptor).getSubclass() == UsbDescriptor.AUDIO_AUDIOCONTROL
+                        && ((UsbACTerminal) descriptor).getSubtype() == subType
+                        && ((UsbACTerminal) descriptor).getTerminalType() != excludedTerminalType) {
                     return true;
                 }
             }
@@ -604,14 +623,21 @@
      * @hide
      */
     public boolean hasAudioPlayback() {
-        return hasAudioTerminal(UsbACInterface.ACI_OUTPUT_TERMINAL);
+        return hasAudioTerminalExcludeType(
+                UsbACInterface.ACI_OUTPUT_TERMINAL, UsbTerminalTypes.TERMINAL_USB_STREAMING)
+                && hasAudioTerminal(
+                        UsbACInterface.ACI_INPUT_TERMINAL, UsbTerminalTypes.TERMINAL_USB_STREAMING);
     }
 
     /**
      * @hide
      */
     public boolean hasAudioCapture() {
-        return hasAudioTerminal(UsbACInterface.ACI_INPUT_TERMINAL);
+        return hasAudioTerminalExcludeType(
+                UsbACInterface.ACI_INPUT_TERMINAL, UsbTerminalTypes.TERMINAL_USB_STREAMING)
+                && hasAudioTerminal(
+                        UsbACInterface.ACI_OUTPUT_TERMINAL,
+                        UsbTerminalTypes.TERMINAL_USB_STREAMING);
     }
 
     /**
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 9dd2a61..26590c4 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -744,10 +744,6 @@
      * state of calls in the self-managed {@link ConnectionService}.  An example use-case is
      * exposing these calls to an automotive device via its companion app.
      * <p>
-     * This meta-data can only be set for an {@link InCallService} which also sets
-     * {@link #METADATA_IN_CALL_SERVICE_UI}. Only the default phone/dialer app, or a car-mode
-     * {@link InCallService} can see self-managed calls.
-     * <p>
      * See also {@link Connection#PROPERTY_SELF_MANAGED}.
      */
     public static final String METADATA_INCLUDE_SELF_MANAGED_CALLS =
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 1ce85ba..28ea5a6 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -1186,6 +1186,7 @@
         ApnSetting other = (ApnSetting) o;
 
         return mEntryName.equals(other.mEntryName)
+                && Objects.equals(mId, other.mId)
                 && Objects.equals(mOperatorNumeric, other.mOperatorNumeric)
                 && Objects.equals(mApnName, other.mApnName)
                 && Objects.equals(mProxyAddress, other.mProxyAddress)
@@ -1337,6 +1338,14 @@
     public ContentValues toContentValues() {
         ContentValues apnValue = new ContentValues();
         apnValue.put(Telephony.Carriers.NUMERIC, nullToEmpty(mOperatorNumeric));
+        // If the APN is editable, the user may be able to set an invalid numeric. The numeric must
+        // always be 5 or 6 characters (depending on the length of the MNC), so skip if it is
+        // potentially invalid.
+        if (!TextUtils.isEmpty(mOperatorNumeric)
+                && (mOperatorNumeric.length() == 5 || mOperatorNumeric.length() == 6)) {
+            apnValue.put(Telephony.Carriers.MCC, mOperatorNumeric.substring(0, 3));
+            apnValue.put(Telephony.Carriers.MNC, mOperatorNumeric.substring(3));
+        }
         apnValue.put(Telephony.Carriers.NAME, nullToEmpty(mEntryName));
         apnValue.put(Telephony.Carriers.APN, nullToEmpty(mApnName));
         apnValue.put(Telephony.Carriers.PROXY, nullToEmpty(mProxyAddress));
@@ -1356,6 +1365,7 @@
                 getProtocolStringFromInt(mRoamingProtocol));
         apnValue.put(Telephony.Carriers.CARRIER_ENABLED, mCarrierEnabled);
         apnValue.put(Telephony.Carriers.MVNO_TYPE, getMvnoTypeStringFromInt(mMvnoType));
+        apnValue.put(Telephony.Carriers.MVNO_MATCH_DATA, nullToEmpty(mMvnoMatchData));
         apnValue.put(Telephony.Carriers.NETWORK_TYPE_BITMASK, mNetworkTypeBitmask);
         apnValue.put(Telephony.Carriers.LINGERING_NETWORK_TYPE_BITMASK,
                 mLingeringNetworkTypeBitmask);
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt
index 4e3ae0c..efd9b00 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt
@@ -18,7 +18,7 @@
 
 import android.app.Instrumentation
 import android.platform.test.annotations.Presubmit
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.junit.FlickerBuilderProvider
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
index f389e13..1f120d4 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -19,9 +19,9 @@
 package com.android.server.wm.flicker
 
 import android.tools.common.PlatformConsts
-import android.tools.common.datatypes.component.ComponentNameMatcher
-import android.tools.common.datatypes.component.IComponentNameMatcher
 import android.tools.common.flicker.subject.region.RegionSubject
+import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.common.traces.component.IComponentNameMatcher
 import android.tools.common.traces.wm.WindowManagerTrace
 import android.tools.device.flicker.legacy.FlickerTest
 import android.tools.device.helpers.WindowUtils
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/OpenActivityEmbeddingSecondaryToSplitTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/OpenActivityEmbeddingSecondaryToSplitTest.kt
index c3cbb84..8638288 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/OpenActivityEmbeddingSecondaryToSplitTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/OpenActivityEmbeddingSecondaryToSplitTest.kt
@@ -17,7 +17,7 @@
 package com.android.server.wm.flicker.activityembedding
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
index 5dc2dd7..10b71ff 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
@@ -40,20 +40,27 @@
  *     Launch an app [testApp] and wait animation to complete
  *     Press back button
  * ```
+ *
  * To run only the presubmit assertions add: `--
+ *
  * ```
  *      --module-arg FlickerTests:exclude-annotation:androidx.test.filters.FlakyTest
  *      --module-arg FlickerTests:include-annotation:android.platform.test.annotations.Presubmit`
  * ```
+ *
  * To run only the postsubmit assertions add: `--
+ *
  * ```
  *      --module-arg FlickerTests:exclude-annotation:androidx.test.filters.FlakyTest
  *      --module-arg FlickerTests:include-annotation:android.platform.test.annotations.Postsubmit`
  * ```
+ *
  * To run only the flaky assertions add: `--
+ *
  * ```
  *      --module-arg FlickerTests:include-annotation:androidx.test.filters.FlakyTest`
  * ```
+ *
  * Notes:
  * ```
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
index b042a14..e5bd350 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
@@ -40,20 +40,27 @@
  *     Launch an app [testApp] and wait animation to complete
  *     Press home button
  * ```
+ *
  * To run only the presubmit assertions add: `--
+ *
  * ```
  *      --module-arg FlickerTests:exclude-annotation:androidx.test.filters.FlakyTest
  *      --module-arg FlickerTests:include-annotation:android.platform.test.annotations.Presubmit`
  * ```
+ *
  * To run only the postsubmit assertions add: `--
+ *
  * ```
  *      --module-arg FlickerTests:exclude-annotation:androidx.test.filters.FlakyTest
  *      --module-arg FlickerTests:include-annotation:android.platform.test.annotations.Postsubmit`
  * ```
+ *
  * To run only the flaky assertions add: `--
+ *
  * ```
  *      --module-arg FlickerTests:include-annotation:androidx.test.filters.FlakyTest`
  * ```
+ *
  * Notes:
  * ```
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
index c4628aa..4570fa2 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
@@ -17,7 +17,7 @@
 package com.android.server.wm.flicker.close
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.datatypes.component.ComponentNameMatcher.Companion.LAUNCHER
+import android.tools.common.traces.component.ComponentNameMatcher.Companion.LAUNCHER
 import android.tools.device.apphelpers.StandardAppHelper
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
index e531bc0..6053f1d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
@@ -17,7 +17,7 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.common.traces.wm.WindowManagerState.Companion.STATE_RESUMED
 import android.tools.device.apphelpers.StandardAppHelper
 import android.tools.device.helpers.FIND_TIMEOUT
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/AppPairsHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/AppPairsHelper.kt
index afb9fbf..94ac1a6 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/AppPairsHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/AppPairsHelper.kt
@@ -17,7 +17,7 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
 
 class AppPairsHelper(
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt
index 47dd4e9..c6fa1bb 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt
@@ -17,7 +17,7 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
 import android.tools.device.traces.parsers.toFlickerComponent
 import com.android.server.wm.flicker.testapp.ActivityOptions
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt
index d4f48fe..747cf37 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt
@@ -17,7 +17,7 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
 import android.tools.device.traces.parsers.WindowManagerStateHelper
 import android.tools.device.traces.parsers.toFlickerComponent
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
index 73effbd..d172252 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
@@ -17,7 +17,7 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
 import android.tools.device.helpers.FIND_TIMEOUT
 import android.tools.device.traces.parsers.WindowManagerStateHelper
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeEditorPopupDialogAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeEditorPopupDialogAppHelper.kt
index a6e57d5..7a8d780 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeEditorPopupDialogAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeEditorPopupDialogAppHelper.kt
@@ -17,7 +17,7 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.helpers.FIND_TIMEOUT
 import android.tools.device.traces.parsers.WindowManagerStateHelper
 import android.tools.device.traces.parsers.toFlickerComponent
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt
index d61a500..83a41ab 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt
@@ -18,10 +18,10 @@
 
 import android.app.Instrumentation
 import android.tools.common.Rotation
-import android.tools.common.datatypes.component.ComponentNameMatcher
-import android.tools.common.datatypes.component.IComponentMatcher
 import android.tools.common.traces.Condition
 import android.tools.common.traces.DeviceStateDump
+import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.common.traces.component.IComponentMatcher
 import android.tools.device.helpers.FIND_TIMEOUT
 import android.tools.device.helpers.IME_PACKAGE
 import android.tools.device.traces.parsers.WindowManagerStateHelper
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt
index fb5e1d2..b2aeb14 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt
@@ -17,7 +17,7 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
 import android.tools.device.traces.parsers.toFlickerComponent
 import com.android.server.wm.flicker.testapp.ActivityOptions
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt
index 1ccac13..a670d68 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt
@@ -17,15 +17,15 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import androidx.test.uiautomator.By
-import androidx.test.uiautomator.Until
-import com.android.server.wm.flicker.testapp.ActivityOptions
-import android.tools.common.datatypes.component.ComponentNameMatcher
-import android.tools.device.traces.parsers.toFlickerComponent
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
 import android.tools.device.helpers.FIND_TIMEOUT
 import android.tools.device.helpers.SYSTEMUI_PACKAGE
+import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.device.traces.parsers.toFlickerComponent
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.Until
+import com.android.server.wm.flicker.testapp.ActivityOptions
 
 class LetterboxAppHelper
 @JvmOverloads
@@ -37,13 +37,21 @@
 ) : StandardAppHelper(instr, launcherName, component) {
 
     fun clickRestart(wmHelper: WindowManagerStateHelper) {
-        val restartButton = uiDevice.wait(Until.findObject(By.res(
-            SYSTEMUI_PACKAGE, "size_compat_restart_button")), FIND_TIMEOUT)
+        val restartButton =
+            uiDevice.wait(
+                Until.findObject(By.res(SYSTEMUI_PACKAGE, "size_compat_restart_button")),
+                FIND_TIMEOUT
+            )
         restartButton?.run { restartButton.click() } ?: error("Restart button not found")
 
         // size compat mode restart confirmation dialog button
-        val restartDialogButton = uiDevice.wait(Until.findObject(By.res(
-            SYSTEMUI_PACKAGE, "letterbox_restart_dialog_restart_button")), FIND_TIMEOUT)
+        val restartDialogButton =
+            uiDevice.wait(
+                Until.findObject(
+                    By.res(SYSTEMUI_PACKAGE, "letterbox_restart_dialog_restart_button")
+                ),
+                FIND_TIMEOUT
+            )
         restartDialogButton?.run { restartDialogButton.click() }
             ?: error("Restart dialog button not found")
         wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify()
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt
index ab91685..c98f1c4 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt
@@ -17,7 +17,7 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
 import android.tools.device.helpers.FIND_TIMEOUT
 import android.tools.device.traces.parsers.toFlickerComponent
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MultiWindowUtils.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MultiWindowUtils.kt
index e93e9c8..65175ef 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MultiWindowUtils.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MultiWindowUtils.kt
@@ -19,7 +19,7 @@
 import android.app.Instrumentation
 import android.content.Context
 import android.provider.Settings
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
 import android.util.Log
 import com.android.compatibility.common.util.SystemUtil
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt
index c547ad0..5b3d308 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt
@@ -17,7 +17,7 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
 import android.tools.device.helpers.FIND_TIMEOUT
 import android.tools.device.traces.parsers.WindowManagerStateHelper
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt
index 20ee3b9..ee65004 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt
@@ -17,7 +17,7 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
 import android.tools.device.traces.parsers.toFlickerComponent
 import com.android.server.wm.flicker.testapp.ActivityOptions
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt
index 78f8bcf..7665690 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt
@@ -17,7 +17,7 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
 import android.tools.device.helpers.FIND_TIMEOUT
 import android.tools.device.traces.parsers.WindowManagerStateHelper
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
index c5a21a8..24e231c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
@@ -21,8 +21,8 @@
 import android.media.session.MediaSessionManager
 import android.tools.common.datatypes.Rect
 import android.tools.common.datatypes.Region
-import android.tools.common.datatypes.component.IComponentMatcher
 import android.tools.common.traces.ConditionsFactory
+import android.tools.common.traces.component.IComponentMatcher
 import android.tools.device.apphelpers.StandardAppHelper
 import android.tools.device.helpers.FIND_TIMEOUT
 import android.tools.device.helpers.SYSTEMUI_PACKAGE
@@ -250,7 +250,8 @@
             waitConditions = arrayOf(ConditionsFactory.hasPipWindow())
         )
 
-        wmHelper.StateSyncBuilder()
+        wmHelper
+            .StateSyncBuilder()
             .withWindowSurfaceAppeared(this)
             .withPipShown()
             .waitForAndVerify()
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt
index 06e668e..cac3530 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt
@@ -17,7 +17,7 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
 import android.tools.device.traces.parsers.toFlickerComponent
 import com.android.server.wm.flicker.testapp.ActivityOptions
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt
index 94c90da..8366a7a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt
@@ -17,7 +17,7 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
 import android.tools.device.traces.parsers.toFlickerComponent
 import com.android.server.wm.flicker.testapp.ActivityOptions
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt
index 64af811..89c6c35 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt
@@ -17,7 +17,7 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
 import android.tools.device.traces.parsers.toFlickerComponent
 import com.android.server.wm.flicker.testapp.ActivityOptions
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
index 316766a..895725c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
@@ -17,7 +17,7 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
 import android.tools.device.helpers.FIND_TIMEOUT
 import android.tools.device.traces.parsers.WindowManagerStateHelper
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt
index 34fa921..7e0632d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt
@@ -18,8 +18,8 @@
 
 import android.platform.test.annotations.Presubmit
 import android.tools.common.Rotation
-import android.tools.common.datatypes.component.ComponentNameMatcher
 import android.tools.common.flicker.subject.region.RegionSubject
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt
index 823328a..7f496d8 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt
@@ -19,7 +19,7 @@
 import android.platform.test.annotations.IwTest
 import android.platform.test.annotations.Presubmit
 import android.tools.common.Rotation
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt
index df9d33b..cbe03dc 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.Presubmit
 import android.tools.common.Rotation
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt
index 7954dd1..82c390b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.Presubmit
 import android.tools.common.Rotation
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt
index 10ce5ea..c693ca7 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.IwTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
index 579c10f..8e33719 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
@@ -18,7 +18,7 @@
 
 package com.android.server.wm.flicker.ime
 
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.legacy.FlickerTest
 
 fun FlickerTest.imeLayerBecomesVisible() {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
index 3f87aef..19bbf0c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
@@ -18,8 +18,8 @@
 import android.platform.test.annotations.Presubmit
 import android.tools.common.NavBar
 import android.tools.common.Rotation
-import android.tools.common.datatypes.component.ComponentNameMatcher
 import android.tools.common.flicker.subject.region.RegionSubject
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt
index 6179fc2..f64ad53 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.Presubmit
 import android.tools.common.Rotation
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt
index 690ed53..11bc7b9 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt
@@ -19,7 +19,7 @@
 import android.platform.test.annotations.Presubmit
 import android.tools.common.NavBar
 import android.tools.common.Rotation
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt
index 866e858..46967db 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.Presubmit
 import android.tools.common.Rotation
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt
index 6f22589..277b9155 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.Presubmit
 import android.tools.common.Rotation
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt
index 231d0d7..9275d6a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt
@@ -17,8 +17,8 @@
 package com.android.server.wm.flicker.ime
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.datatypes.component.ComponentNameMatcher
 import android.tools.common.traces.ConditionsFactory
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
index 3c577ac..e6594c9 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
@@ -17,7 +17,7 @@
 package com.android.server.wm.flicker.launch
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTestCfArm.kt
index 3289bc6..ac05c76 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTestCfArm.kt
@@ -41,4 +41,4 @@
             return FlickerTestFactory.nonRotationTests()
         }
     }
-}
\ No newline at end of file
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
index d0dc42f..26f88d2 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -23,9 +23,9 @@
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
 import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.helpers.setRotation
-import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -42,6 +42,7 @@
  *     Make sure no apps are running on the device
  *     Launch an app [testApp] and wait animation to complete
  * ```
+ *
  * Notes:
  * ```
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTestCfArm.kt
index f75d9ee..d9a99da 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTestCfArm.kt
@@ -49,4 +49,4 @@
             return FlickerTestFactory.nonRotationTests()
         }
     }
-}
\ No newline at end of file
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLauncherTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLauncherTransition.kt
index 1a1d403..3d5a8e3 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLauncherTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLauncherTransition.kt
@@ -17,7 +17,7 @@
 package com.android.server.wm.flicker.launch
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.legacy.FlickerTest
 import com.android.server.wm.flicker.replacesLayer
 import org.junit.Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
index b1a267a..b21777b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
@@ -78,9 +78,7 @@
     override fun taskBarLayerIsVisibleAtStartAndEnd() {}
 
     /** {@inheritDoc} */
-    @Test
-    @Ignore("Display is off at the start")
-    override fun taskBarWindowIsAlwaysVisible() {}
+    @Test @Ignore("Display is off at the start") override fun taskBarWindowIsAlwaysVisible() {}
 
     /** {@inheritDoc} */
     @Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt
index e414325..ec92ca6 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt
@@ -20,7 +20,7 @@
 import android.platform.test.annotations.Presubmit
 import android.platform.test.rule.SettingOverrideRule
 import android.provider.Settings
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt
index 0b09e24..009d617 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt
@@ -19,7 +19,7 @@
 import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
@@ -113,9 +113,7 @@
     @Test
     override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
 
-    @Presubmit
-    @Test
-    override fun entireScreenCovered() = super.entireScreenCovered()
+    @Presubmit @Test override fun entireScreenCovered() = super.entireScreenCovered()
 
     @FlakyTest(bugId = 278227468)
     @Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt
index 730f78f..eae9ca1 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
 import com.android.server.wm.flicker.navBarLayerPositionAtEnd
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt
index 9c16b79..7bcb910 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationColdCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationColdCfArm.kt
index 4aa78d4..8b4a613 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationColdCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationColdCfArm.kt
@@ -44,4 +44,4 @@
             return FlickerTestFactory.nonRotationTests()
         }
     }
-}
\ No newline at end of file
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt
index 23cb1d4..425e674d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index 00d7544..8e1b059 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -44,6 +44,7 @@
  *     Relaunch an app [testApp] by selecting it in the overview screen, and wait animation to
  *     complete (only this action is traced)
  * ```
+ *
  * Notes:
  * ```
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
index 17f5638..1383ae3 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
@@ -20,7 +20,7 @@
 import android.platform.test.annotations.Presubmit
 import android.tools.common.NavBar
 import android.tools.common.Rotation
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.annotation.FlickerServiceCompatible
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerTest
@@ -47,6 +47,7 @@
  *     Lock the device.
  *     Launch an app on top of the lock screen [testApp] and wait animation to complete
  * ```
+ *
  * Notes:
  * ```
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
@@ -161,9 +162,7 @@
         super.appWindowBecomesFirstAndOnlyTopWindow()
 
     /** {@inheritDoc} */
-    @Presubmit
-    @Test
-    override fun appWindowBecomesVisible() = super.appWindowBecomesVisible()
+    @Presubmit @Test override fun appWindowBecomesVisible() = super.appWindowBecomesVisible()
 
     /** Checks the [ComponentNameMatcher.NAV_BAR] is visible at the end of the transition */
     @Presubmit
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
index e0db96f..87a14c6 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
@@ -17,7 +17,7 @@
 package com.android.server.wm.flicker.launch
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index cdd2d45..3385830 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -42,6 +42,7 @@
  *     Press home
  *     Relaunch an app [testApp] and wait animation to complete (only this action is traced)
  * ```
+ *
  * Notes:
  * ```
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTestCfArm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTestCfArm.kt
index 9679059..d8b38b3 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTestCfArm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTestCfArm.kt
@@ -43,4 +43,4 @@
             return FlickerTestFactory.nonRotationTests()
         }
     }
-}
\ No newline at end of file
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt
index b848e63..b48611e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt
@@ -20,20 +20,20 @@
 import android.os.Bundle
 import android.os.Handler
 import android.platform.test.annotations.Presubmit
-import android.tools.common.datatypes.component.ComponentNameMatcher
 import android.tools.common.traces.ConditionsFactory
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.junit.FlickerBuilderProvider
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
 import android.tools.device.flicker.legacy.FlickerTestFactory
+import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule
+import android.tools.device.helpers.wakeUpAndGoToHomeScreen
 import androidx.test.filters.RequiresDevice
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.server.wm.flicker.R
-import com.android.server.wm.flicker.helpers.setRotation
-import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule
-import android.tools.device.helpers.wakeUpAndGoToHomeScreen
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.helpers.setRotation
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
index be73547..d0fd732 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
@@ -21,11 +21,11 @@
 import android.content.res.Resources
 import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.datatypes.component.ComponentNameMatcher
-import android.tools.common.datatypes.component.ComponentNameMatcher.Companion.SPLASH_SCREEN
-import android.tools.common.datatypes.component.ComponentNameMatcher.Companion.WALLPAPER_BBQ_WRAPPER
-import android.tools.common.datatypes.component.ComponentSplashScreenMatcher
-import android.tools.common.datatypes.component.IComponentMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher.Companion.SPLASH_SCREEN
+import android.tools.common.traces.component.ComponentNameMatcher.Companion.WALLPAPER_BBQ_WRAPPER
+import android.tools.common.traces.component.ComponentSplashScreenMatcher
+import android.tools.common.traces.component.IComponentMatcher
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
index eadeef5..a8b80ad 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
@@ -20,7 +20,7 @@
 import android.platform.test.annotations.Presubmit
 import android.tools.common.NavBar
 import android.tools.common.datatypes.Rect
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
index 1360495..96cd8ff 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
@@ -20,7 +20,7 @@
 import android.platform.test.annotations.Presubmit
 import android.tools.common.NavBar
 import android.tools.common.datatypes.Rect
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
index d49f035..7e935f0 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
@@ -21,7 +21,7 @@
 import android.tools.common.NavBar
 import android.tools.common.Rotation
 import android.tools.common.datatypes.Rect
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index fe789a7..855ea3e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.IwTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
index 3c0bbd6..fe9da33 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
@@ -17,7 +17,7 @@
 package com.android.server.wm.flicker.rotation
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index 4d010f3..0cbbb83 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -19,7 +19,7 @@
 import android.platform.test.annotations.IwTest
 import android.platform.test.annotations.Presubmit
 import android.tools.common.ScenarioBuilder
-import android.tools.common.datatypes.component.ComponentNameMatcher
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest