Merge "Add Jank Tracker" into main
diff --git a/core/api/current.txt b/core/api/current.txt
index 0153213..d9ab273 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -52997,7 +52997,7 @@
     method public void addOnUnhandledKeyEventListener(android.view.View.OnUnhandledKeyEventListener);
     method public void addTouchables(java.util.ArrayList<android.view.View>);
     method public android.view.ViewPropertyAnimator animate();
-    method public void announceForAccessibility(CharSequence);
+    method @Deprecated @FlaggedApi("android.view.accessibility.deprecate_accessibility_announcement_apis") public void announceForAccessibility(CharSequence);
     method public void autofill(android.view.autofill.AutofillValue);
     method public void autofill(@NonNull android.util.SparseArray<android.view.autofill.AutofillValue>);
     method protected boolean awakenScrollBars();
@@ -55247,7 +55247,7 @@
     field public static final int SPEECH_STATE_SPEAKING_END = 2; // 0x2
     field public static final int SPEECH_STATE_SPEAKING_START = 1; // 0x1
     field public static final int TYPES_ALL_MASK = -1; // 0xffffffff
-    field public static final int TYPE_ANNOUNCEMENT = 16384; // 0x4000
+    field @Deprecated @FlaggedApi("android.view.accessibility.deprecate_accessibility_announcement_apis") public static final int TYPE_ANNOUNCEMENT = 16384; // 0x4000
     field public static final int TYPE_ASSIST_READING_CONTEXT = 16777216; // 0x1000000
     field public static final int TYPE_GESTURE_DETECTION_END = 524288; // 0x80000
     field public static final int TYPE_GESTURE_DETECTION_START = 262144; // 0x40000
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 02cd00d..860089f 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -3579,6 +3579,7 @@
     field @FlaggedApi("android.companion.virtualdevice.flags.activity_control_api") public static final int POLICY_TYPE_BLOCKED_ACTIVITY = 6; // 0x6
     field @FlaggedApi("android.companion.virtual.flags.virtual_camera") public static final int POLICY_TYPE_CAMERA = 5; // 0x5
     field @FlaggedApi("android.companion.virtual.flags.cross_device_clipboard") public static final int POLICY_TYPE_CLIPBOARD = 4; // 0x4
+    field @FlaggedApi("android.companion.virtualdevice.flags.default_device_camera_access_policy") public static final int POLICY_TYPE_DEFAULT_DEVICE_CAMERA_ACCESS = 7; // 0x7
     field public static final int POLICY_TYPE_RECENTS = 2; // 0x2
     field public static final int POLICY_TYPE_SENSORS = 0; // 0x0
   }
diff --git a/core/java/android/companion/virtual/VirtualDeviceParams.java b/core/java/android/companion/virtual/VirtualDeviceParams.java
index 65f9cbe..6dad015 100644
--- a/core/java/android/companion/virtual/VirtualDeviceParams.java
+++ b/core/java/android/companion/virtual/VirtualDeviceParams.java
@@ -160,7 +160,7 @@
      */
     @IntDef(prefix = "POLICY_TYPE_", value = {POLICY_TYPE_SENSORS, POLICY_TYPE_AUDIO,
             POLICY_TYPE_RECENTS, POLICY_TYPE_ACTIVITY, POLICY_TYPE_CLIPBOARD, POLICY_TYPE_CAMERA,
-            POLICY_TYPE_BLOCKED_ACTIVITY})
+            POLICY_TYPE_BLOCKED_ACTIVITY, POLICY_TYPE_DEFAULT_DEVICE_CAMERA_ACCESS})
     @Retention(RetentionPolicy.SOURCE)
     @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
     public @interface PolicyType {}
@@ -301,6 +301,21 @@
     @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_ACTIVITY_CONTROL_API)
     public static final int POLICY_TYPE_BLOCKED_ACTIVITY = 6;
 
+    /**
+     * Tells the virtual device framework how to handle camera access of the default device by apps
+     * running on the virtual device.
+     *
+     * <ul>
+     *     <li>{@link #DEVICE_POLICY_DEFAULT}: Default device camera access will be allowed.
+     *     <li>{@link #DEVICE_POLICY_CUSTOM}: Default device camera access will be blocked.
+     * </ul>
+     *
+     * @see Context#DEVICE_ID_DEFAULT
+     */
+    @FlaggedApi(android.companion.virtualdevice.flags.Flags
+            .FLAG_DEFAULT_DEVICE_CAMERA_ACCESS_POLICY)
+    public static final int POLICY_TYPE_DEFAULT_DEVICE_CAMERA_ACCESS = 7;
+
     private final int mLockState;
     @NonNull private final ArraySet<UserHandle> mUsersWithMatchingAccounts;
     @NavigationPolicy
@@ -696,7 +711,7 @@
 
     @NonNull
     public static final Parcelable.Creator<VirtualDeviceParams> CREATOR =
-            new Parcelable.Creator<VirtualDeviceParams>() {
+            new Parcelable.Creator<>() {
                 public VirtualDeviceParams createFromParcel(Parcel in) {
                     return new VirtualDeviceParams(in);
                 }
@@ -1213,6 +1228,10 @@
                 mDevicePolicies.delete(POLICY_TYPE_CAMERA);
             }
 
+            if (!android.companion.virtualdevice.flags.Flags.defaultDeviceCameraAccessPolicy()) {
+                mDevicePolicies.delete(POLICY_TYPE_DEFAULT_DEVICE_CAMERA_ACCESS);
+            }
+
             if (!android.companion.virtualdevice.flags.Flags.activityControlApi()) {
                 mDevicePolicies.delete(POLICY_TYPE_BLOCKED_ACTIVITY);
             }
diff --git a/core/java/android/companion/virtual/flags.aconfig b/core/java/android/companion/virtual/flags.aconfig
index fc9c94d..3e6919b 100644
--- a/core/java/android/companion/virtual/flags.aconfig
+++ b/core/java/android/companion/virtual/flags.aconfig
@@ -67,13 +67,6 @@
 }
 
 flag {
-  name: "stream_camera"
-  namespace: "virtual_devices"
-  description: "Enable streaming camera to Virtual Devices"
-  bug: "291740640"
-}
-
-flag {
   name: "persistent_device_id_api"
   is_exported: true
   namespace: "virtual_devices"
diff --git a/core/java/android/hardware/usb/OWNERS b/core/java/android/hardware/usb/OWNERS
index a753f96..37604bc 100644
--- a/core/java/android/hardware/usb/OWNERS
+++ b/core/java/android/hardware/usb/OWNERS
@@ -1,7 +1,7 @@
 # Bug component: 175220
 
-aprasath@google.com
-kumarashishg@google.com
-sarup@google.com
 anothermark@google.com
+febinthattil@google.com
+aprasath@google.com
 badhri@google.com
+kumarashishg@google.com
\ No newline at end of file
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 13d7e3c..b3aebad 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -40,8 +40,6 @@
 import android.util.Slog;
 import android.view.View;
 
-import com.android.internal.ravenwood.RavenwoodEnvironment;
-
 import dalvik.system.VMRuntime;
 
 import java.lang.annotation.Retention;
@@ -57,10 +55,6 @@
  */
 @RavenwoodKeepWholeClass
 public class Build {
-    static {
-        // Set up the default system properties.
-        RavenwoodEnvironment.ensureRavenwoodInitialized();
-    }
     private static final String TAG = "Build";
 
     /** Value used for when a build property is unknown. */
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index e80efd2..60eeb2b 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -41,7 +41,6 @@
 import android.net.Uri;
 import android.os.MessageQueue.OnFileDescriptorEventListener;
 import android.ravenwood.annotation.RavenwoodKeepWholeClass;
-import android.ravenwood.annotation.RavenwoodReplace;
 import android.ravenwood.annotation.RavenwoodThrow;
 import android.system.ErrnoException;
 import android.system.Os;
@@ -51,8 +50,6 @@
 import android.util.Log;
 import android.util.Slog;
 
-import com.android.internal.ravenwood.RavenwoodEnvironment;
-
 import dalvik.system.VMRuntime;
 
 import libcore.io.IoUtils;
@@ -1254,15 +1251,10 @@
         }
     }
 
-    @RavenwoodReplace
     private static boolean isAtLeastQ() {
         return (VMRuntime.getRuntime().getTargetSdkVersion() >= Build.VERSION_CODES.Q);
     }
 
-    private static boolean isAtLeastQ$ravenwood() {
-        return RavenwoodEnvironment.workaround().isTargetSdkAtLeastQ();
-    }
-
     private static int ifAtLeastQ(int value) {
         return isAtLeastQ() ? value : 0;
     }
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 71d29af..e728243 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -29,6 +29,11 @@
 import android.annotation.UptimeMillisLong;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build.VERSION_CODES;
+import android.ravenwood.annotation.RavenwoodKeep;
+import android.ravenwood.annotation.RavenwoodKeepPartialClass;
+import android.ravenwood.annotation.RavenwoodRedirect;
+import android.ravenwood.annotation.RavenwoodRedirectionClass;
+import android.ravenwood.annotation.RavenwoodReplace;
 import android.sysprop.MemoryProperties;
 import android.system.ErrnoException;
 import android.system.Os;
@@ -37,8 +42,6 @@
 import android.util.Pair;
 import android.webkit.WebViewZygote;
 
-import com.android.internal.os.SomeArgs;
-import com.android.internal.util.Preconditions;
 import com.android.sdksandbox.flags.Flags;
 
 import dalvik.system.VMDebug;
@@ -55,6 +58,8 @@
 /**
  * Tools for managing OS processes.
  */
+@RavenwoodKeepPartialClass
+@RavenwoodRedirectionClass("Process_ravenwood")
 public class Process {
     private static final String LOG_TAG = "Process";
 
@@ -671,7 +676,6 @@
      */
     public static final ZygoteProcess ZYGOTE_PROCESS = new ZygoteProcess();
 
-
     /**
      * The process name set via {@link #setArgV0(String)}.
      */
@@ -845,47 +849,20 @@
     /**
      * Returns true if the current process is a 64-bit runtime.
      */
-    @android.ravenwood.annotation.RavenwoodKeep
+    @RavenwoodKeep
     public static final boolean is64Bit() {
         return VMRuntime.getRuntime().is64Bit();
     }
 
-    private static volatile ThreadLocal<SomeArgs> sIdentity$ravenwood;
-
-    /** @hide */
-    @android.ravenwood.annotation.RavenwoodKeep
-    public static void init$ravenwood(final int uid, final int pid) {
-        sIdentity$ravenwood = ThreadLocal.withInitial(() -> {
-            final SomeArgs args = SomeArgs.obtain();
-            args.argi1 = uid;
-            args.argi2 = pid;
-            args.argi3 = Long.hashCode(Thread.currentThread().getId());
-            args.argi4 = THREAD_PRIORITY_DEFAULT;
-            args.arg1 = Boolean.TRUE; // backgroundOk
-            return args;
-        });
-    }
-
-    /** @hide */
-    @android.ravenwood.annotation.RavenwoodKeep
-    public static void reset$ravenwood() {
-        sIdentity$ravenwood = null;
-    }
-
     /**
      * Returns the identifier of this process, which can be used with
      * {@link #killProcess} and {@link #sendSignal}.
      */
-    @android.ravenwood.annotation.RavenwoodReplace
+    @RavenwoodKeep
     public static final int myPid() {
         return Os.getpid();
     }
 
-    /** @hide */
-    public static final int myPid$ravenwood() {
-        return Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get().argi2;
-    }
-
     /**
      * Returns the identifier of this process' parent.
      * @hide
@@ -899,39 +876,29 @@
      * Returns the identifier of the calling thread, which be used with
      * {@link #setThreadPriority(int, int)}.
      */
-    @android.ravenwood.annotation.RavenwoodReplace
+    @RavenwoodKeep
     public static final int myTid() {
         return Os.gettid();
     }
 
-    /** @hide */
-    public static final int myTid$ravenwood() {
-        return Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get().argi3;
-    }
-
     /**
      * Returns the identifier of this process's uid.  This is the kernel uid
      * that the process is running under, which is the identity of its
      * app-specific sandbox.  It is different from {@link #myUserHandle} in that
      * a uid identifies a specific app sandbox in a specific user.
      */
-    @android.ravenwood.annotation.RavenwoodReplace
+    @RavenwoodKeep
     public static final int myUid() {
         return Os.getuid();
     }
 
-    /** @hide */
-    public static final int myUid$ravenwood() {
-        return Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get().argi1;
-    }
-
     /**
      * Returns this process's user handle.  This is the
      * user the process is running under.  It is distinct from
      * {@link #myUid()} in that a particular user will have multiple
      * distinct apps running under it each with their own uid.
      */
-    @android.ravenwood.annotation.RavenwoodKeep
+    @RavenwoodKeep
     public static UserHandle myUserHandle() {
         return UserHandle.of(UserHandle.getUserId(myUid()));
     }
@@ -940,7 +907,7 @@
      * Returns whether the given uid belongs to a system core component or not.
      * @hide
      */
-    @android.ravenwood.annotation.RavenwoodKeep
+    @RavenwoodKeep
     public static boolean isCoreUid(int uid) {
         return UserHandle.isCore(uid);
     }
@@ -951,7 +918,7 @@
      * @return Whether the uid corresponds to an application sandbox running in
      *     a specific user.
      */
-    @android.ravenwood.annotation.RavenwoodKeep
+    @RavenwoodKeep
     public static boolean isApplicationUid(int uid) {
         return UserHandle.isApp(uid);
     }
@@ -959,7 +926,7 @@
     /**
      * Returns whether the current process is in an isolated sandbox.
      */
-    @android.ravenwood.annotation.RavenwoodKeep
+    @RavenwoodKeep
     public static final boolean isIsolated() {
         return isIsolated(myUid());
     }
@@ -971,7 +938,7 @@
     @Deprecated
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
             publicAlternatives = "Use {@link #isIsolatedUid(int)} instead.")
-    @android.ravenwood.annotation.RavenwoodKeep
+    @RavenwoodKeep
     public static final boolean isIsolated(int uid) {
         return isIsolatedUid(uid);
     }
@@ -979,7 +946,7 @@
     /**
      * Returns whether the process with the given {@code uid} is an isolated sandbox.
      */
-    @android.ravenwood.annotation.RavenwoodKeep
+    @RavenwoodKeep
     public static final boolean isIsolatedUid(int uid) {
         uid = UserHandle.getAppId(uid);
         return (uid >= FIRST_ISOLATED_UID && uid <= LAST_ISOLATED_UID)
@@ -991,7 +958,7 @@
      * @see android.app.sdksandbox.SdkSandboxManager
      */
     @SuppressLint("UnflaggedApi") // promoting from @SystemApi.
-    @android.ravenwood.annotation.RavenwoodKeep
+    @RavenwoodKeep
     public static final boolean isSdkSandboxUid(int uid) {
         uid = UserHandle.getAppId(uid);
         return (uid >= FIRST_SDK_SANDBOX_UID && uid <= LAST_SDK_SANDBOX_UID);
@@ -1007,7 +974,7 @@
      * @throws IllegalArgumentException if input is not an sdk sandbox uid
      */
     @SuppressLint("UnflaggedApi") // promoting from @SystemApi.
-    @android.ravenwood.annotation.RavenwoodKeep
+    @RavenwoodKeep
     public static final int getAppUidForSdkSandboxUid(int uid) {
         if (!isSdkSandboxUid(uid)) {
             throw new IllegalArgumentException("Input UID is not an SDK sandbox UID");
@@ -1023,7 +990,7 @@
      */
     @SystemApi(client = MODULE_LIBRARIES)
     @TestApi
-    @android.ravenwood.annotation.RavenwoodKeep
+    @RavenwoodKeep
     // TODO(b/318651609): Deprecate once Process#getSdkSandboxUidForAppUid is rolled out to 100%
     public static final int toSdkSandboxUid(int uid) {
         return uid + (FIRST_SDK_SANDBOX_UID - FIRST_APPLICATION_UID);
@@ -1039,7 +1006,7 @@
      * @throws IllegalArgumentException if input is not an app uid
      */
     @FlaggedApi(Flags.FLAG_SDK_SANDBOX_UID_TO_APP_UID_API)
-    @android.ravenwood.annotation.RavenwoodKeep
+    @RavenwoodKeep
     public static final int getSdkSandboxUidForAppUid(int uid) {
         if (!isApplicationUid(uid)) {
             throw new IllegalArgumentException("Input UID is not an app UID");
@@ -1050,7 +1017,7 @@
     /**
      * Returns whether the current process is a sdk sandbox process.
      */
-    @android.ravenwood.annotation.RavenwoodKeep
+    @RavenwoodKeep
     public static final boolean isSdkSandbox() {
         return isSdkSandboxUid(myUid());
     }
@@ -1127,28 +1094,11 @@
      * not have permission to modify the given thread, or to use the given
      * priority.
      */
-    @android.ravenwood.annotation.RavenwoodReplace
+    @RavenwoodRedirect
     public static final native void setThreadPriority(int tid,
             @IntRange(from = -20, to = THREAD_PRIORITY_LOWEST) int priority)
             throws IllegalArgumentException, SecurityException;
 
-    /** @hide */
-    public static final void setThreadPriority$ravenwood(int tid, int priority) {
-        final SomeArgs args =
-                Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get();
-        if (args.argi3 == tid) {
-            boolean backgroundOk = (args.arg1 == Boolean.TRUE);
-            if (priority >= THREAD_PRIORITY_BACKGROUND && !backgroundOk) {
-                throw new IllegalArgumentException(
-                        "Priority " + priority + " blocked by setCanSelfBackground()");
-            }
-            args.argi4 = priority;
-        } else {
-            throw new UnsupportedOperationException(
-                    "Cross-thread priority management not yet available in Ravenwood");
-        }
-    }
-
     /**
      * Call with 'false' to cause future calls to {@link #setThreadPriority(int)} to
      * throw an exception if passed a background-level thread priority.  This is only
@@ -1156,16 +1106,9 @@
      *
      * @hide
      */
-    @android.ravenwood.annotation.RavenwoodReplace
+    @RavenwoodRedirect
     public static final native void setCanSelfBackground(boolean backgroundOk);
 
-    /** @hide */
-    public static final void setCanSelfBackground$ravenwood(boolean backgroundOk) {
-        final SomeArgs args =
-                Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get();
-        args.arg1 = Boolean.valueOf(backgroundOk);
-    }
-
     /**
      * Sets the scheduling group for a thread.
      * @hide
@@ -1294,13 +1237,12 @@
      *
      * @see #setThreadPriority(int, int)
      */
-    @android.ravenwood.annotation.RavenwoodReplace
+    @RavenwoodReplace
     public static final native void setThreadPriority(
             @IntRange(from = -20, to = THREAD_PRIORITY_LOWEST) int priority)
             throws IllegalArgumentException, SecurityException;
 
-    /** @hide */
-    public static final void setThreadPriority$ravenwood(int priority) {
+    private static void setThreadPriority$ravenwood(int priority) {
         setThreadPriority(myTid(), priority);
     }
 
@@ -1317,23 +1259,11 @@
      * @throws IllegalArgumentException Throws IllegalArgumentException if
      * <var>tid</var> does not exist.
      */
-    @android.ravenwood.annotation.RavenwoodReplace
+    @RavenwoodRedirect
     @IntRange(from = -20, to = THREAD_PRIORITY_LOWEST)
     public static final native int getThreadPriority(int tid)
             throws IllegalArgumentException;
 
-    /** @hide */
-    public static final int getThreadPriority$ravenwood(int tid) {
-        final SomeArgs args =
-                Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get();
-        if (args.argi3 == tid) {
-            return args.argi4;
-        } else {
-            throw new UnsupportedOperationException(
-                    "Cross-thread priority management not yet available in Ravenwood");
-        }
-    }
-
     /**
      * Return the current scheduling policy of a thread, based on Linux.
      *
diff --git a/core/java/android/view/HapticFeedbackConstants.java b/core/java/android/view/HapticFeedbackConstants.java
index 1fe06d4..66d64d7 100644
--- a/core/java/android/view/HapticFeedbackConstants.java
+++ b/core/java/android/view/HapticFeedbackConstants.java
@@ -176,7 +176,7 @@
 
     /**
      * The user is executing a swipe/drag-style gesture, such as pull-to-refresh, where the
-     * gesture action is “eligible” at a certain threshold of movement, and can be cancelled by
+     * gesture action is "eligible" at a certain threshold of movement, and can be cancelled by
      * moving back past the threshold. This constant indicates that the user's motion has just
      * passed the threshold for the action to be activated on release.
      *
@@ -186,7 +186,7 @@
 
     /**
      * The user is executing a swipe/drag-style gesture, such as pull-to-refresh, where the
-     * gesture action is “eligible” at a certain threshold of movement, and can be cancelled by
+     * gesture action is "eligible" at a certain threshold of movement, and can be cancelled by
      * moving back past the threshold. This constant indicates that the user's motion has just
      * re-crossed back "under" the threshold for the action to be activated, meaning the gesture is
      * currently in a cancelled state.
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index e49eec6..f2951d3 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -30,6 +30,7 @@
 import static android.view.Surface.FRAME_RATE_COMPATIBILITY_GTE;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED;
+import static android.view.accessibility.Flags.FLAG_DEPRECATE_ACCESSIBILITY_ANNOUNCEMENT_APIS;
 import static android.view.accessibility.Flags.FLAG_SUPPLEMENTAL_DESCRIPTION;
 import static android.view.accessibility.Flags.removeChildHoverCheckForTouchExploration;
 import static android.view.accessibility.Flags.supplementalDescription;
@@ -8941,44 +8942,45 @@
     }
 
     /**
-     * Convenience method for sending a {@link AccessibilityEvent#TYPE_ANNOUNCEMENT}
-     * {@link AccessibilityEvent} to suggest that an accessibility service announce the
-     * specified text to its users.
-     * <p>
-     * Note: The event generated with this API carries no semantic meaning, and is appropriate only
-     * in exceptional situations. Apps can generally achieve correct behavior for accessibility by
-     * accurately supplying the semantics of their UI.
-     * They should not need to specify what exactly is announced to users.
+     * Convenience method for sending a {@link AccessibilityEvent#TYPE_ANNOUNCEMENT} {@link
+     * AccessibilityEvent} to suggest that an accessibility service announce the specified text to
+     * its users.
      *
-     * <p>
-     * In general, only announce transitions and don't generate a confirmation message for simple
-     * actions like a button press. Label your controls concisely and precisely instead, and for
-     * significant UI changes like window changes, use
-     * {@link android.app.Activity#setTitle(CharSequence)} and
-     * {@link #setAccessibilityPaneTitle(CharSequence)}.
+     * <p>Note: The event generated with this API carries no semantic meaning, and accessibility
+     * services may choose to ignore it. Apps that accurately supply accessibility with the
+     * semantics of their UI should not need to specify what exactly is announced.
      *
-     * <p>
-     * Use {@link #setAccessibilityLiveRegion(int)} to inform the user of changes to critical
+     * <p>In general, do not attempt to generate announcements as confirmation message for simple
+     * actions like a button press. Label your controls concisely and precisely instead.
+     *
+     * <p>To convey significant UI changes like window changes, use {@link
+     * android.app.Activity#setTitle(CharSequence)} and {@link
+     * #setAccessibilityPaneTitle(CharSequence)}.
+     *
+     * <p>Use {@link #setAccessibilityLiveRegion(int)} to inform the user of changes to critical
      * views within the user interface. These should still be used sparingly as they may generate
      * announcements every time a View is updated.
      *
-     * <p>
-     * For notifying users about errors, such as in a login screen with text that displays an
-     * "incorrect password" notification, that view should send an AccessibilityEvent of type
-     * {@link AccessibilityEvent#CONTENT_CHANGE_TYPE_ERROR} and set
-     * {@link AccessibilityNodeInfo#setError(CharSequence)} instead. Custom widgets should expose
-     * error-setting methods that support accessibility automatically. For example, instead of
-     * explicitly sending this event when using a TextView, use
-     * {@link android.widget.TextView#setError(CharSequence)}.
-     *
-     * <p>
-     * Use {@link #setStateDescription(CharSequence)} to convey state changes to views within the
+     * <p>Use {@link #setStateDescription(CharSequence)} to convey state changes to views within the
      * user interface. While a live region may send different types of events generated by the view,
      * state description will send {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} events of
      * type {@link AccessibilityEvent#CONTENT_CHANGE_TYPE_STATE_DESCRIPTION}.
      *
+     * <p>For notifying users about errors, such as in a login screen with text that displays an
+     * "incorrect password" notification, set {@link AccessibilityNodeInfo#setError(CharSequence)}
+     * and dispatch an {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event with a change
+     * type of {@link AccessibilityEvent#CONTENT_CHANGE_TYPE_ERROR}, instead. Some widgets may
+     * expose methods that convey error states to accessibility automatically, such as {@link
+     * android.widget.TextView#setError(CharSequence)}, which manages these accessibility semantics
+     * and event dispatch for callers.
+     *
+     * @deprecated Use one of the methods described in the documentation above to semantically
+     *     describe UI instead of using an announcement, as accessibility services may choose to
+     *     ignore events dispatched with this method.
      * @param text The announcement text.
      */
+    @FlaggedApi(FLAG_DEPRECATE_ACCESSIBILITY_ANNOUNCEMENT_APIS)
+    @Deprecated
     public void announceForAccessibility(CharSequence text) {
         if (AccessibilityManager.getInstance(mContext).isEnabled() && mParent != null) {
             AccessibilityEvent event = AccessibilityEvent.obtain(
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index c690787..0dfaf41 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -563,10 +563,13 @@
 
     /**
      * Represents the event of an application making an announcement.
-     * <p>
-     * In general, follow the practices described in
-     * {@link View#announceForAccessibility(CharSequence)}.
+     *
+     * @deprecated Use one of the semantic alternative methods described in the documentation of
+     *     {@link View#announceForAccessibility(CharSequence)} instead of using this event, as
+     *     accessibility services may choose to ignore dispatch of this event type.
      */
+    @FlaggedApi(Flags.FLAG_DEPRECATE_ACCESSIBILITY_ANNOUNCEMENT_APIS)
+    @Deprecated
     public static final int TYPE_ANNOUNCEMENT = 1 << 14;
 
     /**
diff --git a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
index c07da41..7177ef3 100644
--- a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
+++ b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig
@@ -85,6 +85,13 @@
 
 flag {
     namespace: "accessibility"
+    name: "deprecate_accessibility_announcement_apis"
+    description: "Controls the deprecation of platform APIs related to disruptive accessibility announcements"
+    bug: "376727542"
+}
+
+flag {
+    namespace: "accessibility"
     name: "fix_merged_content_change_event_v2"
     description: "Fixes event type and source of content change event merged in ViewRootImpl"
     bug: "277305460"
diff --git a/core/java/android/view/inputmethod/ImeTracker.java b/core/java/android/view/inputmethod/ImeTracker.java
index 2ca62a0..dd32d57 100644
--- a/core/java/android/view/inputmethod/ImeTracker.java
+++ b/core/java/android/view/inputmethod/ImeTracker.java
@@ -221,6 +221,7 @@
             PHASE_WM_INVOKING_IME_REQUESTED_LISTENER,
             PHASE_CLIENT_ALREADY_HIDDEN,
             PHASE_CLIENT_VIEW_HANDLER_AVAILABLE,
+            PHASE_SERVER_UPDATE_CLIENT_VISIBILITY,
     })
     @Retention(RetentionPolicy.SOURCE)
     @interface Phase {}
@@ -430,6 +431,11 @@
      * continue without.
      */
     int PHASE_CLIENT_VIEW_HANDLER_AVAILABLE = ImeProtoEnums.PHASE_CLIENT_VIEW_HANDLER_AVAILABLE;
+    /**
+     * ImeInsetsSourceProvider sets the reported visibility of the caller/client window (either the
+     * app or the RemoteInsetsControlTarget).
+     */
+    int PHASE_SERVER_UPDATE_CLIENT_VISIBILITY = ImeProtoEnums.PHASE_SERVER_UPDATE_CLIENT_VISIBILITY;
 
     /**
      * Called when an IME request is started.
diff --git a/core/java/android/window/flags/responsible_apis.aconfig b/core/java/android/window/flags/responsible_apis.aconfig
index fd5de91..b2f125d 100644
--- a/core/java/android/window/flags/responsible_apis.aconfig
+++ b/core/java/android/window/flags/responsible_apis.aconfig
@@ -16,13 +16,6 @@
 }
 
 flag {
-    name: "bal_show_toasts"
-    namespace: "responsible_apis"
-    description: "Enable toasts to indicate (potential) BAL blocking."
-    bug: "308059069"
-}
-
-flag {
     name: "bal_show_toasts_blocked"
     namespace: "responsible_apis"
     description: "Enable toasts to indicate actual BAL blocking."
@@ -64,14 +57,6 @@
     bug: "339720406"
 }
 
-# replaced by bal_strict_mode_ro
-flag {
-    name: "bal_strict_mode"
-    namespace: "responsible_apis"
-    description: "Strict mode flag"
-    bug: "324089586"
-}
-
 flag {
     name: "bal_strict_mode_ro"
     namespace: "responsible_apis"
diff --git a/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java b/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java
index 30b160a..a69d2e4 100644
--- a/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java
+++ b/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java
@@ -28,19 +28,9 @@
 public final class RavenwoodEnvironment {
     public static final String TAG = "RavenwoodEnvironment";
 
-    private static final RavenwoodEnvironment sInstance;
-    private static final Workaround sWorkaround;
+    private static RavenwoodEnvironment sInstance = new RavenwoodEnvironment();
 
-    private RavenwoodEnvironment() {
-    }
-
-    static {
-        sInstance = new RavenwoodEnvironment();
-        sWorkaround = new Workaround();
-        ensureRavenwoodInitialized();
-    }
-
-    public static RuntimeException notSupportedOnDevice() {
+    private static RuntimeException notSupportedOnDevice() {
         return new UnsupportedOperationException("This method can only be used on Ravenwood");
     }
 
@@ -52,15 +42,6 @@
     }
 
     /**
-     * Initialize the ravenwood environment if it hasn't happened already, if running on Ravenwood.
-     *
-     * No-op if called on the device side.
-     */
-    @RavenwoodRedirect
-    public static void ensureRavenwoodInitialized() {
-    }
-
-    /**
      * USE IT SPARINGLY! Returns true if it's running on Ravenwood, hostside test environment.
      *
      * <p>Using this allows code to behave differently on a real device and on Ravenwood, but
@@ -91,38 +72,10 @@
     }
 
     /**
-     * See {@link Workaround}. It's only usable on Ravenwood.
-     */
-    @RavenwoodReplace
-    public static Workaround workaround() {
-        throw notSupportedOnDevice();
-    }
-
-    private static Workaround workaround$ravenwood() {
-        return sWorkaround;
-    }
-
-    /**
      * @return the "ravenwood-runtime" directory.
      */
     @RavenwoodRedirect
     public String getRavenwoodRuntimePath() {
         throw notSupportedOnDevice();
     }
-
-    /**
-     * A set of APIs used to work around missing features on Ravenwood. Ideally, this class should
-     * be empty, and all its APIs should be able to be implemented properly.
-     */
-    public static class Workaround {
-        Workaround() {
-        }
-
-        /**
-         * @return whether the app's target SDK level is at least Q.
-         */
-        public boolean isTargetSdkAtLeastQ() {
-            return true;
-        }
-    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 75f8839..83ad14b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -554,19 +554,6 @@
         }
     }
 
-    /** Move a desktop app to split screen. */
-    fun moveToSplit(task: RunningTaskInfo) {
-        logV( "moveToSplit taskId=%s", task.taskId)
-        desktopTilingDecorViewModel.removeTaskIfTiled(task.displayId, task.taskId)
-        val wct = WindowContainerTransaction()
-        wct.setBounds(task.token, Rect())
-        // Rather than set windowing mode to multi-window at task level, set it to
-        // undefined and inherit from split stage.
-        wct.setWindowingMode(task.token, WINDOWING_MODE_UNDEFINED)
-
-        transitions.startTransition(TRANSIT_CHANGE, wct, null /* handler */)
-    }
-
     private fun exitSplitIfApplicable(wct: WindowContainerTransaction, taskInfo: RunningTaskInfo) {
         if (splitScreenController.isTaskInSplitScreen(taskInfo.taskId)) {
             splitScreenController.prepareExitSplitScreen(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipEnterAnimator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipEnterAnimator.java
index e513758..eb33ff4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipEnterAnimator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipEnterAnimator.java
@@ -20,6 +20,7 @@
 import static android.view.Surface.ROTATION_90;
 
 import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.animation.RectEvaluator;
 import android.animation.ValueAnimator;
 import android.content.Context;
@@ -34,6 +35,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.launcher3.icons.IconProvider;
 import com.android.wm.shell.R;
 import com.android.wm.shell.common.pip.PipUtils;
@@ -45,8 +47,7 @@
 /**
  * Animator that handles bounds animations for entering PIP.
  */
-public class PipEnterAnimator extends ValueAnimator
-        implements ValueAnimator.AnimatorUpdateListener, ValueAnimator.AnimatorListener {
+public class PipEnterAnimator extends ValueAnimator {
     @NonNull private final SurfaceControl mLeash;
     private final SurfaceControl.Transaction mStartTransaction;
     private final SurfaceControl.Transaction mFinishTransaction;
@@ -56,49 +57,82 @@
 
     private final RectEvaluator mRectEvaluator;
     private final Rect mEndBounds = new Rect();
-    @Nullable private final Rect mSourceRectHint;
     private final @Surface.Rotation int mRotation;
     @Nullable private Runnable mAnimationStartCallback;
     @Nullable private Runnable mAnimationEndCallback;
 
-    private final PipSurfaceTransactionHelper.SurfaceControlTransactionFactory
+    private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory
             mSurfaceControlTransactionFactory;
     Matrix mTransformTensor = new Matrix();
     final float[] mMatrixTmp = new float[9];
     @Nullable private PipContentOverlay mContentOverlay;
 
+    private PipAppIconOverlaySupplier mPipAppIconOverlaySupplier;
 
     // Internal state representing initial transform - cached to avoid recalculation.
     private final PointF mInitScale = new PointF();
     private final PointF mInitPos = new PointF();
     private final Rect mInitCrop = new Rect();
-    private final PointF mInitActivityScale = new PointF();
-    private final PointF mInitActivityPos = new PointF();
+
+    private final Animator.AnimatorListener mAnimatorListener = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationStart(Animator animation) {
+            super.onAnimationStart(animation);
+            if (mAnimationStartCallback != null) {
+                mAnimationStartCallback.run();
+            }
+            if (mStartTransaction != null) {
+                onEnterAnimationUpdate(0f /* fraction */, mStartTransaction);
+                mStartTransaction.apply();
+            }
+        }
+
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            super.onAnimationEnd(animation);
+            if (mFinishTransaction != null) {
+                onEnterAnimationUpdate(1f /* fraction */, mFinishTransaction);
+            }
+            if (mAnimationEndCallback != null) {
+                mAnimationEndCallback.run();
+            }
+        }
+    };
+
+    private final AnimatorUpdateListener mAnimatorUpdateListener = new AnimatorUpdateListener() {
+        @Override
+        public void onAnimationUpdate(@NonNull ValueAnimator animation) {
+            final SurfaceControl.Transaction tx =
+                    mSurfaceControlTransactionFactory.getTransaction();
+            final float fraction = getAnimatedFraction();
+            onEnterAnimationUpdate(fraction, tx);
+            tx.apply();
+        }
+    };
 
     public PipEnterAnimator(Context context,
             @NonNull SurfaceControl leash,
             SurfaceControl.Transaction startTransaction,
             SurfaceControl.Transaction finishTransaction,
             @NonNull Rect endBounds,
-            @Nullable Rect sourceRectHint,
             @Surface.Rotation int rotation) {
         mLeash = leash;
         mStartTransaction = startTransaction;
         mFinishTransaction = finishTransaction;
         mRectEvaluator = new RectEvaluator(mAnimatedRect);
         mEndBounds.set(endBounds);
-        mSourceRectHint = sourceRectHint != null ? new Rect(sourceRectHint) : null;
         mRotation = rotation;
         mSurfaceControlTransactionFactory =
                 new PipSurfaceTransactionHelper.VsyncSurfaceControlTransactionFactory();
+        mPipAppIconOverlaySupplier = this::getAppIconOverlay;
 
         final int enterAnimationDuration = context.getResources()
                 .getInteger(R.integer.config_pipEnterAnimationDuration);
         setDuration(enterAnimationDuration);
         setFloatValues(0f, 1f);
         setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
-        addListener(this);
-        addUpdateListener(this);
+        addListener(mAnimatorListener);
+        addUpdateListener(mAnimatorUpdateListener);
     }
 
     public void setAnimationStartCallback(@NonNull Runnable runnable) {
@@ -109,35 +143,6 @@
         mAnimationEndCallback = runnable;
     }
 
-    @Override
-    public void onAnimationStart(@NonNull Animator animation) {
-        if (mAnimationStartCallback != null) {
-            mAnimationStartCallback.run();
-        }
-        if (mStartTransaction != null) {
-            onEnterAnimationUpdate(0f /* fraction */, mStartTransaction);
-            mStartTransaction.apply();
-        }
-    }
-
-    @Override
-    public void onAnimationEnd(@NonNull Animator animation) {
-        if (mFinishTransaction != null) {
-            onEnterAnimationUpdate(1f /* fraction */, mFinishTransaction);
-        }
-        if (mAnimationEndCallback != null) {
-            mAnimationEndCallback.run();
-        }
-    }
-
-    @Override
-    public void onAnimationUpdate(@NonNull ValueAnimator animation) {
-        final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
-        final float fraction = getAnimatedFraction();
-        onEnterAnimationUpdate(fraction, tx);
-        tx.apply();
-    }
-
     /**
      * Updates the transaction to reflect the state of PiP leash at a certain fraction during enter.
      *
@@ -177,14 +182,6 @@
         }
     }
 
-    // no-ops
-
-    @Override
-    public void onAnimationCancel(@NonNull Animator animation) {}
-
-    @Override
-    public void onAnimationRepeat(@NonNull Animator animation) {}
-
     /**
      * Caches the initial transform relevant values for the bounds enter animation.
      *
@@ -201,18 +198,13 @@
      */
     public void setAppIconContentOverlay(Context context, Rect appBounds, Rect destinationBounds,
             ActivityInfo activityInfo, int appIconSizePx) {
-        reattachAppIconOverlay(
-                new PipAppIconOverlay(context, appBounds, destinationBounds,
-                        new IconProvider(context).getIcon(activityInfo), appIconSizePx));
-    }
-
-    private void reattachAppIconOverlay(PipAppIconOverlay overlay) {
         final SurfaceControl.Transaction tx =
                 mSurfaceControlTransactionFactory.getTransaction();
         if (mContentOverlay != null) {
             mContentOverlay.detach(tx);
         }
-        mContentOverlay = overlay;
+        mContentOverlay = mPipAppIconOverlaySupplier.get(context, appBounds, destinationBounds,
+                activityInfo, appIconSizePx);
         mContentOverlay.attach(tx, mLeash);
     }
 
@@ -229,6 +221,13 @@
         mContentOverlay = null;
     }
 
+    private PipAppIconOverlay getAppIconOverlay(
+            Context context, Rect appBounds, Rect destinationBounds,
+            ActivityInfo activityInfo, int iconSize) {
+        return new PipAppIconOverlay(context, appBounds, destinationBounds,
+                new IconProvider(context).getIcon(activityInfo), iconSize);
+    }
+
     /**
      * @return the app icon overlay leash; null if no overlay is attached.
      */
@@ -239,4 +238,21 @@
         }
         return mContentOverlay.getLeash();
     }
+
+    @VisibleForTesting
+    void setSurfaceControlTransactionFactory(
+            @NonNull PipSurfaceTransactionHelper.SurfaceControlTransactionFactory factory) {
+        mSurfaceControlTransactionFactory = factory;
+    }
+
+    @VisibleForTesting
+    interface PipAppIconOverlaySupplier {
+        PipAppIconOverlay get(Context context, Rect appBounds, Rect destinationBounds,
+                ActivityInfo activityInfo, int iconSize);
+    }
+
+    @VisibleForTesting
+    void setPipAppIconOverlaySupplier(@NonNull PipAppIconOverlaySupplier supplier) {
+        mPipAppIconOverlaySupplier = supplier;
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
index 64d8887..6bf92f6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
@@ -352,17 +352,11 @@
             handleBoundsTypeFixedRotation(pipChange, pipActivityChange, endRotation);
         }
 
-        Rect sourceRectHint = null;
-        if (pipChange.getTaskInfo() != null
-                && pipChange.getTaskInfo().pictureInPictureParams != null) {
-            sourceRectHint = pipChange.getTaskInfo().pictureInPictureParams.getSourceRectHint();
-        }
-
         prepareConfigAtEndActivity(startTransaction, finishTransaction, pipChange,
                 pipActivityChange);
         startTransaction.merge(finishTransaction);
         PipEnterAnimator animator = new PipEnterAnimator(mContext, pipLeash,
-                startTransaction, finishTransaction, destinationBounds, sourceRectHint, delta);
+                startTransaction, finishTransaction, destinationBounds, delta);
         animator.setEnterStartState(pipChange);
         animator.onEnterAnimationUpdate(1.0f /* fraction */, startTransaction);
         startTransaction.apply();
@@ -433,7 +427,7 @@
         }
 
         PipEnterAnimator animator = new PipEnterAnimator(mContext, pipLeash,
-                startTransaction, finishTransaction, endBounds, adjustedSourceRectHint, delta);
+                startTransaction, finishTransaction, endBounds, delta);
         if (sourceRectHint == null) {
             // update the src-rect-hint in params in place, to set up initial animator transform.
             params.getSourceRectHint().set(adjustedSourceRectHint);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index e1683f3..4d4bd53 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -41,7 +41,6 @@
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
-import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
 
 import android.annotation.NonNull;
 import android.app.ActivityManager;
@@ -122,8 +121,6 @@
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
 import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource;
 import com.android.wm.shell.shared.split.SplitScreenConstants.SplitPosition;
-import com.android.wm.shell.splitscreen.SplitScreen;
-import com.android.wm.shell.splitscreen.SplitScreen.StageType;
 import com.android.wm.shell.splitscreen.SplitScreenController;
 import com.android.wm.shell.sysui.KeyguardChangeListener;
 import com.android.wm.shell.sysui.ShellCommandHandler;
@@ -446,17 +443,6 @@
     @Override
     public void setSplitScreenController(SplitScreenController splitScreenController) {
         mSplitScreenController = splitScreenController;
-        mSplitScreenController.registerSplitScreenListener(new SplitScreen.SplitScreenListener() {
-            @Override
-            public void onTaskStageChanged(int taskId, @StageType int stage, boolean visible) {
-                if (visible && stage != STAGE_TYPE_UNDEFINED) {
-                    DesktopModeWindowDecoration decor = mWindowDecorByTaskId.get(taskId);
-                    if (decor != null && DesktopModeStatus.canEnterDesktopMode(mContext)) {
-                        mDesktopTasksController.moveToSplit(decor.mTaskInfo);
-                    }
-                }
-            }
-        });
     }
 
     @Override
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipEnterAnimatorTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipEnterAnimatorTest.java
new file mode 100644
index 0000000..a4008c1
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipEnterAnimatorTest.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.pip2.animation;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.res.Resources;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.Surface;
+import android.view.SurfaceControl;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.wm.shell.pip2.PipSurfaceTransactionHelper;
+import com.android.wm.shell.pip2.phone.PipAppIconOverlay;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Unit test again {@link PipEnterAnimator}.
+ */
+@SmallTest
+@TestableLooper.RunWithLooper
+@RunWith(AndroidTestingRunner.class)
+public class PipEnterAnimatorTest {
+
+    @Mock private Context mMockContext;
+
+    @Mock private Resources mMockResources;
+
+    @Mock private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory mMockFactory;
+
+    @Mock private SurfaceControl.Transaction mMockAnimateTransaction;
+
+    @Mock private SurfaceControl.Transaction mMockStartTransaction;
+
+    @Mock private SurfaceControl.Transaction mMockFinishTransaction;
+
+    @Mock private Runnable mMockStartCallback;
+
+    @Mock private Runnable mMockEndCallback;
+
+    @Mock private PipAppIconOverlay mMockPipAppIconOverlay;
+
+    @Mock private SurfaceControl mMockAppIconOverlayLeash;
+
+    @Mock private ActivityInfo mMockActivityInfo;
+
+    @Surface.Rotation private int mRotation;
+    private SurfaceControl mTestLeash;
+    private Rect mEndBounds;
+    private PipEnterAnimator mPipEnterAnimator;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        when(mMockContext.getResources()).thenReturn(mMockResources);
+        when(mMockResources.getInteger(anyInt())).thenReturn(0);
+        when(mMockFactory.getTransaction()).thenReturn(mMockAnimateTransaction);
+        when(mMockAnimateTransaction.setMatrix(any(SurfaceControl.class), any(Matrix.class), any()))
+                .thenReturn(mMockAnimateTransaction);
+        when(mMockStartTransaction.setMatrix(any(SurfaceControl.class), any(Matrix.class), any()))
+                .thenReturn(mMockStartTransaction);
+        when(mMockFinishTransaction.setMatrix(any(SurfaceControl.class), any(Matrix.class), any()))
+                .thenReturn(mMockFinishTransaction);
+        when(mMockPipAppIconOverlay.getLeash()).thenReturn(mMockAppIconOverlayLeash);
+
+        mTestLeash = new SurfaceControl.Builder()
+                .setContainerLayer()
+                .setName("PipExpandAnimatorTest")
+                .setCallsite("PipExpandAnimatorTest")
+                .build();
+    }
+
+    @Test
+    public void setAnimationStartCallback_enter_callbackStartCallback() {
+        mRotation = Surface.ROTATION_0;
+        mEndBounds = new Rect(100, 100, 500, 500);
+        mPipEnterAnimator = new PipEnterAnimator(mMockContext, mTestLeash,
+                mMockStartTransaction, mMockFinishTransaction,
+                mEndBounds, mRotation);
+        mPipEnterAnimator.setSurfaceControlTransactionFactory(mMockFactory);
+
+        mPipEnterAnimator.setAnimationStartCallback(mMockStartCallback);
+        mPipEnterAnimator.setAnimationEndCallback(mMockEndCallback);
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            mPipEnterAnimator.start();
+            mPipEnterAnimator.pause();
+        });
+
+        verify(mMockStartCallback).run();
+        verifyZeroInteractions(mMockEndCallback);
+    }
+
+    @Test
+    public void setAnimationEndCallback_enter_callbackStartAndEndCallback() {
+        mRotation = Surface.ROTATION_0;
+        mEndBounds = new Rect(100, 100, 500, 500);
+        mPipEnterAnimator = new PipEnterAnimator(mMockContext, mTestLeash,
+                mMockStartTransaction, mMockFinishTransaction,
+                mEndBounds, mRotation);
+        mPipEnterAnimator.setSurfaceControlTransactionFactory(mMockFactory);
+
+        mPipEnterAnimator.setAnimationStartCallback(mMockStartCallback);
+        mPipEnterAnimator.setAnimationEndCallback(mMockEndCallback);
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            mPipEnterAnimator.start();
+            mPipEnterAnimator.end();
+        });
+
+        verify(mMockStartCallback).run();
+        verify(mMockEndCallback).run();
+    }
+
+    @Test
+    public void setAppIconContentOverlay_thenGetContentOverlayLeash_returnOverlayLeash() {
+        mRotation = Surface.ROTATION_0;
+        mEndBounds = new Rect(100, 100, 500, 500);
+        mPipEnterAnimator = new PipEnterAnimator(mMockContext, mTestLeash,
+                mMockStartTransaction, mMockFinishTransaction,
+                mEndBounds, mRotation);
+        mPipEnterAnimator.setSurfaceControlTransactionFactory(mMockFactory);
+        mPipEnterAnimator.setPipAppIconOverlaySupplier(
+                (context, appBounds, endBounds, icon, iconSize) -> mMockPipAppIconOverlay);
+
+        mPipEnterAnimator.setAppIconContentOverlay(mMockContext, mEndBounds, mEndBounds,
+                mMockActivityInfo, 64 /* iconSize */);
+
+        assertEquals(mPipEnterAnimator.getContentOverlayLeash(), mMockAppIconOverlayLeash);
+    }
+
+    @Test
+    public void setAppIconContentOverlay_thenClearAppIconOverlay_returnNullLeash() {
+        mRotation = Surface.ROTATION_0;
+        mEndBounds = new Rect(100, 100, 500, 500);
+        mPipEnterAnimator = new PipEnterAnimator(mMockContext, mTestLeash,
+                mMockStartTransaction, mMockFinishTransaction,
+                mEndBounds, mRotation);
+        mPipEnterAnimator.setSurfaceControlTransactionFactory(mMockFactory);
+        mPipEnterAnimator.setPipAppIconOverlaySupplier(
+                (context, appBounds, endBounds, icon, iconSize) -> mMockPipAppIconOverlay);
+
+        mPipEnterAnimator.setAppIconContentOverlay(mMockContext, mEndBounds, mEndBounds,
+                mMockActivityInfo, 64 /* iconSize */);
+        mPipEnterAnimator.clearAppIconOverlay();
+
+        assertNull(mPipEnterAnimator.getContentOverlayLeash());
+    }
+
+    @Test
+    public void onEnterAnimationUpdate_withContentOverlay_animateOverlay() {
+        mRotation = Surface.ROTATION_0;
+        mEndBounds = new Rect(100, 100, 500, 500);
+        mPipEnterAnimator = new PipEnterAnimator(mMockContext, mTestLeash,
+                mMockStartTransaction, mMockFinishTransaction,
+                mEndBounds, mRotation);
+        mPipEnterAnimator.setSurfaceControlTransactionFactory(mMockFactory);
+        mPipEnterAnimator.setPipAppIconOverlaySupplier(
+                (context, appBounds, endBounds, icon, iconSize) -> mMockPipAppIconOverlay);
+
+        float fraction = 0.5f;
+        mPipEnterAnimator.setAppIconContentOverlay(mMockContext, mEndBounds, mEndBounds,
+                mMockActivityInfo, 64 /* iconSize */);
+        mPipEnterAnimator.onEnterAnimationUpdate(fraction, mMockAnimateTransaction);
+
+        verify(mMockPipAppIconOverlay).onAnimationUpdate(
+                eq(mMockAnimateTransaction), anyFloat(), eq(fraction), eq(mEndBounds));
+    }
+}
diff --git a/media/java/android/media/flags/editing.aconfig b/media/java/android/media/flags/editing.aconfig
index 185f579..0adc478 100644
--- a/media/java/android/media/flags/editing.aconfig
+++ b/media/java/android/media/flags/editing.aconfig
@@ -15,3 +15,10 @@
   description: "Enable B frames for Stagefright recorder."
   bug: "341121900"
 }
+
+flag {
+  name: "muxer_mp4_enable_apv"
+  namespace: "media_solutions"
+  description: "Enable APV support in mp4 writer."
+  bug: "370061501"
+}
diff --git a/media/java/android/mtp/OWNERS b/media/java/android/mtp/OWNERS
index 6b5336e..77ed08b 100644
--- a/media/java/android/mtp/OWNERS
+++ b/media/java/android/mtp/OWNERS
@@ -1,10 +1,9 @@
 set noparent
 
-aprasath@google.com
 anothermark@google.com
-kumarashishg@google.com
-sarup@google.com
+febinthattil@google.com
+aprasath@google.com
 jsharkey@android.com
 jameswei@google.com
 rmojumder@google.com
-
+kumarashishg@google.com
diff --git a/media/tests/MtpTests/OWNERS b/media/tests/MtpTests/OWNERS
index 6b5336e..bdb6cdb 100644
--- a/media/tests/MtpTests/OWNERS
+++ b/media/tests/MtpTests/OWNERS
@@ -1,10 +1,9 @@
 set noparent
 
-aprasath@google.com
 anothermark@google.com
-kumarashishg@google.com
-sarup@google.com
+febinthattil@google.com
+aprasath@google.com
 jsharkey@android.com
 jameswei@google.com
 rmojumder@google.com
-
+kumarashishg@google.com
\ No newline at end of file
diff --git a/nfc/api/system-current.txt b/nfc/api/system-current.txt
index 24e14e6..80aa7d7 100644
--- a/nfc/api/system-current.txt
+++ b/nfc/api/system-current.txt
@@ -105,7 +105,7 @@
     method public void onRfFieldActivated(boolean);
     method public void onRoutingChanged();
     method public void onStateUpdated(int);
-    method public void onTagConnected(boolean, @NonNull android.nfc.Tag);
+    method public void onTagConnected(boolean);
     method public void onTagDispatch(@NonNull java.util.function.Consumer<java.lang.Boolean>);
   }
 
diff --git a/nfc/java/android/nfc/INfcOemExtensionCallback.aidl b/nfc/java/android/nfc/INfcOemExtensionCallback.aidl
index 48c7ee6..7d0837a 100644
--- a/nfc/java/android/nfc/INfcOemExtensionCallback.aidl
+++ b/nfc/java/android/nfc/INfcOemExtensionCallback.aidl
@@ -27,7 +27,7 @@
  * @hide
  */
 interface INfcOemExtensionCallback {
-   void onTagConnected(boolean connected, in Tag tag);
+   void onTagConnected(boolean connected);
    void onStateUpdated(int state);
    void onApplyRouting(in ResultReceiver isSkipped);
    void onNdefRead(in ResultReceiver isSkipped);
diff --git a/nfc/java/android/nfc/NfcOemExtension.java b/nfc/java/android/nfc/NfcOemExtension.java
index 474ff8c..0a4c488 100644
--- a/nfc/java/android/nfc/NfcOemExtension.java
+++ b/nfc/java/android/nfc/NfcOemExtension.java
@@ -195,9 +195,8 @@
          * ex - if tag is connected  notify cover and Nfctest app if app is in testing mode
          *
          * @param connected status of the tag true if tag is connected otherwise false
-         * @param tag Tag details
          */
-        void onTagConnected(boolean connected, @NonNull Tag tag);
+        void onTagConnected(boolean connected);
 
         /**
          * Update the Nfc Adapter State
@@ -684,9 +683,9 @@
     private final class NfcOemExtensionCallback extends INfcOemExtensionCallback.Stub {
 
         @Override
-        public void onTagConnected(boolean connected, Tag tag) throws RemoteException {
+        public void onTagConnected(boolean connected) throws RemoteException {
             mCallbackMap.forEach((cb, ex) ->
-                    handleVoid2ArgCallback(connected, tag, cb::onTagConnected, ex));
+                    handleVoidCallback(connected, cb::onTagConnected, ex));
         }
 
         @Override
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt
index 66a0908..e78862e 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/NotificationSection.kt
@@ -128,7 +128,7 @@
         }
         val burnIn = rememberBurnIn(clockInteractor)
         AnimatedVisibility(
-            visibleState  = transitionState,
+            visibleState = transitionState,
             enter = fadeIn(),
             exit = fadeOut(),
             modifier =
@@ -151,7 +151,7 @@
                             )
                         }
                     }
-                },
+                }
             )
         }
     }
@@ -173,7 +173,7 @@
         areNotificationsVisible: Boolean,
         isShadeLayoutWide: Boolean,
         burnInParams: BurnInParameters?,
-        modifier: Modifier = Modifier
+        modifier: Modifier = Modifier,
     ) {
         if (!areNotificationsVisible) {
             return
@@ -193,10 +193,7 @@
                         if (burnInParams == null) {
                             it
                         } else {
-                            it.burnInAware(
-                                viewModel = aodBurnInViewModel,
-                                params = burnInParams,
-                            )
+                            it.burnInAware(viewModel = aodBurnInViewModel, params = burnInParams)
                         }
                     },
         )
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt
index 2a91bd8..26c827a 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt
@@ -43,6 +43,7 @@
 import com.android.systemui.compose.modifiers.sysuiResTag
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.lifecycle.rememberViewModel
+import com.android.systemui.notifications.ui.composable.SnoozeableHeadsUpNotificationSpace
 import com.android.systemui.qs.composefragment.ui.GridAnchor
 import com.android.systemui.qs.panels.ui.compose.EditMode
 import com.android.systemui.qs.panels.ui.compose.TileGrid
@@ -53,8 +54,11 @@
 import com.android.systemui.scene.ui.composable.Overlay
 import com.android.systemui.shade.ui.composable.ExpandedShadeHeader
 import com.android.systemui.shade.ui.composable.OverlayShade
+import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView
+import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel
 import com.android.systemui.statusbar.phone.ui.StatusBarIconController
 import com.android.systemui.statusbar.phone.ui.TintedIconManager
+import dagger.Lazy
 import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
 
@@ -67,6 +71,8 @@
     private val tintedIconManagerFactory: TintedIconManager.Factory,
     private val batteryMeterViewControllerFactory: BatteryMeterViewController.Factory,
     private val statusBarIconController: StatusBarIconController,
+    private val notificationStackScrollView: Lazy<NotificationScrollView>,
+    private val notificationsPlaceholderViewModelFactory: NotificationsPlaceholderViewModel.Factory,
 ) : Overlay {
 
     override val key = Overlays.QuickSettingsShade
@@ -98,6 +104,14 @@
 
                 ShadeBody(viewModel = viewModel.quickSettingsContainerViewModel)
             }
+
+            SnoozeableHeadsUpNotificationSpace(
+                stackScrollView = notificationStackScrollView.get(),
+                viewModel =
+                    rememberViewModel("QuickSettingsShadeOverlay") {
+                        notificationsPlaceholderViewModelFactory.create()
+                    },
+            )
         }
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dump/DumpManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dump/DumpManagerTest.kt
index f331060..5827c7b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dump/DumpManagerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dump/DumpManagerTest.kt
@@ -23,6 +23,7 @@
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.table.TableLogBuffer
 import com.google.common.truth.Truth.assertThat
+import java.io.PrintWriter
 import org.junit.Assert.assertThrows
 import org.junit.Before
 import org.junit.Test
@@ -134,6 +135,21 @@
     }
 
     @Test
+    fun registerDumpable_supportsAnonymousDumpables() {
+        val anonDumpable =
+            object : Dumpable {
+                override fun dump(pw: PrintWriter, args: Array<out String>) {
+                    pw.println("AnonDumpable")
+                }
+            }
+
+        // THEN registration with implicit names should succeed
+        dumpManager.registerCriticalDumpable(anonDumpable)
+
+        // No exception thrown
+    }
+
+    @Test
     fun getDumpables_returnsSafeCollection() {
         // GIVEN a variety of registered dumpables
         dumpManager.registerCriticalDumpable("dumpable1", dumpable1)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
index 9c58e2b..92764ae 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
@@ -29,11 +29,13 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.eq
 import org.mockito.Mock
 import org.mockito.Mockito.anyInt
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.verifyNoMoreInteractions
 import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.any
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
@@ -112,4 +114,20 @@
         verify(activityTaskManagerService).setLockScreenShown(true, false)
         verifyNoMoreInteractions(activityTaskManagerService)
     }
+
+    @Test
+    fun setSurfaceBehindVisibility_goesAwayFirst_andIgnoresSecondCall() {
+        underTest.setLockscreenShown(true)
+        underTest.setSurfaceBehindVisibility(true)
+        verify(activityTaskManagerService).keyguardGoingAway(0)
+
+        underTest.setSurfaceBehindVisibility(true)
+        verifyNoMoreInteractions(keyguardTransitions)
+    }
+
+    @Test
+    fun setSurfaceBehindVisibility_falseSetsLockscreenVisibility() {
+        underTest.setSurfaceBehindVisibility(false)
+        verify(activityTaskManagerService).setLockScreenShown(eq(true), any())
+    }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/CommunalSmartspaceControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/CommunalSmartspaceControllerTest.kt
index ce9b3be..7842d75 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/CommunalSmartspaceControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/CommunalSmartspaceControllerTest.kt
@@ -31,6 +31,7 @@
 import com.android.systemui.plugins.BcSmartspaceDataPlugin
 import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceView
 import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.settings.UserTracker
 import com.android.systemui.util.concurrency.Execution
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.withArgCaptor
@@ -52,6 +53,10 @@
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class CommunalSmartspaceControllerTest : SysuiTestCase() {
+    @Mock private lateinit var userTracker: UserTracker
+
+    @Mock private lateinit var userContextPrimary: Context
+
     @Mock private lateinit var smartspaceManager: SmartspaceManager
 
     @Mock private lateinit var execution: Execution
@@ -113,15 +118,18 @@
         MockitoAnnotations.initMocks(this)
         `when`(smartspaceManager.createSmartspaceSession(any())).thenReturn(session)
 
+        `when`(userTracker.userContext).thenReturn(userContextPrimary)
+        `when`(userContextPrimary.getSystemService(SmartspaceManager::class.java))
+            .thenReturn(smartspaceManager)
+
         controller =
             CommunalSmartspaceController(
-                context,
-                smartspaceManager,
+                userTracker,
                 execution,
                 uiExecutor,
                 precondition,
                 Optional.of(targetFilter),
-                Optional.of(plugin)
+                Optional.of(plugin),
             )
     }
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt
index e774aed..c83c82d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt
@@ -33,6 +33,7 @@
 import com.android.systemui.plugins.BcSmartspaceDataPlugin
 import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceView
 import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.settings.UserTracker
 import com.android.systemui.smartspace.dagger.SmartspaceViewComponent
 import com.android.systemui.util.concurrency.Execution
 import com.android.systemui.util.mockito.any
@@ -46,66 +47,51 @@
 import org.junit.runner.RunWith
 import org.mockito.Mock
 import org.mockito.Mockito
+import org.mockito.Mockito.anyInt
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when`
-import org.mockito.Mockito.anyInt
 import org.mockito.MockitoAnnotations
-import org.mockito.Spy
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class DreamSmartspaceControllerTest : SysuiTestCase() {
-    @Mock
-    private lateinit var smartspaceManager: SmartspaceManager
+    @Mock private lateinit var userTracker: UserTracker
 
-    @Mock
-    private lateinit var execution: Execution
+    @Mock private lateinit var userContextPrimary: Context
 
-    @Mock
-    private lateinit var uiExecutor: Executor
+    @Mock private lateinit var smartspaceManager: SmartspaceManager
 
-    @Mock
-    private lateinit var viewComponentFactory: SmartspaceViewComponent.Factory
+    @Mock private lateinit var execution: Execution
 
-    @Mock
-    private lateinit var viewComponent: SmartspaceViewComponent
+    @Mock private lateinit var uiExecutor: Executor
 
-    @Mock
-    private lateinit var weatherViewComponent: SmartspaceViewComponent
+    @Mock private lateinit var viewComponentFactory: SmartspaceViewComponent.Factory
 
-    private val weatherSmartspaceView: SmartspaceView by lazy {
-        Mockito.spy(TestView(context))
-    }
+    @Mock private lateinit var viewComponent: SmartspaceViewComponent
 
-    @Mock
-    private lateinit var targetFilter: SmartspaceTargetFilter
+    @Mock private lateinit var weatherViewComponent: SmartspaceViewComponent
 
-    @Mock
-    private lateinit var plugin: BcSmartspaceDataPlugin
+    private val weatherSmartspaceView: SmartspaceView by lazy { Mockito.spy(TestView(context)) }
 
-    @Mock
-    private lateinit var weatherPlugin: BcSmartspaceDataPlugin
+    @Mock private lateinit var targetFilter: SmartspaceTargetFilter
 
-    @Mock
-    private lateinit var precondition: SmartspacePrecondition
+    @Mock private lateinit var plugin: BcSmartspaceDataPlugin
 
-    private val smartspaceView: SmartspaceView by lazy {
-        Mockito.spy(TestView(context))
-    }
+    @Mock private lateinit var weatherPlugin: BcSmartspaceDataPlugin
 
-    @Mock
-    private lateinit var listener: BcSmartspaceDataPlugin.SmartspaceTargetListener
+    @Mock private lateinit var precondition: SmartspacePrecondition
 
-    @Mock
-    private lateinit var session: SmartspaceSession
+    private val smartspaceView: SmartspaceView by lazy { Mockito.spy(TestView(context)) }
+
+    @Mock private lateinit var listener: BcSmartspaceDataPlugin.SmartspaceTargetListener
+
+    @Mock private lateinit var session: SmartspaceSession
 
     private lateinit var controller: DreamSmartspaceController
 
     // TODO(b/272811280): Remove usage of real view
-    private val fakeParent by lazy {
-        FrameLayout(context)
-    }
+    private val fakeParent by lazy { FrameLayout(context) }
 
     /**
      * A class which implements SmartspaceView and extends View. This is mocked to provide the right
@@ -134,30 +120,44 @@
 
         override fun setMediaTarget(target: SmartspaceTarget?) {}
 
-        override fun getSelectedPage(): Int { return 0; }
+        override fun getSelectedPage(): Int {
+            return 0
+        }
 
-        override fun getCurrentCardTopPadding(): Int { return 0; }
+        override fun getCurrentCardTopPadding(): Int {
+            return 0
+        }
     }
 
     @Before
     fun setup() {
         MockitoAnnotations.initMocks(this)
         `when`(viewComponentFactory.create(any(), eq(plugin), any(), eq(null)))
-                .thenReturn(viewComponent)
+            .thenReturn(viewComponent)
         `when`(viewComponent.getView()).thenReturn(smartspaceView)
         `when`(viewComponentFactory.create(any(), eq(weatherPlugin), any(), any()))
             .thenReturn(weatherViewComponent)
         `when`(weatherViewComponent.getView()).thenReturn(weatherSmartspaceView)
         `when`(smartspaceManager.createSmartspaceSession(any())).thenReturn(session)
 
-        controller = DreamSmartspaceController(context, smartspaceManager, execution, uiExecutor,
-                viewComponentFactory, precondition, Optional.of(targetFilter), Optional.of(plugin),
-        Optional.of(weatherPlugin))
+        `when`(userTracker.userContext).thenReturn(userContextPrimary)
+        `when`(userContextPrimary.getSystemService(SmartspaceManager::class.java))
+            .thenReturn(smartspaceManager)
+
+        controller =
+            DreamSmartspaceController(
+                userTracker,
+                execution,
+                uiExecutor,
+                viewComponentFactory,
+                precondition,
+                Optional.of(targetFilter),
+                Optional.of(plugin),
+                Optional.of(weatherPlugin),
+            )
     }
 
-    /**
-     * Ensures smartspace session begins on a listener only flow.
-     */
+    /** Ensures smartspace session begins on a listener only flow. */
     @Test
     fun testConnectOnListen() {
         `when`(precondition.conditionsMet()).thenReturn(true)
@@ -165,18 +165,18 @@
 
         verify(smartspaceManager).createSmartspaceSession(any())
 
-        var targetListener = withArgCaptor<SmartspaceSession.OnTargetsAvailableListener> {
-            verify(session).addOnTargetsAvailableListener(any(), capture())
-        }
+        var targetListener =
+            withArgCaptor<SmartspaceSession.OnTargetsAvailableListener> {
+                verify(session).addOnTargetsAvailableListener(any(), capture())
+            }
 
         `when`(targetFilter.filterSmartspaceTarget(any())).thenReturn(true)
 
         var target = Mockito.mock(SmartspaceTarget::class.java)
         targetListener.onTargetsAvailable(listOf(target))
 
-        var targets = withArgCaptor<List<SmartspaceTarget>> {
-            verify(plugin).onTargetsAvailable(capture())
-        }
+        var targets =
+            withArgCaptor<List<SmartspaceTarget>> { verify(plugin).onTargetsAvailable(capture()) }
 
         assertThat(targets.contains(target)).isTrue()
 
@@ -185,17 +185,16 @@
         verify(session).close()
     }
 
-    /**
-     * Ensures session begins when a view is attached.
-     */
+    /** Ensures session begins when a view is attached. */
     @Test
     fun testConnectOnViewCreate() {
         `when`(precondition.conditionsMet()).thenReturn(true)
         controller.buildAndConnectView(Mockito.mock(ViewGroup::class.java))
 
-        val stateChangeListener = withArgCaptor<View.OnAttachStateChangeListener> {
-            verify(viewComponentFactory).create(any(), eq(plugin), capture(), eq(null))
-        }
+        val stateChangeListener =
+            withArgCaptor<View.OnAttachStateChangeListener> {
+                verify(viewComponentFactory).create(any(), eq(plugin), capture(), eq(null))
+            }
 
         val mockView = Mockito.mock(TestView::class.java)
         `when`(precondition.conditionsMet()).thenReturn(true)
@@ -209,9 +208,7 @@
         verify(session).close()
     }
 
-    /**
-     * Ensures session is created when weather smartspace view is created and attached.
-     */
+    /** Ensures session is created when weather smartspace view is created and attached. */
     @Test
     fun testConnectOnWeatherViewCreate() {
         `when`(precondition.conditionsMet()).thenReturn(true)
@@ -223,8 +220,8 @@
 
         // Then weather view is created with custom view and the default weatherPlugin.getView
         // should not be called
-        verify(viewComponentFactory).create(eq(fakeParent), eq(weatherPlugin), any(),
-            eq(customView))
+        verify(viewComponentFactory)
+            .create(eq(fakeParent), eq(weatherPlugin), any(), eq(customView))
         verify(weatherPlugin, Mockito.never()).getView(fakeParent)
 
         // And then session is created
@@ -234,9 +231,7 @@
         verify(weatherSmartspaceView).setDozeAmount(0f)
     }
 
-    /**
-     * Ensures weather plugin registers target listener when it is added from the controller.
-     */
+    /** Ensures weather plugin registers target listener when it is added from the controller. */
     @Test
     fun testAddListenerInController_registersListenerForWeatherPlugin() {
         val customView = Mockito.mock(TestView::class.java)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/StatusBarInitializerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/StatusBarInitializerTest.kt
index 20a19a9..938da88 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/StatusBarInitializerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/StatusBarInitializerTest.kt
@@ -26,11 +26,14 @@
 import com.android.systemui.Flags
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.fragments.FragmentHostManager
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.statusbar.data.repository.fakeStatusBarModePerDisplayRepository
 import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment
 import com.android.systemui.statusbar.phone.fragment.dagger.HomeStatusBarComponent
 import com.android.systemui.statusbar.pipeline.shared.ui.composable.StatusBarRootFactory
 import com.android.systemui.statusbar.window.StatusBarWindowController
 import com.android.systemui.statusbar.window.StatusBarWindowControllerStore
+import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
 import kotlin.test.Test
 import org.junit.Assert.assertThrows
@@ -45,12 +48,14 @@
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class StatusBarInitializerTest : SysuiTestCase() {
+    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
     private val windowController = mock(StatusBarWindowController::class.java)
     private val windowControllerStore = mock(StatusBarWindowControllerStore::class.java)
     private val transaction = mock(FragmentTransaction::class.java)
     private val fragmentManager = mock(FragmentManager::class.java)
     private val fragmentHostManager = mock(FragmentHostManager::class.java)
     private val backgroundView = mock(ViewGroup::class.java)
+    private val statusBarModePerDisplayRepository = kosmos.fakeStatusBarModePerDisplayRepository
 
     @Before
     fun setup() {
@@ -72,6 +77,7 @@
             statusBarRootFactory = mock(StatusBarRootFactory::class.java),
             componentFactory = mock(HomeStatusBarComponent.Factory::class.java),
             creationListeners = setOf(),
+            statusBarModePerDisplayRepository = statusBarModePerDisplayRepository,
         )
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarModeRepositoryStoreTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarModeRepositoryStoreTest.kt
new file mode 100644
index 0000000..a9920ec5
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarModeRepositoryStoreTest.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.data.repository
+
+import android.platform.test.annotations.EnableFlags
+import android.view.Display.DEFAULT_DISPLAY
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.display.data.repository.displayRepository
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
+import com.android.systemui.testKosmos
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.verify
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@EnableFlags(StatusBarConnectedDisplays.FLAG_NAME)
+class MultiDisplayStatusBarModeRepositoryStoreTest : SysuiTestCase() {
+
+    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
+    private val testScope = kosmos.testScope
+    private val fakeDisplayRepository = kosmos.displayRepository
+    private val underTest by lazy { kosmos.multiDisplayStatusBarModeRepositoryStore }
+
+    @Before
+    fun start() {
+        underTest.start()
+    }
+
+    @Before fun addDisplays() = runBlocking { fakeDisplayRepository.addDisplay(DEFAULT_DISPLAY) }
+
+    @Test
+    fun forDisplay_startsInstance() =
+        testScope.runTest {
+            val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+
+            verify(instance).start()
+        }
+
+    @Test
+    fun displayRemoved_stopsInstance() =
+        testScope.runTest {
+            val instance = underTest.forDisplay(DEFAULT_DISPLAY)
+
+            fakeDisplayRepository.removeDisplay(DEFAULT_DISPLAY)
+
+            verify(instance).stop()
+        }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
index 12f6825..9099334 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
@@ -98,7 +98,8 @@
                 mock(NavigationModeController.class),
                 mStatusBarModeRepository,
                 mock(DumpManager.class),
-                mTestScope.getCoroutineContext());
+                mTestScope.getCoroutineContext(),
+                mock(BiometricUnlockController.class));
         mLightBarController.start();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 12b5fc0..b491c94 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -27,6 +27,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.AlertDialog;
+import android.app.KeyguardManager;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.PixelFormat;
@@ -315,6 +316,16 @@
         mBiometricCallback = new BiometricCallback();
         mMSDLPlayer = msdlPlayer;
 
+        // Listener for when device locks from adaptive auth, dismiss prompt
+        getContext().getSystemService(KeyguardManager.class).addKeyguardLockedStateListener(
+                getContext().getMainExecutor(),
+                isKeyguardLocked -> {
+                    if (isKeyguardLocked) {
+                        onStartedGoingToSleep();
+                    }
+                }
+        );
+
         final BiometricModalities biometricModalities = new BiometricModalities(
                 Utils.findFirstSensorProperties(fpProps, mConfig.mSensorIds),
                 Utils.findFirstSensorProperties(faceProps, mConfig.mSensorIds));
diff --git a/packages/SystemUI/src/com/android/systemui/common/data/CommonDataLayerModule.kt b/packages/SystemUI/src/com/android/systemui/common/data/CommonDataLayerModule.kt
index b0f5e5e..1923880 100644
--- a/packages/SystemUI/src/com/android/systemui/common/data/CommonDataLayerModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/data/CommonDataLayerModule.kt
@@ -18,8 +18,6 @@
 
 import com.android.systemui.common.data.repository.PackageChangeRepository
 import com.android.systemui.common.data.repository.PackageChangeRepositoryImpl
-import com.android.systemui.common.ui.data.repository.ConfigurationRepository
-import com.android.systemui.common.ui.data.repository.ConfigurationRepositoryImpl
 import dagger.Binds
 import dagger.Module
 
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationStateModule.kt b/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationStateModule.kt
index e0756fc..a3735f9 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationStateModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationStateModule.kt
@@ -17,7 +17,6 @@
 package com.android.systemui.common.ui
 
 import android.content.Context
-import com.android.systemui.common.ui.data.repository.ConfigurationRepositoryModule
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.statusbar.policy.ConfigurationController
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt b/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt
index 31a7fa4..df89152 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt
@@ -134,7 +134,8 @@
                     maxDisplayMode.physicalWidth,
                     maxDisplayMode.physicalHeight,
                     displayInfo.value.naturalWidth,
-                    displayInfo.value.naturalHeight)
+                    displayInfo.value.naturalHeight,
+                )
             return if (scaleFactor == Float.POSITIVE_INFINITY) 1f else scaleFactor
         }
         return 1f
@@ -148,7 +149,7 @@
     interface Factory {
         fun create(
             context: Context,
-            configurationController: ConfigurationController
+            configurationController: ConfigurationController,
         ): ConfigurationRepositoryImpl
     }
 }
@@ -174,7 +175,7 @@
         fun provideGlobalConfigRepository(
             context: Context,
             @GlobalConfig configurationController: ConfigurationController,
-            factory: ConfigurationRepositoryImpl.Factory
+            factory: ConfigurationRepositoryImpl.Factory,
         ): ConfigurationRepository {
             return factory.create(context, configurationController)
         }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/smartspace/CommunalSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/communal/smartspace/CommunalSmartspaceController.kt
index 012c844..b80e77c 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/smartspace/CommunalSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/smartspace/CommunalSmartspaceController.kt
@@ -19,13 +19,13 @@
 import android.app.smartspace.SmartspaceConfig
 import android.app.smartspace.SmartspaceManager
 import android.app.smartspace.SmartspaceSession
-import android.content.Context
 import android.util.Log
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.plugins.BcSmartspaceDataPlugin
 import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceTargetListener
 import com.android.systemui.plugins.BcSmartspaceDataPlugin.UI_SURFACE_GLANCEABLE_HUB
+import com.android.systemui.settings.UserTracker
 import com.android.systemui.smartspace.SmartspacePrecondition
 import com.android.systemui.smartspace.SmartspaceTargetFilter
 import com.android.systemui.smartspace.dagger.SmartspaceModule.Companion.GLANCEABLE_HUB_SMARTSPACE_DATA_PLUGIN
@@ -42,8 +42,7 @@
 class CommunalSmartspaceController
 @Inject
 constructor(
-    private val context: Context,
-    private val smartspaceManager: SmartspaceManager?,
+    private val userTracker: UserTracker,
     private val execution: Execution,
     @Main private val uiExecutor: Executor,
     @Named(LOCKSCREEN_SMARTSPACE_PRECONDITION) private val precondition: SmartspacePrecondition,
@@ -55,6 +54,7 @@
         private const val TAG = "CommunalSmartspaceCtrlr"
     }
 
+    private var userSmartspaceManager: SmartspaceManager? = null
     private var session: SmartspaceSession? = null
     private val plugin: BcSmartspaceDataPlugin? = optionalPlugin.orElse(null)
     private var targetFilter: SmartspaceTargetFilter? = optionalTargetFilter.orElse(null)
@@ -104,7 +104,11 @@
     }
 
     private fun connectSession() {
-        if (smartspaceManager == null) {
+        if (userSmartspaceManager == null) {
+            userSmartspaceManager =
+                userTracker.userContext.getSystemService(SmartspaceManager::class.java)
+        }
+        if (userSmartspaceManager == null) {
             return
         }
         if (plugin == null) {
@@ -119,11 +123,11 @@
         }
 
         val newSession =
-            smartspaceManager.createSmartspaceSession(
-                SmartspaceConfig.Builder(context, UI_SURFACE_GLANCEABLE_HUB).build()
+            userSmartspaceManager?.createSmartspaceSession(
+                SmartspaceConfig.Builder(userTracker.userContext, UI_SURFACE_GLANCEABLE_HUB).build()
             )
         Log.d(TAG, "Starting smartspace session for communal")
-        newSession.addOnTargetsAvailableListener(uiExecutor, sessionListener)
+        newSession?.addOnTargetsAvailableListener(uiExecutor, sessionListener)
         this.session = newSession
 
         plugin?.registerSmartspaceEventNotifier { e -> session?.notifySmartspaceEvent(e) }
@@ -163,7 +167,7 @@
 
     private fun addAndRegisterListener(
         listener: SmartspaceTargetListener,
-        smartspaceDataPlugin: BcSmartspaceDataPlugin?
+        smartspaceDataPlugin: BcSmartspaceDataPlugin?,
     ) {
         execution.assertIsMainThread()
         smartspaceDataPlugin?.registerListener(listener)
@@ -174,7 +178,7 @@
 
     private fun removeAndUnregisterListener(
         listener: SmartspaceTargetListener,
-        smartspaceDataPlugin: BcSmartspaceDataPlugin?
+        smartspaceDataPlugin: BcSmartspaceDataPlugin?,
     ) {
         execution.assertIsMainThread()
         smartspaceDataPlugin?.unregisterListener(listener)
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManagerService.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManagerService.kt
index 4d042fc..be4be19 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManagerService.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/GlanceableHubWidgetManagerService.kt
@@ -22,6 +22,7 @@
 import android.content.Intent
 import android.os.IBinder
 import android.os.RemoteCallbackList
+import android.os.RemoteException
 import android.os.UserHandle
 import android.widget.RemoteViews
 import androidx.lifecycle.LifecycleService
@@ -98,7 +99,15 @@
 
         val job =
             widgetRepository.communalWidgets
-                .onEach { widgets -> listener.onWidgetsUpdated(widgets) }
+                .onEach { widgets ->
+                    try {
+                        listener.onWidgetsUpdated(widgets)
+                    } catch (e: RemoteException) {
+                        logger.e({ "Error pushing widget update: $str1" }) {
+                            str1 = e.localizedMessage
+                        }
+                    }
+                }
                 .launchIn(lifecycleScope)
         widgetListenersRegistry.register(listener, job)
     }
@@ -171,19 +180,41 @@
     private fun createListener(listener: IAppWidgetHostListener): AppWidgetHostListener {
         return object : AppWidgetHostListener {
             override fun onUpdateProviderInfo(appWidget: AppWidgetProviderInfo?) {
-                listener.onUpdateProviderInfo(appWidget)
+                try {
+                    listener.onUpdateProviderInfo(appWidget)
+                } catch (e: RemoteException) {
+                    logger.e({ "Error pushing on update provider info: $str1" }) {
+                        str1 = e.localizedMessage
+                    }
+                }
             }
 
             override fun updateAppWidget(views: RemoteViews?) {
-                listener.updateAppWidget(views)
+                try {
+                    listener.updateAppWidget(views)
+                } catch (e: RemoteException) {
+                    logger.e({ "Error updating app widget: $str1" }) { str1 = e.localizedMessage }
+                }
             }
 
             override fun updateAppWidgetDeferred(packageName: String?, appWidgetId: Int) {
-                listener.updateAppWidgetDeferred(packageName, appWidgetId)
+                try {
+                    listener.updateAppWidgetDeferred(packageName, appWidgetId)
+                } catch (e: RemoteException) {
+                    logger.e({ "Error updating app widget deferred: $str1" }) {
+                        str1 = e.localizedMessage
+                    }
+                }
             }
 
             override fun onViewDataChanged(viewId: Int) {
-                listener.onViewDataChanged(viewId)
+                try {
+                    listener.onViewDataChanged(viewId)
+                } catch (e: RemoteException) {
+                    logger.e({ "Error pushing on view data changed: $str1" }) {
+                        str1 = e.localizedMessage
+                    }
+                }
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/smartspace/DreamSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/dreams/smartspace/DreamSmartspaceController.kt
index 4a8c040..fd91389 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/smartspace/DreamSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/smartspace/DreamSmartspaceController.kt
@@ -20,7 +20,6 @@
 import android.app.smartspace.SmartspaceManager
 import android.app.smartspace.SmartspaceSession
 import android.app.smartspace.SmartspaceTarget
-import android.content.Context
 import android.graphics.Color
 import android.util.Log
 import android.view.View
@@ -31,6 +30,7 @@
 import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceTargetListener
 import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceView
 import com.android.systemui.plugins.BcSmartspaceDataPlugin.UI_SURFACE_DREAM
+import com.android.systemui.settings.UserTracker
 import com.android.systemui.smartspace.SmartspacePrecondition
 import com.android.systemui.smartspace.SmartspaceTargetFilter
 import com.android.systemui.smartspace.dagger.SmartspaceModule.Companion.DREAM_SMARTSPACE_DATA_PLUGIN
@@ -44,13 +44,12 @@
 import javax.inject.Inject
 import javax.inject.Named
 
-/**
- * Controller for managing the smartspace view on the dream
- */
+/** Controller for managing the smartspace view on the dream */
 @SysUISingleton
-class DreamSmartspaceController @Inject constructor(
-    private val context: Context,
-    private val smartspaceManager: SmartspaceManager?,
+class DreamSmartspaceController
+@Inject
+constructor(
+    private val userTracker: UserTracker,
     private val execution: Execution,
     @Main private val uiExecutor: Executor,
     private val smartspaceViewComponentFactory: SmartspaceViewComponent.Factory,
@@ -65,6 +64,7 @@
         private const val TAG = "DreamSmartspaceCtrlr"
     }
 
+    private var userSmartspaceManager: SmartspaceManager? = null
     private var session: SmartspaceSession? = null
     private val weatherPlugin: BcSmartspaceDataPlugin? = optionalWeatherPlugin.orElse(null)
     private val plugin: BcSmartspaceDataPlugin? = optionalPlugin.orElse(null)
@@ -78,66 +78,68 @@
     // Smartspace can be used on multiple displays, such as when the user casts their screen
     private var smartspaceViews = mutableSetOf<SmartspaceView>()
 
-    var preconditionListener = object : SmartspacePrecondition.Listener {
-        override fun onCriteriaChanged() {
-            reloadSmartspace()
+    var preconditionListener =
+        object : SmartspacePrecondition.Listener {
+            override fun onCriteriaChanged() {
+                reloadSmartspace()
+            }
         }
-    }
 
     init {
         precondition.addListener(preconditionListener)
     }
 
-    var filterListener = object : SmartspaceTargetFilter.Listener {
-        override fun onCriteriaChanged() {
-            reloadSmartspace()
+    var filterListener =
+        object : SmartspaceTargetFilter.Listener {
+            override fun onCriteriaChanged() {
+                reloadSmartspace()
+            }
         }
-    }
 
     init {
         targetFilter?.addListener(filterListener)
     }
 
-    var stateChangeListener = object : View.OnAttachStateChangeListener {
-        override fun onViewAttachedToWindow(v: View) {
-            val view = v as SmartspaceView
-            // Until there is dream color matching
-            view.setPrimaryTextColor(Color.WHITE)
-            smartspaceViews.add(view)
-            connectSession()
-            view.setDozeAmount(0f)
-        }
+    var stateChangeListener =
+        object : View.OnAttachStateChangeListener {
+            override fun onViewAttachedToWindow(v: View) {
+                val view = v as SmartspaceView
+                // Until there is dream color matching
+                view.setPrimaryTextColor(Color.WHITE)
+                smartspaceViews.add(view)
+                connectSession()
+                view.setDozeAmount(0f)
+            }
 
-        override fun onViewDetachedFromWindow(v: View) {
-            smartspaceViews.remove(v as SmartspaceView)
+            override fun onViewDetachedFromWindow(v: View) {
+                smartspaceViews.remove(v as SmartspaceView)
 
-            if (smartspaceViews.isEmpty()) {
-                disconnect()
+                if (smartspaceViews.isEmpty()) {
+                    disconnect()
+                }
             }
         }
-    }
 
-    private val sessionListener = SmartspaceSession.OnTargetsAvailableListener { targets ->
-        execution.assertIsMainThread()
+    private val sessionListener =
+        SmartspaceSession.OnTargetsAvailableListener { targets ->
+            execution.assertIsMainThread()
 
-        // The weather data plugin takes unfiltered targets and performs the filtering internally.
-        weatherPlugin?.onTargetsAvailable(targets)
+            // The weather data plugin takes unfiltered targets and performs the filtering
+            // internally.
+            weatherPlugin?.onTargetsAvailable(targets)
 
-        onTargetsAvailableUnfiltered(targets)
-        val filteredTargets = targets.filter { targetFilter?.filterSmartspaceTarget(it) ?: true }
-        plugin?.onTargetsAvailable(filteredTargets)
-    }
+            onTargetsAvailableUnfiltered(targets)
+            val filteredTargets =
+                targets.filter { targetFilter?.filterSmartspaceTarget(it) ?: true }
+            plugin?.onTargetsAvailable(filteredTargets)
+        }
 
-    /**
-     * Constructs the weather view with custom layout and connects it to the weather plugin.
-     */
+    /** Constructs the weather view with custom layout and connects it to the weather plugin. */
     fun buildAndConnectWeatherView(parent: ViewGroup, customView: View?): View? {
         return buildAndConnectViewWithPlugin(parent, weatherPlugin, customView)
     }
 
-    /**
-     * Constructs the smartspace view and connects it to the smartspace service.
-     */
+    /** Constructs the smartspace view and connects it to the smartspace service. */
     fun buildAndConnectView(parent: ViewGroup): View? {
         return buildAndConnectViewWithPlugin(parent, plugin, null)
     }
@@ -145,7 +147,7 @@
     private fun buildAndConnectViewWithPlugin(
         parent: ViewGroup,
         smartspaceDataPlugin: BcSmartspaceDataPlugin?,
-        customView: View?
+        customView: View?,
     ): View? {
         execution.assertIsMainThread()
 
@@ -163,12 +165,13 @@
     private fun buildView(
         parent: ViewGroup,
         smartspaceDataPlugin: BcSmartspaceDataPlugin?,
-        customView: View?
+        customView: View?,
     ): View? {
         return if (smartspaceDataPlugin != null) {
-            val view = smartspaceViewComponentFactory.create(parent, smartspaceDataPlugin,
-                stateChangeListener, customView)
-                .getView()
+            val view =
+                smartspaceViewComponentFactory
+                    .create(parent, smartspaceDataPlugin, stateChangeListener, customView)
+                    .getView()
             if (view !is View) {
                 return null
             }
@@ -179,12 +182,17 @@
     }
 
     private fun hasActiveSessionListeners(): Boolean {
-        return smartspaceViews.isNotEmpty() || listeners.isNotEmpty() ||
+        return smartspaceViews.isNotEmpty() ||
+            listeners.isNotEmpty() ||
             unfilteredListeners.isNotEmpty()
     }
 
     private fun connectSession() {
-        if (smartspaceManager == null) {
+        if (userSmartspaceManager == null) {
+            userSmartspaceManager =
+                userTracker.userContext.getSystemService(SmartspaceManager::class.java)
+        }
+        if (userSmartspaceManager == null) {
             return
         }
         if (plugin == null && weatherPlugin == null) {
@@ -198,25 +206,21 @@
             return
         }
 
-        val newSession = smartspaceManager.createSmartspaceSession(
-            SmartspaceConfig.Builder(context, UI_SURFACE_DREAM).build()
-        )
+        val newSession =
+            userSmartspaceManager?.createSmartspaceSession(
+                SmartspaceConfig.Builder(userTracker.userContext, UI_SURFACE_DREAM).build()
+            )
         Log.d(TAG, "Starting smartspace session for dream")
-        newSession.addOnTargetsAvailableListener(uiExecutor, sessionListener)
+        newSession?.addOnTargetsAvailableListener(uiExecutor, sessionListener)
         this.session = newSession
 
         weatherPlugin?.registerSmartspaceEventNotifier { e -> session?.notifySmartspaceEvent(e) }
-        plugin?.registerSmartspaceEventNotifier {
-                e ->
-            session?.notifySmartspaceEvent(e)
-        }
+        plugin?.registerSmartspaceEventNotifier { e -> session?.notifySmartspaceEvent(e) }
 
         reloadSmartspace()
     }
 
-    /**
-     * Disconnects the smartspace view from the smartspace service and cleans up any resources.
-     */
+    /** Disconnects the smartspace view from the smartspace service and cleans up any resources. */
     private fun disconnect() {
         if (hasActiveSessionListeners()) return
 
@@ -259,7 +263,7 @@
 
     private fun addAndRegisterListener(
         listener: SmartspaceTargetListener,
-        smartspaceDataPlugin: BcSmartspaceDataPlugin?
+        smartspaceDataPlugin: BcSmartspaceDataPlugin?,
     ) {
         execution.assertIsMainThread()
         smartspaceDataPlugin?.registerListener(listener)
@@ -270,7 +274,7 @@
 
     private fun removeAndUnregisterListener(
         listener: SmartspaceTargetListener,
-        smartspaceDataPlugin: BcSmartspaceDataPlugin?
+        smartspaceDataPlugin: BcSmartspaceDataPlugin?,
     ) {
         execution.assertIsMainThread()
         smartspaceDataPlugin?.unregisterListener(listener)
diff --git a/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt b/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt
index 3492365..b2fcc43 100644
--- a/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt
@@ -45,7 +45,7 @@
 
     /** See [registerCriticalDumpable]. */
     fun registerCriticalDumpable(module: Dumpable) {
-        registerCriticalDumpable(module::class.java.canonicalName, module)
+        registerCriticalDumpable(module::class.java.name, module)
     }
 
     /**
@@ -62,7 +62,7 @@
 
     /** See [registerNormalDumpable]. */
     fun registerNormalDumpable(module: Dumpable) {
-        registerNormalDumpable(module::class.java.canonicalName, module)
+        registerNormalDumpable(module::class.java.name, module)
     }
 
     /**
@@ -104,13 +104,10 @@
         dumpables[name] = DumpableEntry(module, name, priority)
     }
 
-    /**
-     * Same as the above override, but automatically uses the canonical class name as the dumpable
-     * name.
-     */
+    /** Same as the above override, but automatically uses the class name as the dumpable name. */
     @Synchronized
     fun registerDumpable(module: Dumpable) {
-        registerDumpable(module::class.java.canonicalName, module)
+        registerDumpable(module::class.java.name, module)
     }
 
     /** Unregisters a previously-registered dumpable. */
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt
index 032af94..2914cb9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt
@@ -44,7 +44,7 @@
     private val keyguardStateController: KeyguardStateController,
     private val keyguardSurfaceBehindAnimator: KeyguardSurfaceBehindParamsApplier,
     private val keyguardDismissTransitionInteractor: KeyguardDismissTransitionInteractor,
-    private val keyguardTransitions: KeyguardTransitions
+    private val keyguardTransitions: KeyguardTransitions,
 ) {
 
     /**
@@ -108,27 +108,28 @@
      * Manager to effect the change.
      */
     fun setSurfaceBehindVisibility(visible: Boolean) {
-        if (isKeyguardGoingAway == visible) {
-            Log.d(TAG, "WmLockscreenVisibilityManager#setVisibility -> already visible=$visible")
+        if (isKeyguardGoingAway && visible) {
+            Log.d(TAG, "#setSurfaceBehindVisibility: already visible, ignoring")
             return
         }
 
         // The surface behind is always visible if the lockscreen is not showing, so we're already
         // visible.
         if (visible && isLockscreenShowing != true) {
-            Log.d(TAG, "#setVisibility -> already visible since the lockscreen isn't showing")
+            Log.d(TAG, "#setSurfaceBehindVisibility: ignoring since the lockscreen isn't showing")
             return
         }
 
-
-
         if (visible) {
             if (enableNewKeyguardShellTransitions) {
-                keyguardTransitions.startKeyguardTransition(false /* keyguardShowing */, false /* aodShowing */)
+                keyguardTransitions.startKeyguardTransition(
+                    false /* keyguardShowing */,
+                    false, /* aodShowing */
+                )
                 isKeyguardGoingAway = true
                 return
             }
-            // Make the surface visible behind the keyguard by calling keyguardGoingAway. The
+            // Make the surface behind the keyguard visible by calling keyguardGoingAway. The
             // lockscreen is still showing as well, allowing us to animate unlocked.
             Log.d(TAG, "ActivityTaskManagerService#keyguardGoingAway()")
             activityTaskManagerService.keyguardGoingAway(0)
@@ -153,7 +154,7 @@
         apps: Array<RemoteAnimationTarget>,
         wallpapers: Array<RemoteAnimationTarget>,
         nonApps: Array<RemoteAnimationTarget>,
-        finishedCallback: IRemoteAnimationFinishedCallback
+        finishedCallback: IRemoteAnimationFinishedCallback,
     ) {
         // Ensure that we've started a dismiss keyguard transition. WindowManager can start the
         // going away animation on its own, if an activity launches and then requests dismissing the
@@ -203,27 +204,25 @@
      */
     private fun setWmLockscreenState(
         lockscreenShowing: Boolean? = this.isLockscreenShowing,
-        aodVisible: Boolean = this.isAodVisible
+        aodVisible: Boolean = this.isAodVisible,
     ) {
-        Log.d(
-            TAG,
-            "#setWmLockscreenState(" +
-                "isLockscreenShowing=$lockscreenShowing, " +
-                "aodVisible=$aodVisible)."
-        )
-
         if (lockscreenShowing == null) {
             Log.d(
                 TAG,
                 "isAodVisible=$aodVisible, but lockscreenShowing=null. Waiting for" +
                     "non-null lockscreenShowing before calling ATMS#setLockScreenShown, which" +
-                    "will happen once KeyguardTransitionBootInteractor starts the boot transition."
+                    "will happen once KeyguardTransitionBootInteractor starts the boot transition.",
             )
             this.isAodVisible = aodVisible
             return
         }
 
         if (this.isLockscreenShowing == lockscreenShowing && this.isAodVisible == aodVisible) {
+            Log.d(
+                TAG,
+                "#setWmLockscreenState: lockscreenShowing=$lockscreenShowing and " +
+                    "isAodVisible=$aodVisible were both unchanged, not forwarding to ATMS.",
+            )
             return
         }
 
@@ -231,7 +230,7 @@
             TAG,
             "ATMS#setLockScreenShown(" +
                 "isLockscreenShowing=$lockscreenShowing, " +
-                "aodVisible=$aodVisible)."
+                "aodVisible=$aodVisible).",
         )
         if (enableNewKeyguardShellTransitions) {
             keyguardTransitions.startKeyguardTransition(lockscreenShowing, aodVisible)
@@ -247,7 +246,7 @@
             Log.d(
                 TAG,
                 "#endKeyguardGoingAwayAnimation() called when isKeyguardGoingAway=false. " +
-                    "Short-circuiting."
+                    "Short-circuiting.",
             )
             return
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt
index 6d5bf32..e922e09 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt
@@ -22,6 +22,7 @@
 import android.view.View
 import androidx.annotation.VisibleForTesting
 import androidx.asynclayoutinflater.view.AsyncLayoutInflater
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.settingslib.applications.InterestingConfigChanges
 import com.android.systemui.Dumpable
 import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
@@ -57,7 +58,6 @@
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.stateIn
 import kotlinx.coroutines.flow.update
-import com.android.app.tracing.coroutines.launchTraced as launch
 import kotlinx.coroutines.withContext
 
 // TODO(307945185) Split View concerns into a ViewBinder
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationController.kt b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationController.kt
index 6e63446..1776a2c 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationController.kt
@@ -18,14 +18,14 @@
 
 import android.content.Context
 import android.view.ViewGroup
-import com.android.systemui.res.R
 import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.statusbar.StatusBarState.SHADE
-import com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED
+import com.android.systemui.res.R
 import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator
 import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator.Direction.END
 import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator.Direction.START
 import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator.ViewIdToTranslate
+import com.android.systemui.statusbar.StatusBarState.SHADE
+import com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED
 import com.android.systemui.unfold.SysUIUnfoldScope
 import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider
 import javax.inject.Inject
@@ -39,8 +39,10 @@
     progressProvider: NaturalRotationUnfoldProgressProvider,
 ) {
 
-    private val filterShade: () -> Boolean = { statusBarStateController.getState() == SHADE ||
-        statusBarStateController.getState() == SHADE_LOCKED }
+    private val filterShade: () -> Boolean = {
+        statusBarStateController.getState() == SHADE ||
+            statusBarStateController.getState() == SHADE_LOCKED
+    }
 
     private val translateAnimator by lazy {
         UnfoldConstantTranslateAnimator(
@@ -48,21 +50,23 @@
                 setOf(
                     ViewIdToTranslate(R.id.quick_settings_panel, START, filterShade),
                     ViewIdToTranslate(R.id.qs_footer_actions, START, filterShade),
-                    ViewIdToTranslate(R.id.notification_stack_scroller, END, filterShade)),
-            progressProvider = progressProvider)
+                    ViewIdToTranslate(R.id.notification_stack_scroller, END, filterShade),
+                ),
+            progressProvider = progressProvider,
+        )
     }
 
     private val translateAnimatorStatusBar by lazy {
         UnfoldConstantTranslateAnimator(
             viewsIdToTranslate =
-            setOf(
-                ViewIdToTranslate(R.id.shade_header_system_icons, END, filterShade),
-                ViewIdToTranslate(R.id.privacy_container, END, filterShade),
-                ViewIdToTranslate(R.id.carrier_group, END, filterShade),
-                ViewIdToTranslate(R.id.clock, START, filterShade),
-                ViewIdToTranslate(R.id.date, START, filterShade)
-            ),
-            progressProvider = progressProvider
+                setOf(
+                    ViewIdToTranslate(R.id.shade_header_system_icons, END, filterShade),
+                    ViewIdToTranslate(R.id.privacy_container, END, filterShade),
+                    ViewIdToTranslate(R.id.carrier_group, END, filterShade),
+                    ViewIdToTranslate(R.id.clock, START, filterShade),
+                    ViewIdToTranslate(R.id.date, START, filterShade),
+                ),
+            progressProvider = progressProvider,
         )
     }
 
@@ -73,10 +77,7 @@
         val splitShadeStatusBarViewGroup: ViewGroup? =
             root.findViewById(R.id.split_shade_status_bar)
         if (splitShadeStatusBarViewGroup != null) {
-            translateAnimatorStatusBar.init(
-                splitShadeStatusBarViewGroup,
-                translationMax
-            )
+            translateAnimatorStatusBar.init(splitShadeStatusBarViewGroup, translationMax)
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt
index 32255c6..6fb9b1f 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt
@@ -96,7 +96,7 @@
     @ShadeDisplayAware
     @SysUISingleton
     fun provideShadeWindowConfigurationForwarder(
-        @ShadeDisplayAware shadeConfigurationController: ConfigurationController,
+        @ShadeDisplayAware shadeConfigurationController: ConfigurationController
     ): ConfigurationForwarder {
         ShadeWindowGoesAround.isUnexpectedlyInLegacyMode()
         return shadeConfigurationController
@@ -125,7 +125,7 @@
         factory: ConfigurationRepositoryImpl.Factory,
         @ShadeDisplayAware configurationController: ConfigurationController,
         @ShadeDisplayAware context: Context,
-        @GlobalConfig globalConfigurationRepository: ConfigurationRepository
+        @GlobalConfig globalConfigurationRepository: ConfigurationRepository,
     ): ConfigurationRepository {
         return if (ShadeWindowGoesAround.isEnabled) {
             factory.create(context, configurationController)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
index 72a4650..2348a11 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
@@ -49,10 +49,7 @@
 import javax.inject.Provider
 
 /** Module for classes related to the notification shade. */
-@Module(
-    includes =
-        [StartShadeModule::class, ShadeViewProviderModule::class]
-)
+@Module(includes = [StartShadeModule::class, ShadeViewProviderModule::class])
 abstract class ShadeModule {
     companion object {
         @Provides
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 5629938..ef62d2d 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
@@ -15,9 +15,7 @@
  */
 package com.android.systemui.shade.data.repository
 
-import android.content.Context
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
 import javax.inject.Inject
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
@@ -182,8 +180,7 @@
 
 /** Business logic for shade interactions */
 @SysUISingleton
-class ShadeRepositoryImpl @Inject constructor() :
-    ShadeRepository {
+class ShadeRepositoryImpl @Inject constructor() : ShadeRepository {
     private val _qsExpansion = MutableStateFlow(0f)
     @Deprecated("Use ShadeInteractor.qsExpansion instead")
     override val qsExpansion: StateFlow<Float> = _qsExpansion.asStateFlow()
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/startable/ShadeStartable.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/startable/ShadeStartable.kt
index a8d616c..44f2911 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/startable/ShadeStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/startable/ShadeStartable.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.shade.domain.startable
 
 import android.content.Context
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.CoreStartable
 import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
 import com.android.systemui.common.ui.data.repository.ConfigurationRepository
@@ -42,7 +43,6 @@
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onStart
-import com.android.app.tracing.coroutines.launchTraced as launch
 
 @SysUISingleton
 class ShadeStartable
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt
index 3abbc6e..f441fd6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt
@@ -23,6 +23,7 @@
 import com.android.systemui.res.R
 import com.android.systemui.statusbar.core.StatusBarInitializer.OnStatusBarViewInitializedListener
 import com.android.systemui.statusbar.core.StatusBarInitializer.OnStatusBarViewUpdatedListener
+import com.android.systemui.statusbar.data.repository.StatusBarModePerDisplayRepository
 import com.android.systemui.statusbar.phone.PhoneStatusBarTransitions
 import com.android.systemui.statusbar.phone.PhoneStatusBarView
 import com.android.systemui.statusbar.phone.PhoneStatusBarViewController
@@ -71,7 +72,10 @@
     }
 
     interface Factory {
-        fun create(statusBarWindowController: StatusBarWindowController): StatusBarInitializer
+        fun create(
+            statusBarWindowController: StatusBarWindowController,
+            statusBarModePerDisplayRepository: StatusBarModePerDisplayRepository,
+        ): StatusBarInitializer
     }
 }
 
@@ -79,6 +83,7 @@
 @AssistedInject
 constructor(
     @Assisted private val statusBarWindowController: StatusBarWindowController,
+    @Assisted private val statusBarModePerDisplayRepository: StatusBarModePerDisplayRepository,
     private val collapsedStatusBarFragmentProvider: Provider<CollapsedStatusBarFragment>,
     private val statusBarRootFactory: StatusBarRootFactory,
     private val componentFactory: HomeStatusBarComponent.Factory,
@@ -127,7 +132,7 @@
                 val phoneStatusBarView = cv.findViewById<PhoneStatusBarView>(R.id.status_bar)
                 component =
                     componentFactory.create(phoneStatusBarView).also { component ->
-                        // CollapsedStatusBarFragment used to be responsible initializting
+                        // CollapsedStatusBarFragment used to be responsible initializing
                         component.init()
 
                         statusBarViewUpdatedListener?.onStatusBarViewUpdated(
@@ -135,8 +140,12 @@
                             component.phoneStatusBarTransitions,
                         )
 
-                        creationListeners.forEach { listener ->
-                            listener.onStatusBarViewInitialized(component)
+                        if (StatusBarConnectedDisplays.isEnabled) {
+                            statusBarModePerDisplayRepository.onStatusBarViewInitialized(component)
+                        } else {
+                            creationListeners.forEach { listener ->
+                                listener.onStatusBarViewInitialized(component)
+                            }
                         }
                     }
             }
@@ -184,7 +193,8 @@
     @AssistedFactory
     interface Factory : StatusBarInitializer.Factory {
         override fun create(
-            statusBarWindowController: StatusBarWindowController
+            statusBarWindowController: StatusBarWindowController,
+            statusBarModePerDisplayRepository: StatusBarModePerDisplayRepository,
         ): StatusBarInitializerImpl
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializerStore.kt
index 041f0b0..4f815c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializerStore.kt
@@ -22,6 +22,7 @@
 import com.android.systemui.display.data.repository.PerDisplayStore
 import com.android.systemui.display.data.repository.PerDisplayStoreImpl
 import com.android.systemui.display.data.repository.SingleDisplayStore
+import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore
 import com.android.systemui.statusbar.window.StatusBarWindowControllerStore
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
@@ -37,6 +38,7 @@
     displayRepository: DisplayRepository,
     private val factory: StatusBarInitializer.Factory,
     private val statusBarWindowControllerStore: StatusBarWindowControllerStore,
+    private val statusBarModeRepositoryStore: StatusBarModeRepositoryStore,
 ) :
     StatusBarInitializerStore,
     PerDisplayStoreImpl<StatusBarInitializer>(backgroundApplicationScope, displayRepository) {
@@ -47,7 +49,8 @@
 
     override fun createInstanceForDisplay(displayId: Int): StatusBarInitializer {
         return factory.create(
-            statusBarWindowController = statusBarWindowControllerStore.forDisplay(displayId)
+            statusBarWindowController = statusBarWindowControllerStore.forDisplay(displayId),
+            statusBarModePerDisplayRepository = statusBarModeRepositoryStore.forDisplay(displayId),
         )
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModePerDisplayRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModePerDisplayRepository.kt
index 44bee1d..cc91e2d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModePerDisplayRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModePerDisplayRepository.kt
@@ -27,7 +27,7 @@
 import android.view.WindowInsetsController.Appearance
 import com.android.internal.statusbar.LetterboxDetails
 import com.android.internal.view.AppearanceRegion
-import com.android.systemui.Dumpable
+import com.android.systemui.CoreStartable
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.statusbar.CommandQueue
 import com.android.systemui.statusbar.core.StatusBarInitializer.OnStatusBarViewInitializedListener
@@ -59,7 +59,7 @@
  * Note: These status bar modes are status bar *window* states that are sent to us from
  * WindowManager, not determined internally.
  */
-interface StatusBarModePerDisplayRepository {
+interface StatusBarModePerDisplayRepository : OnStatusBarViewInitializedListener, CoreStartable {
     /**
      * True if the status bar window is showing transiently and will disappear soon, and false
      * otherwise. ("Otherwise" in this case means the status bar is persistently hidden OR
@@ -104,6 +104,12 @@
      *   determined internally instead.
      */
     fun clearTransient()
+
+    /**
+     * Called when the [StatusBarModePerDisplayRepository] should stop doing any work and clean up
+     * if needed.
+     */
+    fun stop()
 }
 
 class StatusBarModePerDisplayRepositoryImpl
@@ -114,7 +120,7 @@
     private val commandQueue: CommandQueue,
     private val letterboxAppearanceCalculator: LetterboxAppearanceCalculator,
     ongoingCallRepository: OngoingCallRepository,
-) : StatusBarModePerDisplayRepository, OnStatusBarViewInitializedListener, Dumpable {
+) : StatusBarModePerDisplayRepository {
 
     private val commandQueueCallback =
         object : CommandQueue.Callbacks {
@@ -163,10 +169,14 @@
             }
         }
 
-    fun start() {
+    override fun start() {
         commandQueue.addCallback(commandQueueCallback)
     }
 
+    override fun stop() {
+        commandQueue.removeCallback(commandQueueCallback)
+    }
+
     private val _isTransientShown = MutableStateFlow(false)
     override val isTransientShown: StateFlow<Boolean> = _isTransientShown.asStateFlow()
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryStore.kt
index 2c9fa25..143e998 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryStore.kt
@@ -18,21 +18,54 @@
 
 import com.android.systemui.CoreStartable
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.DisplayId
+import com.android.systemui.display.data.repository.DisplayRepository
+import com.android.systemui.display.data.repository.PerDisplayStore
+import com.android.systemui.display.data.repository.PerDisplayStoreImpl
+import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
 import com.android.systemui.statusbar.core.StatusBarInitializer
 import com.android.systemui.statusbar.phone.fragment.dagger.HomeStatusBarComponent
 import dagger.Binds
+import dagger.Lazy
 import dagger.Module
+import dagger.Provides
 import dagger.multibindings.ClassKey
 import dagger.multibindings.IntoMap
 import dagger.multibindings.IntoSet
 import java.io.PrintWriter
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
 
-interface StatusBarModeRepositoryStore {
-    val defaultDisplay: StatusBarModePerDisplayRepository
+interface StatusBarModeRepositoryStore : PerDisplayStore<StatusBarModePerDisplayRepository>
 
-    fun forDisplay(displayId: Int): StatusBarModePerDisplayRepository
+@SysUISingleton
+class MultiDisplayStatusBarModeRepositoryStore
+@Inject
+constructor(
+    @Background backgroundApplicationScope: CoroutineScope,
+    private val factory: StatusBarModePerDisplayRepositoryFactory,
+    displayRepository: DisplayRepository,
+) :
+    StatusBarModeRepositoryStore,
+    PerDisplayStoreImpl<StatusBarModePerDisplayRepository>(
+        backgroundApplicationScope,
+        displayRepository,
+    ) {
+
+    init {
+        StatusBarConnectedDisplays.assertInNewMode()
+    }
+
+    override fun createInstanceForDisplay(displayId: Int): StatusBarModePerDisplayRepository {
+        return factory.create(displayId).also { it.start() }
+    }
+
+    override suspend fun onDisplayRemovalAction(instance: StatusBarModePerDisplayRepository) {
+        instance.stop()
+    }
+
+    override val instanceClass = StatusBarModePerDisplayRepository::class.java
 }
 
 @SysUISingleton
@@ -47,10 +80,7 @@
     StatusBarInitializer.OnStatusBarViewInitializedListener {
     override val defaultDisplay = factory.create(displayId)
 
-    override fun forDisplay(displayId: Int) =
-        // TODO(b/369337087): implement per display status bar modes.
-        //  For now just use default display instance.
-        defaultDisplay
+    override fun forDisplay(displayId: Int) = defaultDisplay
 
     override fun start() {
         defaultDisplay.start()
@@ -66,17 +96,40 @@
 }
 
 @Module
-interface StatusBarModeRepositoryModule {
-    @Binds fun bindImpl(impl: StatusBarModeRepositoryImpl): StatusBarModeRepositoryStore
-
-    @Binds
-    @IntoMap
-    @ClassKey(StatusBarModeRepositoryStore::class)
-    fun bindCoreStartable(impl: StatusBarModeRepositoryImpl): CoreStartable
-
+abstract class StatusBarModeRepositoryModule {
     @Binds
     @IntoSet
-    fun bindViewInitListener(
+    abstract fun bindViewInitListener(
         impl: StatusBarModeRepositoryImpl
     ): StatusBarInitializer.OnStatusBarViewInitializedListener
+
+    companion object {
+        @Provides
+        @SysUISingleton
+        @IntoMap
+        @ClassKey(StatusBarModeRepositoryStore::class)
+        fun storeAsCoreStartable(
+            singleDisplayLazy: Lazy<StatusBarModeRepositoryImpl>,
+            multiDisplayLazy: Lazy<MultiDisplayStatusBarModeRepositoryStore>,
+        ): CoreStartable {
+            return if (StatusBarConnectedDisplays.isEnabled) {
+                multiDisplayLazy.get()
+            } else {
+                singleDisplayLazy.get()
+            }
+        }
+
+        @Provides
+        @SysUISingleton
+        fun store(
+            singleDisplayLazy: Lazy<StatusBarModeRepositoryImpl>,
+            multiDisplayLazy: Lazy<MultiDisplayStatusBarModeRepositoryStore>,
+        ): StatusBarModeRepositoryStore {
+            return if (StatusBarConnectedDisplays.isEnabled) {
+                multiDisplayLazy.get()
+            } else {
+                singleDisplayLazy.get()
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
index 77ec65b..9a779300 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
@@ -49,12 +49,12 @@
 @Inject
 constructor(
     private val launcherApps: LauncherApps,
-    private val conversationNotificationManager: ConversationNotificationManager
+    private val conversationNotificationManager: ConversationNotificationManager,
 ) {
     fun processNotification(
         entry: NotificationEntry,
         recoveredBuilder: Notification.Builder,
-        logger: NotificationRowContentBinderLogger
+        logger: NotificationRowContentBinderLogger,
     ): Notification.MessagingStyle? {
         val messagingStyle = recoveredBuilder.style as? Notification.MessagingStyle ?: return null
         messagingStyle.conversationType =
@@ -83,7 +83,7 @@
     private val notifCollection: CommonNotifCollection,
     private val bindEventManager: BindEventManager,
     private val headsUpManager: HeadsUpManager,
-    private val statusBarStateController: StatusBarStateController
+    private val statusBarStateController: StatusBarStateController,
 ) {
 
     private var isStatusBarExpanded = false
@@ -118,7 +118,8 @@
             .flatMap { layout -> layout.allViews.asSequence() }
             .flatMap { view ->
                 (view as? ConversationLayout)?.messagingGroups?.asSequence()
-                    ?: (view as? MessagingLayout)?.messagingGroups?.asSequence() ?: emptySequence()
+                    ?: (view as? MessagingLayout)?.messagingGroups?.asSequence()
+                    ?: emptySequence()
             }
             .flatMap { messagingGroup -> messagingGroup.messageContainer.children }
             .mapNotNull { view ->
@@ -144,7 +145,7 @@
     bindEventManager: BindEventManager,
     @ShadeDisplayAware private val context: Context,
     private val notifCollection: CommonNotifCollection,
-    @Main private val mainHandler: Handler
+    @Main private val mainHandler: Handler,
 ) {
     // Need this state to be thread safe, since it's accessed from the ui thread
     // (NotificationEntryListener) and a bg thread (NotificationRowContentBinder)
@@ -175,7 +176,7 @@
                             // the notif has been moved in the shade
                             mainHandler.postDelayed(
                                 { layout.setIsImportantConversation(important, true) },
-                                IMPORTANCE_ANIMATION_DELAY.toLong()
+                                IMPORTANCE_ANIMATION_DELAY.toLong(),
                             )
                         } else {
                             layout.setIsImportantConversation(important, false)
@@ -233,8 +234,7 @@
                     state?.run {
                         if (shouldIncrementUnread(recoveredBuilder)) unreadCount + 1
                         else unreadCount
-                    }
-                        ?: 1
+                    } ?: 1
                 ConversationState(newCount, entry.sbn.notification)
             }!!
             .unreadCount
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinator.kt
index de868d4..df8e56e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinator.kt
@@ -33,29 +33,30 @@
  * they are fully attached.
  */
 @CoordinatorScope
-class RowAppearanceCoordinator @Inject internal constructor(
+class RowAppearanceCoordinator
+@Inject
+internal constructor(
     @ShadeDisplayAware context: Context,
     private var mAssistantFeedbackController: AssistantFeedbackController,
-    private var mSectionStyleProvider: SectionStyleProvider
+    private var mSectionStyleProvider: SectionStyleProvider,
 ) : Coordinator {
 
     private var entryToExpand: NotificationEntry? = null
 
     /**
-     * `true` if notifications not part of a group should by default be rendered in their
-     * expanded state. If `false`, then only the first notification will be expanded if
-     * possible.
+     * `true` if notifications not part of a group should by default be rendered in their expanded
+     * state. If `false`, then only the first notification will be expanded if possible.
      */
     private val mAlwaysExpandNonGroupedNotification =
         context.resources.getBoolean(R.bool.config_alwaysExpandNonGroupedNotifications)
 
     /**
-     * `true` if the first non-group expandable notification should be expanded automatically
-     * when possible. If `false`, then the first non-group expandable notification should not
-     * be expanded.
+     * `true` if the first non-group expandable notification should be expanded automatically when
+     * possible. If `false`, then the first non-group expandable notification should not be
+     * expanded.
      */
     private val mAutoExpandFirstNotification =
-            context.resources.getBoolean(R.bool.config_autoExpandFirstNotification)
+        context.resources.getBoolean(R.bool.config_autoExpandFirstNotification)
 
     override fun attach(pipeline: NotifPipeline) {
         pipeline.addOnBeforeRenderListListener(::onBeforeRenderList)
@@ -63,17 +64,20 @@
     }
 
     private fun onBeforeRenderList(list: List<ListEntry>) {
-        entryToExpand = list.firstOrNull()?.representativeEntry?.takeIf { entry ->
-            !mSectionStyleProvider.isMinimizedSection(entry.section!!)
-        }
+        entryToExpand =
+            list.firstOrNull()?.representativeEntry?.takeIf { entry ->
+                !mSectionStyleProvider.isMinimizedSection(entry.section!!)
+            }
     }
 
     private fun onAfterRenderEntry(entry: NotificationEntry, controller: NotifRowController) {
         // If mAlwaysExpandNonGroupedNotification is false, then only expand the
         // very first notification if it's not a child of grouped notifications and when
         // mAutoExpandFirstNotification is true.
-        controller.setSystemExpanded(mAlwaysExpandNonGroupedNotification ||
-                (mAutoExpandFirstNotification && entry == entryToExpand))
+        controller.setSystemExpanded(
+            mAlwaysExpandNonGroupedNotification ||
+                (mAutoExpandFirstNotification && entry == entryToExpand)
+        )
         // Show/hide the feedback icon
         controller.setFeedbackIcon(mAssistantFeedbackController.getFeedbackIcon(entry))
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt
index db778b80..2d1eccd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt
@@ -17,10 +17,12 @@
 package com.android.systemui.statusbar.notification.collection.coordinator
 
 import android.util.Log
+import com.android.app.tracing.traceSection
 import com.android.internal.widget.MessagingGroup
 import com.android.internal.widget.MessagingMessage
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.statusbar.NotificationLockscreenUserManager
 import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener
 import com.android.systemui.statusbar.notification.ColorUpdateLogger
@@ -29,17 +31,17 @@
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.util.Compile
-import com.android.app.tracing.traceSection
-import com.android.systemui.shade.ShadeDisplayAware
 import javax.inject.Inject
 
 /**
- * A coordinator which ensures that notifications within the new pipeline are correctly inflated
- * for the current uiMode and screen properties; additionally deferring those changes when a user
- * change is in progress until that process has completed.
+ * A coordinator which ensures that notifications within the new pipeline are correctly inflated for
+ * the current uiMode and screen properties; additionally deferring those changes when a user change
+ * is in progress until that process has completed.
  */
 @CoordinatorScope
-class ViewConfigCoordinator @Inject internal constructor(
+class ViewConfigCoordinator
+@Inject
+internal constructor(
     @ShadeDisplayAware private val mConfigurationController: ConfigurationController,
     private val mLockscreenUserManager: NotificationLockscreenUserManager,
     private val mGutsManager: NotificationGutsManager,
@@ -52,28 +54,32 @@
     private var mDispatchUiModeChangeOnUserSwitched = false
     private var mPipeline: NotifPipeline? = null
 
-    private val mKeyguardUpdateCallback = object : KeyguardUpdateMonitorCallback() {
-        override fun onUserSwitching(userId: Int) {
-            colorUpdateLogger.logTriggerEvent("VCC.mKeyguardUpdateCallback.onUserSwitching()")
-            log { "ViewConfigCoordinator.onUserSwitching(userId=$userId)" }
-            mIsSwitchingUser = true
+    private val mKeyguardUpdateCallback =
+        object : KeyguardUpdateMonitorCallback() {
+            override fun onUserSwitching(userId: Int) {
+                colorUpdateLogger.logTriggerEvent("VCC.mKeyguardUpdateCallback.onUserSwitching()")
+                log { "ViewConfigCoordinator.onUserSwitching(userId=$userId)" }
+                mIsSwitchingUser = true
+            }
+
+            override fun onUserSwitchComplete(userId: Int) {
+                colorUpdateLogger.logTriggerEvent(
+                    "VCC.mKeyguardUpdateCallback.onUserSwitchComplete()"
+                )
+                log { "ViewConfigCoordinator.onUserSwitchComplete(userId=$userId)" }
+                mIsSwitchingUser = false
+                applyChangesOnUserSwitched()
+            }
         }
 
-        override fun onUserSwitchComplete(userId: Int) {
-            colorUpdateLogger.logTriggerEvent("VCC.mKeyguardUpdateCallback.onUserSwitchComplete()")
-            log { "ViewConfigCoordinator.onUserSwitchComplete(userId=$userId)" }
-            mIsSwitchingUser = false
-            applyChangesOnUserSwitched()
+    private val mUserChangedListener =
+        object : UserChangedListener {
+            override fun onUserChanged(userId: Int) {
+                colorUpdateLogger.logTriggerEvent("VCC.mUserChangedListener.onUserChanged()")
+                log { "ViewConfigCoordinator.onUserChanged(userId=$userId)" }
+                applyChangesOnUserSwitched()
+            }
         }
-    }
-
-    private val mUserChangedListener = object : UserChangedListener {
-        override fun onUserChanged(userId: Int) {
-            colorUpdateLogger.logTriggerEvent("VCC.mUserChangedListener.onUserChanged()")
-            log { "ViewConfigCoordinator.onUserChanged(userId=$userId)" }
-            applyChangesOnUserSwitched()
-        }
-    }
 
     override fun attach(pipeline: NotifPipeline) {
         mPipeline = pipeline
@@ -87,8 +93,8 @@
         log {
             val keyguardIsSwitchingUser = mKeyguardUpdateMonitor.isSwitchingUser
             "ViewConfigCoordinator.onDensityOrFontScaleChanged()" +
-                    " isSwitchingUser=$mIsSwitchingUser" +
-                    " keyguardUpdateMonitor.isSwitchingUser=$keyguardIsSwitchingUser"
+                " isSwitchingUser=$mIsSwitchingUser" +
+                " keyguardUpdateMonitor.isSwitchingUser=$keyguardIsSwitchingUser"
         }
         MessagingMessage.dropCache()
         MessagingGroup.dropCache()
@@ -104,8 +110,8 @@
         log {
             val keyguardIsSwitchingUser = mKeyguardUpdateMonitor.isSwitchingUser
             "ViewConfigCoordinator.onUiModeChanged()" +
-                    " isSwitchingUser=$mIsSwitchingUser" +
-                    " keyguardUpdateMonitor.isSwitchingUser=$keyguardIsSwitchingUser"
+                " isSwitchingUser=$mIsSwitchingUser" +
+                " keyguardUpdateMonitor.isSwitchingUser=$keyguardIsSwitchingUser"
         }
         if (!mIsSwitchingUser) {
             updateNotificationsOnUiModeChanged()
@@ -132,13 +138,13 @@
     }
 
     private fun updateNotificationsOnUiModeChanged() {
-        colorUpdateLogger.logEvent("VCC.updateNotificationsOnUiModeChanged()",
-                "mode=" + mConfigurationController.nightModeName)
+        colorUpdateLogger.logEvent(
+            "VCC.updateNotificationsOnUiModeChanged()",
+            "mode=" + mConfigurationController.nightModeName,
+        )
         log { "ViewConfigCoordinator.updateNotificationsOnUiModeChanged()" }
         traceSection("updateNotifOnUiModeChanged") {
-            mPipeline?.allNotifs?.forEach { entry ->
-                entry.row?.onUiModeChanged()
-            }
+            mPipeline?.allNotifs?.forEach { entry -> entry.row?.onUiModeChanged() }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
index cab4c1c..3c838e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
@@ -18,6 +18,8 @@
 
 import android.content.Context
 import android.view.View
+import com.android.app.tracing.traceSection
+import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
 import com.android.systemui.statusbar.notification.collection.GroupEntry
 import com.android.systemui.statusbar.notification.collection.ListEntry
@@ -26,8 +28,6 @@
 import com.android.systemui.statusbar.notification.collection.PipelineDumper
 import com.android.systemui.statusbar.notification.collection.provider.SectionHeaderVisibilityProvider
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer
-import com.android.app.tracing.traceSection
-import com.android.systemui.shade.ShadeDisplayAware
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
@@ -36,7 +36,9 @@
  * Responsible for building and applying the "shade node spec": the list (tree) of things that
  * currently populate the notification shade.
  */
-class ShadeViewManager @AssistedInject constructor(
+class ShadeViewManager
+@AssistedInject
+constructor(
     @ShadeDisplayAware context: Context,
     @Assisted listContainer: NotificationListContainer,
     @Assisted private val stackController: NotifStackController,
@@ -45,13 +47,19 @@
     sectionHeaderVisibilityProvider: SectionHeaderVisibilityProvider,
     nodeSpecBuilderLogger: NodeSpecBuilderLogger,
     shadeViewDifferLogger: ShadeViewDifferLogger,
-    private val viewBarn: NotifViewBarn
+    private val viewBarn: NotifViewBarn,
 ) : PipelineDumpable {
     // We pass a shim view here because the listContainer may not actually have a view associated
     // with it and the differ never actually cares about the root node's view.
     private val rootController = RootNodeController(listContainer, View(context))
-    private val specBuilder = NodeSpecBuilder(mediaContainerController, featureManager,
-        sectionHeaderVisibilityProvider, viewBarn, nodeSpecBuilderLogger)
+    private val specBuilder =
+        NodeSpecBuilder(
+            mediaContainerController,
+            featureManager,
+            sectionHeaderVisibilityProvider,
+            viewBarn,
+            nodeSpecBuilderLogger,
+        )
     private val viewDiffer = ShadeViewDiffer(rootController, shadeViewDifferLogger)
 
     /** Method for attaching this manager to the pipeline. */
@@ -59,34 +67,36 @@
         renderStageManager.setViewRenderer(viewRenderer)
     }
 
-    override fun dumpPipeline(d: PipelineDumper) = with(d) {
-        dump("rootController", rootController)
-        dump("specBuilder", specBuilder)
-        dump("viewDiffer", viewDiffer)
-    }
-
-    private val viewRenderer = object : NotifViewRenderer {
-
-        override fun onRenderList(notifList: List<ListEntry>) {
-            traceSection("ShadeViewManager.onRenderList") {
-                viewDiffer.applySpec(specBuilder.buildNodeSpec(rootController, notifList))
-            }
+    override fun dumpPipeline(d: PipelineDumper) =
+        with(d) {
+            dump("rootController", rootController)
+            dump("specBuilder", specBuilder)
+            dump("viewDiffer", viewDiffer)
         }
 
-        override fun getStackController(): NotifStackController = stackController
+    private val viewRenderer =
+        object : NotifViewRenderer {
 
-        override fun getGroupController(group: GroupEntry): NotifGroupController =
-            viewBarn.requireGroupController(group.requireSummary)
+            override fun onRenderList(notifList: List<ListEntry>) {
+                traceSection("ShadeViewManager.onRenderList") {
+                    viewDiffer.applySpec(specBuilder.buildNodeSpec(rootController, notifList))
+                }
+            }
 
-        override fun getRowController(entry: NotificationEntry): NotifRowController =
-            viewBarn.requireRowController(entry)
-    }
+            override fun getStackController(): NotifStackController = stackController
+
+            override fun getGroupController(group: GroupEntry): NotifGroupController =
+                viewBarn.requireGroupController(group.requireSummary)
+
+            override fun getRowController(entry: NotificationEntry): NotifRowController =
+                viewBarn.requireRowController(entry)
+        }
 }
 
 @AssistedFactory
 interface ShadeViewManagerFactory {
     fun create(
         listContainer: NotificationListContainer,
-        stackController: NotifStackController
+        stackController: NotifStackController,
     ): ShadeViewManager
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt
index 71cddc9..52336be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProviderImpl.kt
@@ -75,7 +75,7 @@
     private val bubbles: Optional<Bubbles>,
     @ShadeDisplayAware private val context: Context,
     private val notificationManager: NotificationManager,
-    private val settingsInteractor: NotificationSettingsInteractor
+    private val settingsInteractor: NotificationSettingsInteractor,
 ) : VisualInterruptionDecisionProvider {
 
     init {
@@ -89,7 +89,7 @@
 
     private class DecisionImpl(
         override val shouldInterrupt: Boolean,
-        override val logReason: String
+        override val logReason: String,
     ) : Decision
 
     private data class LoggableDecision
@@ -107,7 +107,7 @@
                 LoggableDecision(
                     DecisionImpl(
                         shouldInterrupt = false,
-                        logReason = "${legacySuppressor.name}.$methodName"
+                        logReason = "${legacySuppressor.name}.$methodName",
                     )
                 )
 
@@ -123,7 +123,7 @@
 
     private class FullScreenIntentDecisionImpl(
         val entry: NotificationEntry,
-        private val fsiDecision: FullScreenIntentDecisionProvider.Decision
+        private val fsiDecision: FullScreenIntentDecisionProvider.Decision,
     ) : FullScreenIntentDecision, Loggable {
         var hasBeenLogged = false
 
@@ -154,7 +154,7 @@
             deviceProvisionedController,
             keyguardStateController,
             powerManager,
-            statusBarStateController
+            statusBarStateController,
         )
 
     private val legacySuppressors = mutableSetOf<NotificationInterruptSuppressor>()
@@ -197,7 +197,7 @@
                     context,
                     notificationManager,
                     logger,
-                    systemSettings
+                    systemSettings,
                 )
             )
             avalancheProvider.register()
@@ -290,7 +290,7 @@
     private fun logDecision(
         type: VisualInterruptionType,
         entry: NotificationEntry,
-        loggableDecision: LoggableDecision
+        loggableDecision: LoggableDecision,
     ) {
         if (!loggableDecision.isSpammy || logger.spew) {
             logger.logDecision(type.name, entry, loggableDecision.decision)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BigPictureIconManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BigPictureIconManager.kt
index e233def..9164145 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BigPictureIconManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BigPictureIconManager.kt
@@ -25,6 +25,7 @@
 import android.util.Log
 import android.util.Size
 import androidx.annotation.MainThread
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.internal.R
 import com.android.internal.widget.NotificationDrawableConsumer
 import com.android.internal.widget.NotificationIconManager
@@ -45,7 +46,6 @@
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.delay
-import com.android.app.tracing.coroutines.launchTraced as launch
 import kotlinx.coroutines.withContext
 
 private const val TAG = "BigPicImageLoader"
@@ -67,7 +67,7 @@
     private val statsManager: BigPictureStatsManager,
     @Application private val scope: CoroutineScope,
     @Main private val mainDispatcher: CoroutineDispatcher,
-    @Background private val bgDispatcher: CoroutineDispatcher
+    @Background private val bgDispatcher: CoroutineDispatcher,
 ) : NotificationIconManager, Dumpable {
 
     private var lastLoadingJob: Job? = null
@@ -153,7 +153,7 @@
 
     private fun checkPlaceHolderSizeForDrawable(
         displayedState: DrawableState,
-        newDrawable: Drawable
+        newDrawable: Drawable,
     ) {
         if (displayedState is PlaceHolder) {
             val (oldWidth, oldHeight) = displayedState.drawableSize
@@ -163,7 +163,7 @@
                 Log.e(
                     TAG,
                     "Mismatch in dimensions, when replacing PlaceHolder " +
-                        "$oldWidth X $oldHeight with Drawable $newWidth X $newHeight."
+                        "$oldWidth X $oldHeight with Drawable $newWidth X $newHeight.",
                 )
             }
         }
@@ -184,9 +184,8 @@
         displayedState = drawableAndState?.second ?: Empty
     }
 
-    private fun startLoadingJob(icon: Icon): Job = scope.launch {
-        statsManager.measure { loadImage(icon) }
-    }
+    private fun startLoadingJob(icon: Icon): Job =
+        scope.launch { statsManager.measure { loadImage(icon) } }
 
     private suspend fun loadImage(icon: Icon) {
         val drawableAndState = withContext(bgDispatcher) { loadImageSync(icon) }
@@ -254,9 +253,12 @@
 
     private sealed class DrawableState(open val icon: Icon?) {
         data object Initial : DrawableState(null)
+
         data object Empty : DrawableState(null)
+
         data class PlaceHolder(override val icon: Icon, val drawableSize: Size) :
             DrawableState(icon)
+
         data class FullImage(override val icon: Icon, val drawableSize: Size) : DrawableState(icon)
     }
 }
@@ -298,7 +300,7 @@
 }
 
 private val Drawable.intrinsicSize
-    get() = Size(/*width=*/ intrinsicWidth, /*height=*/ intrinsicHeight)
+    get() = Size(/* width= */ intrinsicWidth, /* height= */ intrinsicHeight)
 
 private operator fun Size.component1() = width
 
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 c9a0010..31e4d2c 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
@@ -26,7 +26,14 @@
 import com.android.systemui.statusbar.notification.collection.NotificationClassificationFlag
 import com.android.systemui.statusbar.notification.collection.render.MediaContainerController
 import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController
-import com.android.systemui.statusbar.notification.dagger.*
+import com.android.systemui.statusbar.notification.dagger.AlertingHeader
+import com.android.systemui.statusbar.notification.dagger.IncomingHeader
+import com.android.systemui.statusbar.notification.dagger.NewsHeader
+import com.android.systemui.statusbar.notification.dagger.PeopleHeader
+import com.android.systemui.statusbar.notification.dagger.PromoHeader
+import com.android.systemui.statusbar.notification.dagger.RecsHeader
+import com.android.systemui.statusbar.notification.dagger.SilentHeader
+import com.android.systemui.statusbar.notification.dagger.SocialHeader
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.ExpandableView
 import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.SectionProvider
@@ -54,7 +61,7 @@
     @NewsHeader private val newsHeaderController: SectionHeaderController,
     @SocialHeader private val socialHeaderController: SectionHeaderController,
     @RecsHeader private val recsHeaderController: SectionHeaderController,
-    @PromoHeader private val promoHeaderController: SectionHeaderController
+    @PromoHeader private val promoHeaderController: SectionHeaderController,
 ) : SectionProvider {
 
     private val configurationListener =
@@ -136,14 +143,16 @@
 
     override fun beginsSection(view: View, previous: View?): Boolean =
         view === silentHeaderView ||
-                view === mediaControlsView ||
-                view === peopleHeaderView ||
-                view === alertingHeaderView ||
-                view === incomingHeaderView ||
-                (NotificationClassificationFlag.isEnabled && (view === newsHeaderView
-                        || view === socialHeaderView || view === recsHeaderView
-                        || view === promoHeaderView)) ||
-                getBucket(view) != getBucket(previous)
+            view === mediaControlsView ||
+            view === peopleHeaderView ||
+            view === alertingHeaderView ||
+            view === incomingHeaderView ||
+            (NotificationClassificationFlag.isEnabled &&
+                (view === newsHeaderView ||
+                    view === socialHeaderView ||
+                    view === recsHeaderView ||
+                    view === promoHeaderView)) ||
+            getBucket(view) != getBucket(previous)
 
     private fun getBucket(view: View?): Int? =
         when {
@@ -165,6 +174,7 @@
         data class Many(val first: ExpandableView, val last: ExpandableView) : SectionBounds()
 
         data class One(val lone: ExpandableView) : SectionBounds()
+
         object None : SectionBounds()
 
         fun addNotif(notif: ExpandableView): SectionBounds =
@@ -183,7 +193,7 @@
 
         private fun NotificationSection.setFirstAndLastVisibleChildren(
             first: ExpandableView?,
-            last: ExpandableView?
+            last: ExpandableView?,
         ): Boolean {
             val firstChanged = setFirstVisibleChild(first)
             val lastChanged = setLastVisibleChild(last)
@@ -198,7 +208,7 @@
      */
     fun updateFirstAndLastViewsForAllSections(
         sections: Array<NotificationSection>,
-        children: List<ExpandableView>
+        children: List<ExpandableView>,
     ): Boolean {
         // Create mapping of bucket to section
         val sectionBounds =
@@ -213,7 +223,7 @@
                 .foldToSparseArray(
                     SectionBounds.None,
                     size = sections.size,
-                    operation = SectionBounds::addNotif
+                    operation = SectionBounds::addNotif,
                 )
 
         // Build a set of the old first/last Views of the sections
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index dceee22..7389086 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -297,7 +297,7 @@
             };
 
     void onStatusBarWindowStateChanged(@WindowVisibleState int state) {
-        StatusBarSimpleFragment.assertInLegacyMode();
+        StatusBarConnectedDisplays.assertInLegacyMode();
         mStatusBarWindowState = state;
         updateBubblesVisibility();
     }
@@ -1599,8 +1599,6 @@
                 .setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
         mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager);
         mRemoteInputManager.addControllerCallback(mStatusBarKeyguardViewManager);
-
-        mLightBarController.setBiometricUnlockController(mBiometricUnlockController);
         Trace.endSection();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.kt
index b5b3162..a6374a6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.kt
@@ -28,8 +28,6 @@
 
     fun setNavigationBar(navigationBar: LightBarTransitionsController)
 
-    fun setBiometricUnlockController(biometricUnlockController: BiometricUnlockController)
-
     fun onNavigationBarAppearanceChanged(
         @WindowInsetsController.Appearance appearance: Int,
         nbModeChanged: Boolean,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarControllerImpl.java
index 6ff9f4c..edc1f88 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarControllerImpl.java
@@ -74,7 +74,7 @@
     private final DumpManager mDumpManager;
     private final StatusBarModePerDisplayRepository mStatusBarModeRepository;
     private final CoroutineContext mMainContext;
-    private BiometricUnlockController mBiometricUnlockController;
+    private final BiometricUnlockController mBiometricUnlockController;
 
     private LightBarTransitionsController mNavigationBarController;
     private @Appearance int mAppearance;
@@ -138,7 +138,8 @@
             NavigationModeController navModeController,
             @Assisted StatusBarModePerDisplayRepository statusBarModeRepository,
             DumpManager dumpManager,
-            @Main CoroutineContext mainContext) {
+            @Main CoroutineContext mainContext,
+            BiometricUnlockController biometricUnlockController) {
         mCoroutineScope = coroutineScope;
         mStatusBarIconController = (SysuiDarkIconDispatcher) darkIconDispatcher;
         mBatteryController = batteryController;
@@ -146,6 +147,7 @@
         mDumpManager = dumpManager;
         mStatusBarModeRepository = statusBarModeRepository;
         mMainContext = mainContext;
+        mBiometricUnlockController = biometricUnlockController;
         String dumpableNameSuffix =
                 displayId == Display.DEFAULT_DISPLAY ? "" : String.valueOf(displayId);
         mDumpableName = getClass().getSimpleName() + dumpableNameSuffix;
@@ -176,12 +178,6 @@
         updateNavigation();
     }
 
-    @Override
-    public void setBiometricUnlockController(
-            BiometricUnlockController biometricUnlockController) {
-        mBiometricUnlockController = biometricUnlockController;
-    }
-
     private void onStatusBarAppearanceChanged(@Nullable StatusBarAppearance params) {
         if (params == null) {
             return;
@@ -388,9 +384,6 @@
     }
 
     private boolean animateChange() {
-        if (mBiometricUnlockController == null) {
-            return false;
-        }
         int unlockMode = mBiometricUnlockController.getMode();
         return unlockMode != BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
                 && unlockMode != BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt
index 94de3510..ba878ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt
@@ -103,8 +103,12 @@
         fun statusBarInitializerImpl(
             implFactory: StatusBarInitializerImpl.Factory,
             statusBarWindowControllerStore: StatusBarWindowControllerStore,
+            statusBarModeRepositoryStore: StatusBarModeRepositoryStore,
         ): StatusBarInitializerImpl {
-            return implFactory.create(statusBarWindowControllerStore.defaultDisplay)
+            return implFactory.create(
+                statusBarWindowControllerStore.defaultDisplay,
+                statusBarModeRepositoryStore.defaultDisplay,
+            )
         }
 
         @Provides
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
index e1b8a1d..91f9cce 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
@@ -212,6 +212,20 @@
     }
 
     @Test
+    fun testDimissOnLock() {
+        val container = initializeFingerprintContainer(addToView = true)
+        assertThat(container.parent).isNotNull()
+        val root = container.rootView
+
+        // Simulate sleep/lock invocation
+        container.onStartedGoingToSleep()
+        waitForIdleSync()
+
+        assertThat(container.parent).isNull()
+        assertThat(root.isAttachedToWindow).isFalse()
+    }
+
+    @Test
     fun testCredentialPasswordDismissesOnBack() {
         val container = initializeCredentialPasswordContainer(addToView = true)
         assertThat(container.parent).isNotNull()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 11b5603..7d019bf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -176,6 +176,7 @@
 import com.android.systemui.statusbar.core.StatusBarConnectedDisplays;
 import com.android.systemui.statusbar.core.StatusBarInitializerImpl;
 import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository;
+import com.android.systemui.statusbar.data.repository.StatusBarModePerDisplayRepository;
 import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
 import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider;
@@ -387,6 +388,9 @@
 
     private final BrightnessMirrorShowingInteractor mBrightnessMirrorShowingInteractor =
             mKosmos.getBrightnessMirrorShowingInteractor();
+
+    private final StatusBarModePerDisplayRepository mStatusBarModePerDisplayRepository =
+            mKosmos.getStatusBarModePerDisplayRepository();
     private ScrimController mScrimController;
 
     @Before
@@ -537,6 +541,7 @@
                 mAutoHideController,
                 new StatusBarInitializerImpl(
                         mStatusBarWindowController,
+                        mStatusBarModePerDisplayRepository,
                         mCollapsedStatusBarFragmentProvider,
                         mock(StatusBarRootFactory.class),
                         mock(HomeStatusBarComponent.Factory.class),
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
index 5eaa198..0cfdc49 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
@@ -68,6 +68,7 @@
 import com.android.systemui.shade.shadeController
 import com.android.systemui.shade.ui.viewmodel.notificationShadeWindowModel
 import com.android.systemui.statusbar.chips.ui.viewmodel.ongoingActivityChipsViewModel
+import com.android.systemui.statusbar.data.repository.fakeStatusBarModePerDisplayRepository
 import com.android.systemui.statusbar.notification.domain.interactor.seenNotificationsInteractor
 import com.android.systemui.statusbar.notification.stack.domain.interactor.headsUpNotificationInteractor
 import com.android.systemui.statusbar.notification.stack.domain.interactor.sharedNotificationContainerInteractor
@@ -119,6 +120,7 @@
     val mobileConnectionsRepository by lazy { kosmos.fakeMobileConnectionsRepository }
     val simBouncerInteractor by lazy { kosmos.simBouncerInteractor }
     val statusBarStateController by lazy { kosmos.statusBarStateController }
+    val statusBarModePerDisplayRepository by lazy { kosmos.fakeStatusBarModePerDisplayRepository }
     val interactionJankMonitor by lazy { kosmos.interactionJankMonitor }
     val fakeSceneContainerConfig by lazy { kosmos.sceneContainerConfig }
     val sceneInteractor by lazy { kosmos.sceneInteractor }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/FakeStatusBarInitializerFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/FakeStatusBarInitializerFactory.kt
index 8c218be..50a19a9 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/FakeStatusBarInitializerFactory.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/FakeStatusBarInitializerFactory.kt
@@ -16,11 +16,13 @@
 
 package com.android.systemui.statusbar.core
 
+import com.android.systemui.statusbar.data.repository.StatusBarModePerDisplayRepository
 import com.android.systemui.statusbar.window.StatusBarWindowController
 
 class FakeStatusBarInitializerFactory() : StatusBarInitializer.Factory {
 
     override fun create(
-        statusBarWindowController: StatusBarWindowController
+        statusBarWindowController: StatusBarWindowController,
+        statusBarModePerDisplayRepository: StatusBarModePerDisplayRepository,
     ): StatusBarInitializer = FakeStatusBarInitializer()
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/StatusBarInitializerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/StatusBarInitializerKosmos.kt
index 303529b..6e99027 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/StatusBarInitializerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/StatusBarInitializerKosmos.kt
@@ -19,6 +19,7 @@
 import com.android.systemui.display.data.repository.displayRepository
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.statusbar.data.repository.fakeStatusBarModeRepository
 import com.android.systemui.statusbar.window.fakeStatusBarWindowControllerStore
 
 val Kosmos.fakeStatusBarInitializer by Kosmos.Fixture { FakeStatusBarInitializer() }
@@ -37,6 +38,7 @@
             displayRepository,
             fakeStatusBarInitializerFactory,
             fakeStatusBarWindowControllerStore,
+            fakeStatusBarModeRepository,
         )
     }
 
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeStatusBarModeRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeStatusBarModeRepository.kt
index 285cebb..8712b02 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeStatusBarModeRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeStatusBarModeRepository.kt
@@ -20,8 +20,10 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.statusbar.data.model.StatusBarAppearance
 import com.android.systemui.statusbar.data.model.StatusBarMode
+import com.android.systemui.statusbar.phone.fragment.dagger.HomeStatusBarComponent
 import dagger.Binds
 import dagger.Module
+import java.io.PrintWriter
 import javax.inject.Inject
 import kotlinx.coroutines.flow.MutableStateFlow
 
@@ -53,6 +55,14 @@
     override fun clearTransient() {
         isTransientShown.value = false
     }
+
+    override fun start() {}
+
+    override fun stop() {}
+
+    override fun onStatusBarViewInitialized(component: HomeStatusBarComponent) {}
+
+    override fun dump(pw: PrintWriter, args: Array<out String>) {}
 }
 
 @Module
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryKosmos.kt
index 12db2f741..a585602 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryKosmos.kt
@@ -16,7 +16,10 @@
 
 package com.android.systemui.statusbar.data.repository
 
+import com.android.systemui.display.data.repository.displayRepository
 import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import org.mockito.kotlin.mock
 
 val Kosmos.fakeStatusBarModePerDisplayRepository by
     Kosmos.Fixture { FakeStatusBarModePerDisplayRepository() }
@@ -24,3 +27,21 @@
 val Kosmos.statusBarModeRepository: StatusBarModeRepositoryStore by
     Kosmos.Fixture { fakeStatusBarModeRepository }
 val Kosmos.fakeStatusBarModeRepository by Kosmos.Fixture { FakeStatusBarModeRepository() }
+val Kosmos.fakeStatusBarModePerDisplayRepositoryFactory by
+    Kosmos.Fixture { FakeStatusBarModePerDisplayRepositoryFactory() }
+
+val Kosmos.multiDisplayStatusBarModeRepositoryStore by
+    Kosmos.Fixture {
+        MultiDisplayStatusBarModeRepositoryStore(
+            applicationCoroutineScope,
+            fakeStatusBarModePerDisplayRepositoryFactory,
+            displayRepository,
+        )
+    }
+
+class FakeStatusBarModePerDisplayRepositoryFactory : StatusBarModePerDisplayRepositoryFactory {
+
+    override fun create(displayId: Int): StatusBarModePerDisplayRepositoryImpl {
+        return mock<StatusBarModePerDisplayRepositoryImpl>()
+    }
+}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
index 66a6890..869d854 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java
@@ -26,12 +26,10 @@
 import android.os.Bundle;
 import android.platform.test.annotations.RavenwoodTestRunnerInitializing;
 import android.platform.test.annotations.internal.InnerRunner;
-import android.platform.test.ravenwood.RavenwoodTestStats.Result;
 import android.util.Log;
 
 import androidx.test.platform.app.InstrumentationRegistry;
 
-import org.junit.AssumptionViolatedException;
 import org.junit.rules.TestRule;
 import org.junit.runner.Description;
 import org.junit.runner.Runner;
@@ -171,10 +169,11 @@
         final var notifier = new RavenwoodRunNotifier(realNotifier);
         final var description = getDescription();
 
+        RavenwoodTestStats.getInstance().attachToRunNotifier(notifier);
+
         if (mRealRunner instanceof ClassSkippingTestRunner) {
-            mRealRunner.run(notifier);
             Log.i(TAG, "onClassSkipped: description=" + description);
-            RavenwoodTestStats.getInstance().onClassSkipped(description);
+            mRealRunner.run(notifier);
             return;
         }
 
@@ -205,7 +204,6 @@
 
             if (!skipRunnerHook) {
                 try {
-                    RavenwoodTestStats.getInstance().onClassFinished(description);
                     mState.exitTestClass();
                 } catch (Throwable th) {
                     notifier.reportAfterTestFailure(th);
@@ -295,8 +293,6 @@
         // method-level annotations here.
         if (scope == Scope.Instance && order == Order.Outer) {
             if (!RavenwoodEnablementChecker.shouldEnableOnRavenwood(description, true)) {
-                RavenwoodTestStats.getInstance().onTestFinished(
-                        classDescription, description, Result.Skipped);
                 return false;
             }
         }
@@ -317,16 +313,6 @@
             // End of a test method.
             mState.exitTestMethod();
 
-            final Result result;
-            if (th == null) {
-                result = Result.Passed;
-            } else if (th instanceof AssumptionViolatedException) {
-                result = Result.Skipped;
-            } else {
-                result = Result.Failed;
-            }
-
-            RavenwoodTestStats.getInstance().onTestFinished(classDescription, description, result);
         }
 
         // If RUN_DISABLED_TESTS is set, and the method did _not_ throw, make it an error.
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
index 0f16352..28c262d 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
@@ -40,6 +40,7 @@
 import android.os.Bundle;
 import android.os.HandlerThread;
 import android.os.Looper;
+import android.os.Process_ravenwood;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.provider.DeviceConfig_host;
@@ -52,6 +53,7 @@
 import com.android.hoststubgen.hosthelper.HostTestUtils;
 import com.android.internal.os.RuntimeInit;
 import com.android.ravenwood.RavenwoodRuntimeNative;
+import com.android.ravenwood.RavenwoodRuntimeState;
 import com.android.ravenwood.common.RavenwoodCommonUtils;
 import com.android.ravenwood.common.RavenwoodRuntimeException;
 import com.android.ravenwood.common.SneakyThrow;
@@ -199,7 +201,7 @@
      */
     public static void init(RavenwoodAwareTestRunner runner) {
         if (RAVENWOOD_VERBOSE_LOGGING) {
-            Log.i(TAG, "init() called here: " + runner, new RuntimeException("STACKTRACE"));
+            Log.v(TAG, "init() called here: " + runner, new RuntimeException("STACKTRACE"));
         }
         if (sRunner == runner) {
             return;
@@ -223,7 +225,9 @@
             Thread.setDefaultUncaughtExceptionHandler(sUncaughtExceptionHandler);
         }
 
-        android.os.Process.init$ravenwood(config.mUid, config.mPid);
+        RavenwoodRuntimeState.sUid = config.mUid;
+        RavenwoodRuntimeState.sPid = config.mPid;
+        RavenwoodRuntimeState.sTargetSdkLevel = config.mTargetSdkLevel;
         sOriginalIdentityToken = Binder.clearCallingIdentity();
         reinit();
         setSystemProperties(config.mSystemProperties);
@@ -310,7 +314,7 @@
      */
     public static void reset() {
         if (RAVENWOOD_VERBOSE_LOGGING) {
-            Log.i(TAG, "reset() called here", new RuntimeException("STACKTRACE"));
+            Log.v(TAG, "reset() called here", new RuntimeException("STACKTRACE"));
         }
         if (sRunner == null) {
             throw new RavenwoodRuntimeException("Internal error: reset() already called");
@@ -350,8 +354,8 @@
         if (sOriginalIdentityToken != -1) {
             Binder.restoreCallingIdentity(sOriginalIdentityToken);
         }
-        android.os.Process.reset$ravenwood();
-
+        RavenwoodRuntimeState.reset();
+        Process_ravenwood.reset();
         DeviceConfig_host.reset();
 
         try {
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodTestStats.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodTestStats.java
index 016de8e..7870585 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodTestStats.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodTestStats.java
@@ -18,6 +18,9 @@
 import android.util.Log;
 
 import org.junit.runner.Description;
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunListener;
+import org.junit.runner.notification.RunNotifier;
 
 import java.io.File;
 import java.io.IOException;
@@ -27,7 +30,7 @@
 import java.nio.file.Paths;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
-import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.Map;
 
 /**
@@ -39,7 +42,7 @@
  */
 public class RavenwoodTestStats {
     private static final String TAG = "RavenwoodTestStats";
-    private static final String HEADER = "Module,Class,ClassDesc,Passed,Failed,Skipped";
+    private static final String HEADER = "Module,Class,OuterClass,Passed,Failed,Skipped";
 
     private static RavenwoodTestStats sInstance;
 
@@ -66,7 +69,7 @@
     private final PrintWriter mOutputWriter;
     private final String mTestModuleName;
 
-    public final Map<Description, Map<Description, Result>> mStats = new HashMap<>();
+    public final Map<String, Map<String, Result>> mStats = new LinkedHashMap<>();
 
     /** Ctor */
     public RavenwoodTestStats() {
@@ -115,75 +118,129 @@
         return cwd.getName();
     }
 
-    private void addResult(Description classDescription, Description methodDescription,
+    private void addResult(String className, String methodName,
             Result result) {
-        mStats.compute(classDescription, (classDesc, value) -> {
+        mStats.compute(className, (className_, value) -> {
             if (value == null) {
-                value = new HashMap<>();
+                value = new LinkedHashMap<>();
             }
-            value.put(methodDescription, result);
+            // If the result is already set, don't overwrite it.
+            if (!value.containsKey(methodName)) {
+                value.put(methodName, result);
+            }
             return value;
         });
     }
 
     /**
-     * Call it when a test class is skipped.
-     */
-    public void onClassSkipped(Description classDescription) {
-        addResult(classDescription, Description.EMPTY, Result.Skipped);
-        onClassFinished(classDescription);
-    }
-
-    /**
      * Call it when a test method is finished.
      */
-    public void onTestFinished(Description classDescription, Description testDescription,
-            Result result) {
-        addResult(classDescription, testDescription, result);
+    private void onTestFinished(String className, String testName, Result result) {
+        addResult(className, testName, result);
     }
 
     /**
-     * Call it when a test class is finished.
+     * Dump all the results and clear it.
      */
-    public void onClassFinished(Description classDescription) {
-        int passed = 0;
-        int skipped = 0;
-        int failed = 0;
-        var stats = mStats.get(classDescription);
-        if (stats == null) {
-            return;
-        }
-        for (var e : stats.values()) {
-            switch (e) {
-                case Passed: passed++; break;
-                case Skipped: skipped++; break;
-                case Failed: failed++; break;
+    private void dumpAllAndClear() {
+        for (var entry : mStats.entrySet()) {
+            int passed = 0;
+            int skipped = 0;
+            int failed = 0;
+            var className = entry.getKey();
+
+            for (var e : entry.getValue().values()) {
+                switch (e) {
+                    case Passed:
+                        passed++;
+                        break;
+                    case Skipped:
+                        skipped++;
+                        break;
+                    case Failed:
+                        failed++;
+                        break;
+                }
             }
+
+            mOutputWriter.printf("%s,%s,%s,%d,%d,%d\n",
+                    mTestModuleName, className, getOuterClassName(className),
+                    passed, failed, skipped);
         }
-
-        var testClass = extractTestClass(classDescription);
-
-        mOutputWriter.printf("%s,%s,%s,%d,%d,%d\n",
-                mTestModuleName, (testClass == null ? "?" : testClass.getCanonicalName()),
-                classDescription, passed, failed, skipped);
         mOutputWriter.flush();
+        mStats.clear();
     }
 
-    /**
-     * Try to extract the class from a description, which is needed because
-     * ParameterizedAndroidJunit4's description doesn't contain a class.
-     */
-    private Class<?> extractTestClass(Description desc) {
-        if (desc.getTestClass() != null) {
-            return desc.getTestClass();
+    private static String getOuterClassName(String className) {
+        // Just delete the '$', because I'm not sure if the className we get here is actaully a
+        // valid class name that does exist. (it might have a parameter name, etc?)
+        int p = className.indexOf('$');
+        if (p < 0) {
+            return className;
         }
-        // Look into the children.
-        for (var child : desc.getChildren()) {
-            var fromChild = extractTestClass(child);
-            if (fromChild != null) {
-                return fromChild;
-            }
-        }
-        return null;
+        return className.substring(0, p);
     }
+
+    public void attachToRunNotifier(RunNotifier notifier) {
+        notifier.addListener(mRunListener);
+    }
+
+    private final RunListener mRunListener = new RunListener() {
+        @Override
+        public void testSuiteStarted(Description description) {
+            Log.d(TAG, "testSuiteStarted: " + description);
+        }
+
+        @Override
+        public void testSuiteFinished(Description description) {
+            Log.d(TAG, "testSuiteFinished: " + description);
+        }
+
+        @Override
+        public void testRunStarted(Description description) {
+            Log.d(TAG, "testRunStarted: " + description);
+        }
+
+        @Override
+        public void testRunFinished(org.junit.runner.Result result) {
+            Log.d(TAG, "testRunFinished: " + result);
+
+            dumpAllAndClear();
+        }
+
+        @Override
+        public void testStarted(Description description) {
+            Log.d(TAG, "  testStarted: " + description);
+        }
+
+        @Override
+        public void testFinished(Description description) {
+            Log.d(TAG, "  testFinished: " + description);
+
+            // Send "Passed", but if there's already another result sent for this, this won't
+            // override it.
+            onTestFinished(description.getClassName(), description.getMethodName(), Result.Passed);
+        }
+
+        @Override
+        public void testFailure(Failure failure) {
+            Log.d(TAG, "    testFailure: " + failure);
+
+            var description = failure.getDescription();
+            onTestFinished(description.getClassName(), description.getMethodName(), Result.Failed);
+        }
+
+        @Override
+        public void testAssumptionFailure(Failure failure) {
+            Log.d(TAG, "    testAssumptionFailure: " + failure);
+            var description = failure.getDescription();
+            onTestFinished(description.getClassName(), description.getMethodName(), Result.Skipped);
+        }
+
+        @Override
+        public void testIgnored(Description description) {
+            Log.d(TAG, "    testIgnored: " + description);
+            onTestFinished(description.getClassName(), description.getMethodName(), Result.Skipped);
+        }
+    };
 }
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java
index 37b0abc..d8f2b70 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java
@@ -23,6 +23,7 @@
 import android.annotation.Nullable;
 import android.app.Instrumentation;
 import android.content.Context;
+import android.os.Build;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
@@ -67,7 +68,7 @@
     String mTargetPackageName;
 
     int mMinSdkLevel;
-    int mTargetSdkLevel;
+    int mTargetSdkLevel = Build.VERSION_CODES.CUR_DEVELOPMENT;
 
     boolean mProvideMainThread = false;
 
diff --git a/ravenwood/runtime-helper-src/framework/android/os/Process_ravenwood.java b/ravenwood/runtime-helper-src/framework/android/os/Process_ravenwood.java
new file mode 100644
index 0000000..3c6a4d7
--- /dev/null
+++ b/ravenwood/runtime-helper-src/framework/android/os/Process_ravenwood.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.os;
+
+import android.util.Pair;
+
+public class Process_ravenwood {
+
+    private static volatile ThreadLocal<Pair<Integer, Boolean>> sThreadPriority;
+
+    static {
+        reset();
+    }
+
+    public static void reset() {
+        // Reset the thread local variable
+        sThreadPriority = ThreadLocal.withInitial(
+                () -> Pair.create(Process.THREAD_PRIORITY_DEFAULT, true));
+    }
+
+    /**
+     * Called by {@link Process#setThreadPriority(int, int)}
+     */
+    public static void setThreadPriority(int tid, int priority) {
+        if (Process.myTid() == tid) {
+            boolean backgroundOk = sThreadPriority.get().second;
+            if (priority >= Process.THREAD_PRIORITY_BACKGROUND && !backgroundOk) {
+                throw new IllegalArgumentException(
+                        "Priority " + priority + " blocked by setCanSelfBackground()");
+            }
+            sThreadPriority.set(Pair.create(priority, backgroundOk));
+        } else {
+            throw new UnsupportedOperationException(
+                    "Cross-thread priority management not yet available in Ravenwood");
+        }
+    }
+
+    /**
+     * Called by {@link Process#setCanSelfBackground(boolean)}
+     */
+    public static void setCanSelfBackground(boolean backgroundOk) {
+        int priority = sThreadPriority.get().first;
+        sThreadPriority.set(Pair.create(priority, backgroundOk));
+    }
+
+    /**
+     * Called by {@link Process#getThreadPriority(int)}
+     */
+    public static int getThreadPriority(int tid) {
+        if (Process.myTid() == tid) {
+            return sThreadPriority.get().first;
+        } else {
+            throw new UnsupportedOperationException(
+                    "Cross-thread priority management not yet available in Ravenwood");
+        }
+    }
+}
diff --git a/ravenwood/runtime-helper-src/framework/com/android/internal/ravenwood/RavenwoodEnvironment_host.java b/ravenwood/runtime-helper-src/framework/com/android/internal/ravenwood/RavenwoodEnvironment_host.java
index e12ff24..b65668b 100644
--- a/ravenwood/runtime-helper-src/framework/com/android/internal/ravenwood/RavenwoodEnvironment_host.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/internal/ravenwood/RavenwoodEnvironment_host.java
@@ -23,14 +23,6 @@
     }
 
     /**
-     * Called from {@link RavenwoodEnvironment#ensureRavenwoodInitialized()}.
-     */
-    public static void ensureRavenwoodInitialized() {
-        // Initialization is now done by RavenwoodAwareTestRunner.
-        // Should we remove it?
-    }
-
-    /**
      * Called from {@link RavenwoodEnvironment#getRavenwoodRuntimePath()}.
      */
     public static String getRavenwoodRuntimePath(RavenwoodEnvironment env) {
diff --git a/ravenwood/runtime-helper-src/libcore-fake/android/system/Os.java b/ravenwood/runtime-helper-src/libcore-fake/android/system/Os.java
index c94ef31..0298171 100644
--- a/ravenwood/runtime-helper-src/libcore-fake/android/system/Os.java
+++ b/ravenwood/runtime-helper-src/libcore-fake/android/system/Os.java
@@ -16,6 +16,7 @@
 package android.system;
 
 import com.android.ravenwood.RavenwoodRuntimeNative;
+import com.android.ravenwood.RavenwoodRuntimeState;
 import com.android.ravenwood.common.JvmWorkaround;
 
 import java.io.FileDescriptor;
@@ -97,4 +98,16 @@
     public static void setenv(String name, String value, boolean overwrite) throws ErrnoException {
         RavenwoodRuntimeNative.setenv(name, value, overwrite);
     }
+
+    public static int getpid() {
+        return RavenwoodRuntimeState.sPid;
+    }
+
+    public static int getuid() {
+        return RavenwoodRuntimeState.sUid;
+    }
+
+    public static int gettid() {
+        return RavenwoodRuntimeNative.gettid();
+    }
 }
diff --git a/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodRuntimeNative.java b/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodRuntimeNative.java
index f13189f..7b940b4 100644
--- a/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodRuntimeNative.java
+++ b/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodRuntimeNative.java
@@ -58,6 +58,8 @@
 
     public static native void clearSystemProperties();
 
+    public static native int gettid();
+
     public static long lseek(FileDescriptor fd, long offset, int whence) throws ErrnoException {
         return nLseek(JvmWorkaround.getInstance().getFdInt(fd), offset, whence);
     }
diff --git a/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodRuntimeState.java b/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodRuntimeState.java
new file mode 100644
index 0000000..175e020
--- /dev/null
+++ b/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodRuntimeState.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.ravenwood;
+
+public class RavenwoodRuntimeState {
+    // This must match VMRuntime.SDK_VERSION_CUR_DEVELOPMENT.
+    public static final int CUR_DEVELOPMENT = 10000;
+
+    public static volatile int sUid;
+    public static volatile int sPid;
+    public static volatile int sTargetSdkLevel;
+
+    static {
+        reset();
+    }
+
+    public static void reset() {
+        sUid = -1;
+        sPid = -1;
+        sTargetSdkLevel = CUR_DEVELOPMENT;
+    }
+}
diff --git a/ravenwood/runtime-helper-src/libcore-fake/dalvik/system/VMRuntime.java b/ravenwood/runtime-helper-src/libcore-fake/dalvik/system/VMRuntime.java
index ba89f71..eaadac6 100644
--- a/ravenwood/runtime-helper-src/libcore-fake/dalvik/system/VMRuntime.java
+++ b/ravenwood/runtime-helper-src/libcore-fake/dalvik/system/VMRuntime.java
@@ -19,6 +19,7 @@
 // The original is here:
 // $ANDROID_BUILD_TOP/libcore/libart/src/main/java/dalvik/system/VMRuntime.java
 
+import com.android.ravenwood.RavenwoodRuntimeState;
 import com.android.ravenwood.common.JvmWorkaround;
 
 import java.lang.reflect.Array;
@@ -52,4 +53,8 @@
     public long addressOf(Object obj) {
         return JvmWorkaround.getInstance().addressOf(obj);
     }
+
+    public int getTargetSdkVersion() {
+        return RavenwoodRuntimeState.sTargetSdkLevel;
+    }
 }
diff --git a/ravenwood/runtime-jni/ravenwood_runtime.cpp b/ravenwood/runtime-jni/ravenwood_runtime.cpp
index 2a3c26e..5b75e98 100644
--- a/ravenwood/runtime-jni/ravenwood_runtime.cpp
+++ b/ravenwood/runtime-jni/ravenwood_runtime.cpp
@@ -17,6 +17,7 @@
 #include <fcntl.h>
 #include <string.h>
 #include <sys/stat.h>
+#include <sys/syscall.h>
 #include <unistd.h>
 #include <utils/misc.h>
 
@@ -173,6 +174,12 @@
     throwIfMinusOne(env, "setenv", setenv(name.c_str(), value.c_str(), overwrite ? 1 : 0));
 }
 
+
+static jint Linux_gettid(JNIEnv* env, jobject) {
+    // gettid(2() was added in glibc 2.30 but Android uses an older version in prebuilt.
+    return syscall(__NR_gettid);
+}
+
 static void maybeRedirectLog() {
     auto ravenwoodLogOut = getenv("RAVENWOOD_LOG_OUT");
     if (ravenwoodLogOut == NULL) {
@@ -207,6 +214,7 @@
     { "stat", "(Ljava/lang/String;)Landroid/system/StructStat;", (void*)Linux_stat },
     { "nOpen", "(Ljava/lang/String;II)I", (void*)Linux_open },
     { "setenv", "(Ljava/lang/String;Ljava/lang/String;Z)V", (void*)Linux_setenv },
+    { "gettid", "()I", (void*)Linux_gettid },
 };
 
 extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) {
diff --git a/ravenwood/scripts/run-ravenwood-tests.sh b/ravenwood/scripts/run-ravenwood-tests.sh
index 5d623e0..672c685 100755
--- a/ravenwood/scripts/run-ravenwood-tests.sh
+++ b/ravenwood/scripts/run-ravenwood-tests.sh
@@ -18,12 +18,38 @@
 # Options:
 #
 #   -s: "Smoke" test -- skip slow tests (SysUI, ICU)
+#
+#   -x PCRE: Specify exclusion filter in PCRE
+#            Example: -x '^(Cts|hoststub)' # Exclude CTS and hoststubgen tests.
+#
+#   -f PCRE: Specify inclusion filter in PCRE
+
+
+# Regex to identify slow tests, in PCRE
+SLOW_TEST_RE='^(SystemUiRavenTests|CtsIcuTestCasesRavenwood)$'
 
 smoke=0
-while getopts "s" opt; do
+include_re=""
+exclude_re=""
+smoke_exclude_re=""
+dry_run=""
+while getopts "sx:f:d" opt; do
 case "$opt" in
     s)
-        smoke=1
+        # Remove slow tests.
+        smoke_exclude_re="$SLOW_TEST_RE"
+        ;;
+    x)
+        # Take a PCRE from the arg, and use it as an exclusion filter.
+        exclude_re="$OPTARG"
+        ;;
+    f)
+        # Take a PCRE from the arg, and use it as an inclusion filter.
+        include_re="$OPTARG"
+        ;;
+    d)
+        # Dry run
+        dry_run="echo"
         ;;
     '?')
         exit 1
@@ -35,21 +61,46 @@
 all_tests=(hoststubgentest tiny-framework-dump-test hoststubgen-invoke-test ravenwood-stats-checker)
 all_tests+=( $(${0%/*}/list-ravenwood-tests.sh) )
 
-# Regex to identify slow tests, in PCRE
-slow_tests_re='^(SystemUiRavenTests|CtsIcuTestCasesRavenwood)$'
-
-if (( $smoke )) ; then
-    # Remove the slow tests.
-    all_tests=( $(
-        for t in "${all_tests[@]}"; do
-            echo $t | grep -vP "$slow_tests_re"
-        done
-    ) )
-fi
-
-run() {
-    echo "Running: $*"
-    "${@}"
+filter() {
+    local re="$1"
+    local grep_arg="$2"
+    if [[ "$re" == "" ]] ; then
+        cat # No filtering
+    else
+        grep $grep_arg -P "$re"
+    fi
 }
 
-run ${ATEST:-atest} "${all_tests[@]}"
+filter_in() {
+    filter "$1"
+}
+
+filter_out() {
+    filter "$1" -v
+}
+
+
+# Remove the slow tests.
+targets=( $(
+    for t in "${all_tests[@]}"; do
+        echo $t | filter_in "$include_re" | filter_out "$smoke_exclude_re" | filter_out "$exclude_re"
+    done
+) )
+
+# Show the target tests
+
+echo "Target tests:"
+for t in "${targets[@]}"; do
+    echo "  $t"
+done
+
+# Calculate the removed tests.
+
+diff="$(diff  <(echo "${all_tests[@]}" | tr ' ' '\n') <(echo "${targets[@]}" | tr ' ' '\n') )"
+
+if [[ "$diff" != "" ]]; then
+    echo "Excluded tests:"
+    echo "$diff"
+fi
+
+$dry_run ${ATEST:-atest} "${targets[@]}"
diff --git a/ravenwood/tests/runtime-test/Android.bp b/ravenwood/tests/runtime-test/Android.bp
index 4102920..0c0df1f 100644
--- a/ravenwood/tests/runtime-test/Android.bp
+++ b/ravenwood/tests/runtime-test/Android.bp
@@ -10,6 +10,9 @@
 android_ravenwood_test {
     name: "RavenwoodRuntimeTest",
 
+    libs: [
+        "ravenwood-helper-runtime",
+    ],
     static_libs: [
         "androidx.annotation_annotation",
         "androidx.test.ext.junit",
diff --git a/ravenwood/tests/runtime-test/test/com/android/ravenwoodtest/runtimetest/IdentityTest.java b/ravenwood/tests/runtime-test/test/com/android/ravenwoodtest/runtimetest/IdentityTest.java
new file mode 100644
index 0000000..8e04b69
--- /dev/null
+++ b/ravenwood/tests/runtime-test/test/com/android/ravenwoodtest/runtimetest/IdentityTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.ravenwoodtest.runtimetest;
+
+import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
+import static android.os.Process.FIRST_APPLICATION_UID;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.Binder;
+import android.os.Build;
+import android.os.Process;
+import android.platform.test.ravenwood.RavenwoodConfig;
+import android.system.Os;
+
+import com.android.ravenwood.RavenwoodRuntimeState;
+
+import dalvik.system.VMRuntime;
+
+import org.junit.Test;
+
+public class IdentityTest {
+
+    @RavenwoodConfig.Config
+    public static final RavenwoodConfig sConfig =
+            new RavenwoodConfig.Builder()
+                    .setTargetSdkLevel(UPSIDE_DOWN_CAKE)
+                    .setProcessApp()
+                    .build();
+
+    @Test
+    public void testUid() {
+        assertEquals(FIRST_APPLICATION_UID, RavenwoodRuntimeState.sUid);
+        assertEquals(FIRST_APPLICATION_UID, Os.getuid());
+        assertEquals(FIRST_APPLICATION_UID, Process.myUid());
+        assertEquals(FIRST_APPLICATION_UID, Binder.getCallingUid());
+    }
+
+    @Test
+    public void testPid() {
+        int pid = RavenwoodRuntimeState.sPid;
+        assertEquals(pid, Os.getpid());
+        assertEquals(pid, Process.myPid());
+        assertEquals(pid, Binder.getCallingPid());
+    }
+
+    @Test
+    public void testTargetSdkLevel() {
+        assertEquals(Build.VERSION_CODES.CUR_DEVELOPMENT, RavenwoodRuntimeState.CUR_DEVELOPMENT);
+        assertEquals(UPSIDE_DOWN_CAKE, RavenwoodRuntimeState.sTargetSdkLevel);
+        assertEquals(UPSIDE_DOWN_CAKE, VMRuntime.getRuntime().getTargetSdkVersion());
+    }
+}
diff --git a/ravenwood/tests/runtime-test/test/com/android/ravenwoodtest/runtimetest/OsTest.java b/ravenwood/tests/runtime-test/test/com/android/ravenwoodtest/runtimetest/OsTest.java
index c2230c7..c55506a 100644
--- a/ravenwood/tests/runtime-test/test/com/android/ravenwoodtest/runtimetest/OsTest.java
+++ b/ravenwood/tests/runtime-test/test/com/android/ravenwoodtest/runtimetest/OsTest.java
@@ -24,6 +24,8 @@
 import static android.system.OsConstants.S_ISSOCK;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
 
 import static java.nio.file.LinkOption.NOFOLLOW_LINKS;
 
@@ -51,10 +53,12 @@
 import java.nio.file.attribute.PosixFilePermission;
 import java.util.HashSet;
 import java.util.Set;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
 @RunWith(AndroidJUnit4.class)
 public class OsTest {
+
     public interface ConsumerWithThrow<T> {
         void accept(T var1) throws Exception;
     }
@@ -165,6 +169,35 @@
         });
     }
 
+    private static class TestThread extends Thread {
+
+        final CountDownLatch mLatch = new CountDownLatch(1);
+        int mTid;
+
+        TestThread() {
+            setDaemon(true);
+        }
+
+        @Override
+        public void run() {
+            mTid = Os.gettid();
+            mLatch.countDown();
+        }
+    }
+
+    @Test
+    public void testGetTid() throws InterruptedException {
+        var t1 = new TestThread();
+        var t2 = new TestThread();
+        t1.start();
+        t2.start();
+        // Wait for thread execution
+        assertTrue(t1.mLatch.await(1, TimeUnit.SECONDS));
+        assertTrue(t2.mLatch.await(1, TimeUnit.SECONDS));
+        // Make sure the tid is unique per-thread
+        assertNotEquals(t1.mTid, t2.mTid);
+    }
+
     // Verify StructStat values from libcore against native JVM PosixFileAttributes
     private static void assertAttributesEqual(PosixFileAttributes attr, StructStat stat) {
         assertEquals(attr.lastModifiedTime(), convertTimespecToFileTime(stat.st_mtim));
diff --git a/ravenwood/tests/runtime-test/test/com/android/ravenwoodtest/runtimetest/ProcessTest.java b/ravenwood/tests/runtime-test/test/com/android/ravenwoodtest/runtimetest/ProcessTest.java
new file mode 100644
index 0000000..d25b5c1
--- /dev/null
+++ b/ravenwood/tests/runtime-test/test/com/android/ravenwoodtest/runtimetest/ProcessTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.ravenwoodtest.runtimetest;
+
+import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
+import static android.os.Process.THREAD_PRIORITY_DEFAULT;
+import static android.os.Process.THREAD_PRIORITY_FOREGROUND;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import android.os.Process;
+import android.system.Os;
+
+import org.junit.Test;
+
+public class ProcessTest {
+
+    @Test
+    public void testGetUidPidTid() {
+        assertEquals(Os.getuid(), Process.myUid());
+        assertEquals(Os.getpid(), Process.myPid());
+        assertEquals(Os.gettid(), Process.myTid());
+    }
+
+    @Test
+    public void testThreadPriority() {
+        assertThrows(UnsupportedOperationException.class,
+                () -> Process.getThreadPriority(Process.myTid() + 1));
+        assertThrows(UnsupportedOperationException.class,
+                () -> Process.setThreadPriority(Process.myTid() + 1, THREAD_PRIORITY_DEFAULT));
+        assertEquals(THREAD_PRIORITY_DEFAULT, Process.getThreadPriority(Process.myTid()));
+        Process.setThreadPriority(THREAD_PRIORITY_FOREGROUND);
+        assertEquals(THREAD_PRIORITY_FOREGROUND, Process.getThreadPriority(Process.myTid()));
+        Process.setCanSelfBackground(false);
+        Process.setThreadPriority(THREAD_PRIORITY_DEFAULT);
+        assertEquals(THREAD_PRIORITY_DEFAULT, Process.getThreadPriority(Process.myTid()));
+        assertThrows(IllegalArgumentException.class,
+                () -> Process.setThreadPriority(THREAD_PRIORITY_BACKGROUND));
+    }
+}
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 68ff972..edecb2b 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -898,18 +898,30 @@
             for (int j = 0; j < widgetCount; j++) {
                 Widget widget = provider.widgets.get(j);
                 if (targetWidget != null && targetWidget != widget) continue;
+                // Identify the user in the host process since the intent will be invoked by
+                // the host app.
+                final Host host = widget.host;
+                final UserHandle hostUser;
+                if (host != null && host.id != null) {
+                    hostUser = UserHandle.getUserHandleForUid(host.id.uid);
+                } else {
+                    // Fallback to the parent profile if the host is null.
+                    Slog.w(TAG, "Host is null when masking widget: " + widget.appWidgetId);
+                    hostUser = mUserManager.getProfileParent(appUserId).getUserHandle();
+                }
                 if (provider.maskedByStoppedPackage) {
                     Intent intent = createUpdateIntentLocked(provider,
                             new int[] { widget.appWidgetId });
                     views.setOnClickPendingIntent(android.R.id.background,
-                            PendingIntent.getBroadcast(mContext, widget.appWidgetId,
+                            PendingIntent.getBroadcastAsUser(mContext, widget.appWidgetId,
                                     intent, PendingIntent.FLAG_UPDATE_CURRENT
-                                            | PendingIntent.FLAG_IMMUTABLE));
+                                            | PendingIntent.FLAG_IMMUTABLE, hostUser));
                 } else if (onClickIntent != null) {
                     views.setOnClickPendingIntent(android.R.id.background,
-                            PendingIntent.getActivity(mContext, widget.appWidgetId, onClickIntent,
-                                    PendingIntent.FLAG_UPDATE_CURRENT
-                                       | PendingIntent.FLAG_IMMUTABLE));
+                            PendingIntent.getActivityAsUser(mContext, widget.appWidgetId,
+                            onClickIntent, PendingIntent.FLAG_UPDATE_CURRENT
+                                    | PendingIntent.FLAG_IMMUTABLE, null /* options */,
+                            hostUser));
                 }
                 if (widget.replaceWithMaskedViewsLocked(views)) {
                     scheduleNotifyUpdateAppWidgetLocked(widget, widget.getEffectiveViewsLocked());
diff --git a/services/companion/java/com/android/server/companion/virtual/CameraAccessController.java b/services/companion/java/com/android/server/companion/virtual/CameraAccessController.java
index ef39846..8a4b1fa 100644
--- a/services/companion/java/com/android/server/companion/virtual/CameraAccessController.java
+++ b/services/companion/java/com/android/server/companion/virtual/CameraAccessController.java
@@ -59,14 +59,14 @@
     private int mObserverCount = 0;
 
     @GuardedBy("mLock")
-    private ArrayMap<String, InjectionSessionData> mPackageToSessionData = new ArrayMap<>();
+    private final ArrayMap<String, InjectionSessionData> mPackageToSessionData = new ArrayMap<>();
 
     /**
      * Mapping from camera ID to open camera app associations. Key is the camera id, value is the
      * information of the app's uid and package name.
      */
     @GuardedBy("mLock")
-    private ArrayMap<String, OpenCameraInfo> mAppsToBlockOnVirtualDevice = new ArrayMap<>();
+    private final ArrayMap<String, OpenCameraInfo> mAppsToBlockOnVirtualDevice = new ArrayMap<>();
 
     static class InjectionSessionData {
         public int appUid;
@@ -179,6 +179,15 @@
                 Slog.w(TAG, "Unexpected close with observers remaining: " + mObserverCount);
             }
         }
+        // Clean up camera injection sessions (if any).
+        synchronized (mLock) {
+            for (InjectionSessionData sessionData : mPackageToSessionData.values()) {
+                for (CameraInjectionSession session : sessionData.cameraIdToSession.values()) {
+                    session.close();
+                }
+            }
+            mPackageToSessionData.clear();
+        }
         mCameraManager.unregisterAvailabilityCallback(this);
     }
 
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
index f87e3c3..604aaa7 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
@@ -17,6 +17,7 @@
 package com.android.server.companion.virtual;
 
 import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
+import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_DEFAULT_DEVICE_CAMERA_ACCESS;
 import static android.media.AudioManager.AUDIO_SESSION_ID_GENERATE;
 
 import static com.android.server.wm.ActivityInterceptorCallback.VIRTUAL_DEVICE_SERVICE_ORDERED_ID;
@@ -27,6 +28,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SuppressLint;
 import android.app.ActivityOptions;
+import android.app.compat.CompatChanges;
 import android.companion.AssociationInfo;
 import android.companion.AssociationRequest;
 import android.companion.CompanionDeviceManager;
@@ -41,11 +43,14 @@
 import android.companion.virtual.flags.Flags;
 import android.companion.virtual.sensor.VirtualSensor;
 import android.companion.virtualnative.IVirtualDeviceManagerNative;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
 import android.content.AttributionSource;
 import android.content.Context;
 import android.content.Intent;
 import android.hardware.display.DisplayManagerInternal;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.LocaleList;
@@ -88,7 +93,6 @@
 import java.util.function.Consumer;
 import java.util.stream.Collectors;
 
-
 @SuppressLint("LongLogTag")
 public class VirtualDeviceManagerService extends SystemService {
 
@@ -101,6 +105,11 @@
             AssociationRequest.DEVICE_PROFILE_APP_STREAMING,
             AssociationRequest.DEVICE_PROFILE_NEARBY_DEVICE_STREAMING);
 
+    /** Enable default device camera access for apps running on virtual devices. */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
+    public static final long ENABLE_DEFAULT_DEVICE_CAMERA_ACCESS = 371173368L;
+
     /**
      * A virtual device association id corresponding to no CDM association.
      */
@@ -110,7 +119,7 @@
     private final VirtualDeviceManagerImpl mImpl;
     private final VirtualDeviceManagerNativeImpl mNativeImpl;
     private final VirtualDeviceManagerInternal mLocalService;
-    private VirtualDeviceLog mVirtualDeviceLog = new VirtualDeviceLog(getContext());
+    private final VirtualDeviceLog mVirtualDeviceLog = new VirtualDeviceLog(getContext());
     private final Handler mHandler = new Handler(Looper.getMainLooper());
     private final PendingTrampolineMap mPendingTrampolines = new PendingTrampolineMap(mHandler);
 
@@ -236,7 +245,7 @@
         }
     }
 
-    void onCameraAccessBlocked(int appUid) {
+    private void onCameraAccessBlocked(int appUid) {
         ArrayList<VirtualDeviceImpl> virtualDevicesSnapshot = getVirtualDevicesSnapshot();
         for (int i = 0; i < virtualDevicesSnapshot.size(); i++) {
             VirtualDeviceImpl virtualDevice = virtualDevicesSnapshot.get(i);
@@ -248,8 +257,13 @@
         }
     }
 
-    CameraAccessController getCameraAccessController(UserHandle userHandle) {
-        if (Flags.streamCamera()) {
+    private CameraAccessController getCameraAccessController(UserHandle userHandle,
+            VirtualDeviceParams params, String callingPackage) {
+        if (CompatChanges.isChangeEnabled(ENABLE_DEFAULT_DEVICE_CAMERA_ACCESS, callingPackage,
+                userHandle)
+                && android.companion.virtualdevice.flags.Flags.defaultDeviceCameraAccessPolicy()
+                && (params.getDevicePolicy(POLICY_TYPE_DEFAULT_DEVICE_CAMERA_ACCESS)
+                    == DEVICE_POLICY_DEFAULT)) {
             return null;
         }
         int userId = userHandle.getIdentifier();
@@ -496,7 +510,8 @@
 
             final UserHandle userHandle = getCallingUserHandle();
             final CameraAccessController cameraAccessController =
-                    getCameraAccessController(userHandle);
+                    getCameraAccessController(userHandle, params,
+                            attributionSource.getPackageName());
             final int deviceId = sNextUniqueIndex.getAndIncrement();
             final Consumer<ArraySet<Integer>> runningAppsChangedCallback =
                     runningUids -> notifyRunningAppsChanged(deviceId, runningUids);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 1c3569d..3e7bcb8 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5155,6 +5155,11 @@
         mContext.registerReceiver(new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
+                final String action = intent.getAction();
+                if (action == null) {
+                    return;
+                }
+
                 String[] pkgs = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
                 if (pkgs != null) {
                     for (String pkg : pkgs) {
diff --git a/services/core/java/com/android/server/appbinding/AppBindingService.java b/services/core/java/com/android/server/appbinding/AppBindingService.java
index 5db6dc7..6ccb3ee 100644
--- a/services/core/java/com/android/server/appbinding/AppBindingService.java
+++ b/services/core/java/com/android/server/appbinding/AppBindingService.java
@@ -235,6 +235,9 @@
             }
 
             final String action = intent.getAction();
+            if (action == null) {
+                return;
+            }
 
             if (Intent.ACTION_USER_REMOVED.equals(action)) {
                 onUserRemoved(userId);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index b696c54..1b527da 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -273,13 +273,8 @@
     private class DelayedStandbyOnActiveSourceLostRunnable implements Runnable {
         @Override
         public void run() {
-            if (mService.getPowerManagerInternal().wasDeviceIdleFor(
-                    STANDBY_AFTER_ACTIVE_SOURCE_LOST_DELAY_MS)) {
+            if (!isActiveSource()) {
                 mService.standby();
-            } else {
-                mService.setAndBroadcastActiveSource(mService.getPhysicalAddress(),
-                        getDeviceInfo().getDeviceType(), Constants.ADDR_TV,
-                        "DelayedActiveSourceLostStandbyRunnable");
             }
         }
     }
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 0104373..d8483f7 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -4969,7 +4969,7 @@
                     final var userData = getUserData(userId);
                     if (Flags.refactorInsetsController()) {
                         setImeVisibilityOnFocusedWindowClient(false, userData,
-                                null /* TODO(b329229469) check statsToken */);
+                                null /* TODO(b/353463205) check statsToken */);
                     } else {
 
                         hideCurrentInputLocked(userData.mImeBindingState.mFocusedWindow,
diff --git a/services/core/java/com/android/server/integrity/parser/RuleMetadataParser.java b/services/core/java/com/android/server/integrity/parser/RuleMetadataParser.java
deleted file mode 100644
index e831e40..0000000
--- a/services/core/java/com/android/server/integrity/parser/RuleMetadataParser.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2019 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.integrity.parser;
-
-import android.annotation.Nullable;
-import android.util.Xml;
-
-import com.android.modules.utils.TypedXmlPullParser;
-import com.android.server.integrity.model.RuleMetadata;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-/** Helper class for parsing rule metadata. */
-public class RuleMetadataParser {
-
-    public static final String RULE_PROVIDER_TAG = "P";
-    public static final String VERSION_TAG = "V";
-
-    /** Parse the rule metadata from an input stream. */
-    @Nullable
-    public static RuleMetadata parse(InputStream inputStream)
-            throws XmlPullParserException, IOException {
-
-        String ruleProvider = "";
-        String version = "";
-
-        TypedXmlPullParser xmlPullParser = Xml.resolvePullParser(inputStream);
-
-        int eventType;
-        while ((eventType = xmlPullParser.next()) != XmlPullParser.END_DOCUMENT) {
-            if (eventType == XmlPullParser.START_TAG) {
-                String tag = xmlPullParser.getName();
-                switch (tag) {
-                    case RULE_PROVIDER_TAG:
-                        ruleProvider = xmlPullParser.nextText();
-                        break;
-                    case VERSION_TAG:
-                        version = xmlPullParser.nextText();
-                        break;
-                    default:
-                        throw new IllegalStateException("Unknown tag in metadata: " + tag);
-                }
-            }
-        }
-
-        return new RuleMetadata(ruleProvider, version);
-    }
-}
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java
deleted file mode 100644
index 8ba5870..0000000
--- a/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java
+++ /dev/null
@@ -1,324 +0,0 @@
-/*
- * Copyright (C) 2019 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.integrity.serializer;
-
-import static com.android.server.integrity.model.ComponentBitSize.ATOMIC_FORMULA_START;
-import static com.android.server.integrity.model.ComponentBitSize.COMPOUND_FORMULA_END;
-import static com.android.server.integrity.model.ComponentBitSize.COMPOUND_FORMULA_START;
-import static com.android.server.integrity.model.ComponentBitSize.CONNECTOR_BITS;
-import static com.android.server.integrity.model.ComponentBitSize.DEFAULT_FORMAT_VERSION;
-import static com.android.server.integrity.model.ComponentBitSize.EFFECT_BITS;
-import static com.android.server.integrity.model.ComponentBitSize.FORMAT_VERSION_BITS;
-import static com.android.server.integrity.model.ComponentBitSize.INSTALLER_ALLOWED_BY_MANIFEST_START;
-import static com.android.server.integrity.model.ComponentBitSize.KEY_BITS;
-import static com.android.server.integrity.model.ComponentBitSize.OPERATOR_BITS;
-import static com.android.server.integrity.model.ComponentBitSize.SEPARATOR_BITS;
-import static com.android.server.integrity.model.ComponentBitSize.VALUE_SIZE_BITS;
-import static com.android.server.integrity.model.IndexingFileConstants.END_INDEXING_KEY;
-import static com.android.server.integrity.model.IndexingFileConstants.INDEXING_BLOCK_SIZE;
-import static com.android.server.integrity.model.IndexingFileConstants.START_INDEXING_KEY;
-import static com.android.server.integrity.serializer.RuleIndexingDetails.APP_CERTIFICATE_INDEXED;
-import static com.android.server.integrity.serializer.RuleIndexingDetails.NOT_INDEXED;
-import static com.android.server.integrity.serializer.RuleIndexingDetails.PACKAGE_NAME_INDEXED;
-
-import android.content.integrity.AtomicFormula;
-import android.content.integrity.CompoundFormula;
-import android.content.integrity.InstallerAllowedByManifestFormula;
-import android.content.integrity.IntegrityFormula;
-import android.content.integrity.IntegrityUtils;
-import android.content.integrity.Rule;
-
-import com.android.internal.util.Preconditions;
-import com.android.server.integrity.model.BitOutputStream;
-import com.android.server.integrity.model.ByteTrackedOutputStream;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.nio.charset.StandardCharsets;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.stream.Collectors;
-
-/** A helper class to serialize rules from the {@link Rule} model to Binary representation. */
-public class RuleBinarySerializer implements RuleSerializer {
-    static final int TOTAL_RULE_SIZE_LIMIT = 200000;
-    static final int INDEXED_RULE_SIZE_LIMIT = 100000;
-    static final int NONINDEXED_RULE_SIZE_LIMIT = 1000;
-
-    // Get the byte representation for a list of rules.
-    @Override
-    public byte[] serialize(List<Rule> rules, Optional<Integer> formatVersion)
-            throws RuleSerializeException {
-        try {
-            ByteArrayOutputStream rulesOutputStream = new ByteArrayOutputStream();
-            serialize(rules, formatVersion, rulesOutputStream, new ByteArrayOutputStream());
-            return rulesOutputStream.toByteArray();
-        } catch (Exception e) {
-            throw new RuleSerializeException(e.getMessage(), e);
-        }
-    }
-
-    // Get the byte representation for a list of rules, and write them to an output stream.
-    @Override
-    public void serialize(
-            List<Rule> rules,
-            Optional<Integer> formatVersion,
-            OutputStream rulesFileOutputStream,
-            OutputStream indexingFileOutputStream)
-            throws RuleSerializeException {
-        try {
-            if (rules == null) {
-                throw new IllegalArgumentException("Null rules cannot be serialized.");
-            }
-
-            if (rules.size() > TOTAL_RULE_SIZE_LIMIT) {
-                throw new IllegalArgumentException("Too many rules provided: " + rules.size());
-            }
-
-            // Determine the indexing groups and the order of the rules within each indexed group.
-            Map<Integer, Map<String, List<Rule>>> indexedRules =
-                    RuleIndexingDetailsIdentifier.splitRulesIntoIndexBuckets(rules);
-
-            // Validate the rule blocks are not larger than expected limits.
-            verifySize(indexedRules.get(PACKAGE_NAME_INDEXED), INDEXED_RULE_SIZE_LIMIT);
-            verifySize(indexedRules.get(APP_CERTIFICATE_INDEXED), INDEXED_RULE_SIZE_LIMIT);
-            verifySize(indexedRules.get(NOT_INDEXED), NONINDEXED_RULE_SIZE_LIMIT);
-
-            // Serialize the rules.
-            ByteTrackedOutputStream ruleFileByteTrackedOutputStream =
-                    new ByteTrackedOutputStream(rulesFileOutputStream);
-            serializeRuleFileMetadata(formatVersion, ruleFileByteTrackedOutputStream);
-            LinkedHashMap<String, Integer> packageNameIndexes =
-                    serializeRuleList(
-                            indexedRules.get(PACKAGE_NAME_INDEXED),
-                            ruleFileByteTrackedOutputStream);
-            LinkedHashMap<String, Integer> appCertificateIndexes =
-                    serializeRuleList(
-                            indexedRules.get(APP_CERTIFICATE_INDEXED),
-                            ruleFileByteTrackedOutputStream);
-            LinkedHashMap<String, Integer> unindexedRulesIndexes =
-                    serializeRuleList(
-                            indexedRules.get(NOT_INDEXED), ruleFileByteTrackedOutputStream);
-
-            // Serialize their indexes.
-            BitOutputStream indexingBitOutputStream = new BitOutputStream(indexingFileOutputStream);
-            serializeIndexGroup(packageNameIndexes, indexingBitOutputStream, /* isIndexed= */ true);
-            serializeIndexGroup(
-                    appCertificateIndexes, indexingBitOutputStream, /* isIndexed= */ true);
-            serializeIndexGroup(
-                    unindexedRulesIndexes, indexingBitOutputStream, /* isIndexed= */ false);
-            indexingBitOutputStream.flush();
-        } catch (Exception e) {
-            throw new RuleSerializeException(e.getMessage(), e);
-        }
-    }
-
-    private void verifySize(Map<String, List<Rule>> ruleListMap, int ruleSizeLimit) {
-        int totalRuleCount =
-                ruleListMap.values().stream()
-                        .map(list -> list.size())
-                        .collect(Collectors.summingInt(Integer::intValue));
-        if (totalRuleCount > ruleSizeLimit) {
-            throw new IllegalArgumentException(
-                    "Too many rules provided in the indexing group. Provided "
-                            + totalRuleCount
-                            + " limit "
-                            + ruleSizeLimit);
-        }
-    }
-
-    private void serializeRuleFileMetadata(
-            Optional<Integer> formatVersion, ByteTrackedOutputStream outputStream)
-            throws IOException {
-        int formatVersionValue = formatVersion.orElse(DEFAULT_FORMAT_VERSION);
-
-        BitOutputStream bitOutputStream = new BitOutputStream(outputStream);
-        bitOutputStream.setNext(FORMAT_VERSION_BITS, formatVersionValue);
-        bitOutputStream.flush();
-    }
-
-    private LinkedHashMap<String, Integer> serializeRuleList(
-            Map<String, List<Rule>> rulesMap, ByteTrackedOutputStream outputStream)
-            throws IOException {
-        Preconditions.checkArgument(
-                rulesMap != null, "serializeRuleList should never be called with null rule list.");
-
-        BitOutputStream bitOutputStream = new BitOutputStream(outputStream);
-        LinkedHashMap<String, Integer> indexMapping = new LinkedHashMap();
-        indexMapping.put(START_INDEXING_KEY, outputStream.getWrittenBytesCount());
-
-        List<String> sortedKeys = rulesMap.keySet().stream().sorted().collect(Collectors.toList());
-        int indexTracker = 0;
-        for (String key : sortedKeys) {
-            if (indexTracker >= INDEXING_BLOCK_SIZE) {
-                indexMapping.put(key, outputStream.getWrittenBytesCount());
-                indexTracker = 0;
-            }
-
-            for (Rule rule : rulesMap.get(key)) {
-                serializeRule(rule, bitOutputStream);
-                bitOutputStream.flush();
-                indexTracker++;
-            }
-        }
-        indexMapping.put(END_INDEXING_KEY, outputStream.getWrittenBytesCount());
-
-        return indexMapping;
-    }
-
-    private void serializeRule(Rule rule, BitOutputStream bitOutputStream) throws IOException {
-        if (rule == null) {
-            throw new IllegalArgumentException("Null rule can not be serialized");
-        }
-
-        // Start with a '1' bit to mark the start of a rule.
-        bitOutputStream.setNext();
-
-        serializeFormula(rule.getFormula(), bitOutputStream);
-        bitOutputStream.setNext(EFFECT_BITS, rule.getEffect());
-
-        // End with a '1' bit to mark the end of a rule.
-        bitOutputStream.setNext();
-    }
-
-    private void serializeFormula(IntegrityFormula formula, BitOutputStream bitOutputStream)
-            throws IOException {
-        if (formula instanceof AtomicFormula) {
-            serializeAtomicFormula((AtomicFormula) formula, bitOutputStream);
-        } else if (formula instanceof CompoundFormula) {
-            serializeCompoundFormula((CompoundFormula) formula, bitOutputStream);
-        } else if (formula instanceof InstallerAllowedByManifestFormula) {
-            bitOutputStream.setNext(SEPARATOR_BITS, INSTALLER_ALLOWED_BY_MANIFEST_START);
-        } else {
-            throw new IllegalArgumentException(
-                    String.format("Invalid formula type: %s", formula.getClass()));
-        }
-    }
-
-    private void serializeCompoundFormula(
-            CompoundFormula compoundFormula, BitOutputStream bitOutputStream) throws IOException {
-        if (compoundFormula == null) {
-            throw new IllegalArgumentException("Null compound formula can not be serialized");
-        }
-
-        bitOutputStream.setNext(SEPARATOR_BITS, COMPOUND_FORMULA_START);
-        bitOutputStream.setNext(CONNECTOR_BITS, compoundFormula.getConnector());
-        for (IntegrityFormula formula : compoundFormula.getFormulas()) {
-            serializeFormula(formula, bitOutputStream);
-        }
-        bitOutputStream.setNext(SEPARATOR_BITS, COMPOUND_FORMULA_END);
-    }
-
-    private void serializeAtomicFormula(
-            AtomicFormula atomicFormula, BitOutputStream bitOutputStream) throws IOException {
-        if (atomicFormula == null) {
-            throw new IllegalArgumentException("Null atomic formula can not be serialized");
-        }
-
-        bitOutputStream.setNext(SEPARATOR_BITS, ATOMIC_FORMULA_START);
-        bitOutputStream.setNext(KEY_BITS, atomicFormula.getKey());
-        if (atomicFormula.getTag() == AtomicFormula.STRING_ATOMIC_FORMULA_TAG) {
-            AtomicFormula.StringAtomicFormula stringAtomicFormula =
-                    (AtomicFormula.StringAtomicFormula) atomicFormula;
-            bitOutputStream.setNext(OPERATOR_BITS, AtomicFormula.EQ);
-            serializeStringValue(
-                    stringAtomicFormula.getValue(),
-                    stringAtomicFormula.getIsHashedValue(),
-                    bitOutputStream);
-        } else if (atomicFormula.getTag() == AtomicFormula.LONG_ATOMIC_FORMULA_TAG) {
-            AtomicFormula.LongAtomicFormula longAtomicFormula =
-                    (AtomicFormula.LongAtomicFormula) atomicFormula;
-            bitOutputStream.setNext(OPERATOR_BITS, longAtomicFormula.getOperator());
-            // TODO(b/147880712): Temporary hack until we support long values in bitOutputStream
-            long value = longAtomicFormula.getValue();
-            serializeIntValue((int) (value >>> 32), bitOutputStream);
-            serializeIntValue((int) value, bitOutputStream);
-        } else if (atomicFormula.getTag() == AtomicFormula.BOOLEAN_ATOMIC_FORMULA_TAG) {
-            AtomicFormula.BooleanAtomicFormula booleanAtomicFormula =
-                    (AtomicFormula.BooleanAtomicFormula) atomicFormula;
-            bitOutputStream.setNext(OPERATOR_BITS, AtomicFormula.EQ);
-            serializeBooleanValue(booleanAtomicFormula.getValue(), bitOutputStream);
-        } else {
-            throw new IllegalArgumentException(
-                    String.format("Invalid atomic formula type: %s", atomicFormula.getClass()));
-        }
-    }
-
-    private void serializeIndexGroup(
-            LinkedHashMap<String, Integer> indexes,
-            BitOutputStream bitOutputStream,
-            boolean isIndexed)
-            throws IOException {
-        // Output the starting location of this indexing group.
-        serializeStringValue(START_INDEXING_KEY, /* isHashedValue= */ false, bitOutputStream);
-        serializeIntValue(indexes.get(START_INDEXING_KEY), bitOutputStream);
-
-        // If the group is indexed, output the locations of the indexes.
-        if (isIndexed) {
-            for (Map.Entry<String, Integer> entry : indexes.entrySet()) {
-                if (!entry.getKey().equals(START_INDEXING_KEY)
-                        && !entry.getKey().equals(END_INDEXING_KEY)) {
-                    serializeStringValue(
-                            entry.getKey(), /* isHashedValue= */ false, bitOutputStream);
-                    serializeIntValue(entry.getValue(), bitOutputStream);
-                }
-            }
-        }
-
-        // Output the end location of this indexing group.
-        serializeStringValue(END_INDEXING_KEY, /*isHashedValue= */ false, bitOutputStream);
-        serializeIntValue(indexes.get(END_INDEXING_KEY), bitOutputStream);
-    }
-
-    private void serializeStringValue(
-            String value, boolean isHashedValue, BitOutputStream bitOutputStream)
-            throws IOException {
-        if (value == null) {
-            throw new IllegalArgumentException("String value can not be null.");
-        }
-        byte[] valueBytes = getBytesForString(value, isHashedValue);
-
-        bitOutputStream.setNext(isHashedValue);
-        bitOutputStream.setNext(VALUE_SIZE_BITS, valueBytes.length);
-        for (byte valueByte : valueBytes) {
-            bitOutputStream.setNext(/* numOfBits= */ 8, valueByte);
-        }
-    }
-
-    private void serializeIntValue(int value, BitOutputStream bitOutputStream) throws IOException {
-        bitOutputStream.setNext(/* numOfBits= */ 32, value);
-    }
-
-    private void serializeBooleanValue(boolean value, BitOutputStream bitOutputStream)
-            throws IOException {
-        bitOutputStream.setNext(value);
-    }
-
-    // Get the byte array for a value.
-    // If the value is not hashed, use its byte array form directly.
-    // If the value is hashed, get the raw form decoding of the value. All hashed values are
-    // hex-encoded. Serialized values are in raw form.
-    private static byte[] getBytesForString(String value, boolean isHashedValue) {
-        if (!isHashedValue) {
-            return value.getBytes(StandardCharsets.UTF_8);
-        }
-        return IntegrityUtils.getBytesFromHexDigest(value);
-    }
-}
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetails.java b/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetails.java
deleted file mode 100644
index 2cbd4ede..0000000
--- a/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetails.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2019 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.integrity.serializer;
-
-import android.annotation.IntDef;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/** Holds the indexing type and indexing key of a given formula. */
-class RuleIndexingDetails {
-
-    static final int NOT_INDEXED = 0;
-    static final int PACKAGE_NAME_INDEXED = 1;
-    static final int APP_CERTIFICATE_INDEXED = 2;
-
-    static final String DEFAULT_RULE_KEY = "N/A";
-
-    /** Represents which indexed file the rule should be located. */
-    @IntDef(
-            value = {
-                    NOT_INDEXED,
-                    PACKAGE_NAME_INDEXED,
-                    APP_CERTIFICATE_INDEXED
-            })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface IndexType {
-    }
-
-    private @IndexType int mIndexType;
-    private String mRuleKey;
-
-    /** Constructor without a ruleKey for {@code NOT_INDEXED}. */
-    RuleIndexingDetails(@IndexType int indexType) {
-        this.mIndexType = indexType;
-        this.mRuleKey = DEFAULT_RULE_KEY;
-    }
-
-    /** Constructor with a ruleKey for indexed rules. */
-    RuleIndexingDetails(@IndexType int indexType, String ruleKey) {
-        this.mIndexType = indexType;
-        this.mRuleKey = ruleKey;
-    }
-
-    /** Returns the indexing type for the rule. */
-    @IndexType
-    public int getIndexType() {
-        return mIndexType;
-    }
-
-    /** Returns the identified rule key. */
-    public String getRuleKey() {
-        return mRuleKey;
-    }
-}
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifier.java b/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifier.java
deleted file mode 100644
index e723559..0000000
--- a/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifier.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2019 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.integrity.serializer;
-
-import static com.android.server.integrity.serializer.RuleIndexingDetails.APP_CERTIFICATE_INDEXED;
-import static com.android.server.integrity.serializer.RuleIndexingDetails.NOT_INDEXED;
-import static com.android.server.integrity.serializer.RuleIndexingDetails.PACKAGE_NAME_INDEXED;
-
-import android.content.integrity.AtomicFormula;
-import android.content.integrity.CompoundFormula;
-import android.content.integrity.IntegrityFormula;
-import android.content.integrity.Rule;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-
-/** A helper class for identifying the indexing type and key of a given rule. */
-class RuleIndexingDetailsIdentifier {
-
-    /**
-     * Splits a given rule list into three indexing categories. Each rule category is returned as a
-     * TreeMap that is sorted by their indexing keys -- where keys correspond to package name for
-     * PACKAGE_NAME_INDEXED rules, app certificate for APP_CERTIFICATE_INDEXED rules and N/A for
-     * NOT_INDEXED rules.
-     */
-    public static Map<Integer, Map<String, List<Rule>>> splitRulesIntoIndexBuckets(
-            List<Rule> rules) {
-        if (rules == null) {
-            throw new IllegalArgumentException(
-                    "Index buckets cannot be created for null rule list.");
-        }
-
-        Map<Integer, Map<String, List<Rule>>> typeOrganizedRuleMap = new HashMap();
-        typeOrganizedRuleMap.put(NOT_INDEXED, new HashMap());
-        typeOrganizedRuleMap.put(PACKAGE_NAME_INDEXED, new HashMap<>());
-        typeOrganizedRuleMap.put(APP_CERTIFICATE_INDEXED, new HashMap<>());
-
-        // Split the rules into the appropriate indexed pattern. The Tree Maps help us to keep the
-        // entries sorted by their index key.
-        for (Rule rule : rules) {
-            RuleIndexingDetails indexingDetails;
-            try {
-                indexingDetails = getIndexingDetails(rule.getFormula());
-            } catch (Exception e) {
-                throw new IllegalArgumentException(
-                        String.format("Malformed rule identified. [%s]", rule.toString()));
-            }
-
-            int ruleIndexType = indexingDetails.getIndexType();
-            String ruleKey = indexingDetails.getRuleKey();
-
-            if (!typeOrganizedRuleMap.get(ruleIndexType).containsKey(ruleKey)) {
-                typeOrganizedRuleMap.get(ruleIndexType).put(ruleKey, new ArrayList());
-            }
-
-            typeOrganizedRuleMap.get(ruleIndexType).get(ruleKey).add(rule);
-        }
-
-        return typeOrganizedRuleMap;
-    }
-
-    private static RuleIndexingDetails getIndexingDetails(IntegrityFormula formula) {
-        switch (formula.getTag()) {
-            case IntegrityFormula.COMPOUND_FORMULA_TAG:
-                return getIndexingDetailsForCompoundFormula((CompoundFormula) formula);
-            case IntegrityFormula.STRING_ATOMIC_FORMULA_TAG:
-                return getIndexingDetailsForStringAtomicFormula(
-                        (AtomicFormula.StringAtomicFormula) formula);
-            case IntegrityFormula.LONG_ATOMIC_FORMULA_TAG:
-            case IntegrityFormula.INSTALLER_ALLOWED_BY_MANIFEST_FORMULA_TAG:
-            case IntegrityFormula.BOOLEAN_ATOMIC_FORMULA_TAG:
-                // Package name and app certificate related formulas are string atomic formulas.
-                return new RuleIndexingDetails(NOT_INDEXED);
-            default:
-                throw new IllegalArgumentException(
-                        String.format("Invalid formula tag type: %s", formula.getTag()));
-        }
-    }
-
-    private static RuleIndexingDetails getIndexingDetailsForCompoundFormula(
-            CompoundFormula compoundFormula) {
-        int connector = compoundFormula.getConnector();
-        List<IntegrityFormula> formulas = compoundFormula.getFormulas();
-
-        switch (connector) {
-            case CompoundFormula.AND:
-            case CompoundFormula.OR:
-                // If there is a package name related atomic rule, return package name indexed.
-                Optional<RuleIndexingDetails> packageNameRule =
-                        formulas.stream()
-                                .map(formula -> getIndexingDetails(formula))
-                                .filter(ruleIndexingDetails -> ruleIndexingDetails.getIndexType()
-                                        == PACKAGE_NAME_INDEXED)
-                                .findAny();
-                if (packageNameRule.isPresent()) {
-                    return packageNameRule.get();
-                }
-
-                // If there is an app certificate related atomic rule but no package name related
-                // atomic rule, return app certificate indexed.
-                Optional<RuleIndexingDetails> appCertificateRule =
-                        formulas.stream()
-                                .map(formula -> getIndexingDetails(formula))
-                                .filter(ruleIndexingDetails -> ruleIndexingDetails.getIndexType()
-                                        == APP_CERTIFICATE_INDEXED)
-                                .findAny();
-                if (appCertificateRule.isPresent()) {
-                    return appCertificateRule.get();
-                }
-
-                // Do not index when there is not package name or app certificate indexing.
-                return new RuleIndexingDetails(NOT_INDEXED);
-            default:
-                // Having a NOT operator in the indexing messes up the indexing; e.g., deny
-                // installation if app certificate is NOT X (should not be indexed with app cert
-                // X). We will not keep these rules indexed.
-                // Also any other type of unknown operators will not be indexed.
-                return new RuleIndexingDetails(NOT_INDEXED);
-        }
-    }
-
-    private static RuleIndexingDetails getIndexingDetailsForStringAtomicFormula(
-            AtomicFormula.StringAtomicFormula atomicFormula) {
-        switch (atomicFormula.getKey()) {
-            case AtomicFormula.PACKAGE_NAME:
-                return new RuleIndexingDetails(PACKAGE_NAME_INDEXED, atomicFormula.getValue());
-            case AtomicFormula.APP_CERTIFICATE:
-                return new RuleIndexingDetails(APP_CERTIFICATE_INDEXED, atomicFormula.getValue());
-            default:
-                return new RuleIndexingDetails(NOT_INDEXED);
-        }
-    }
-}
-
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleMetadataSerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleMetadataSerializer.java
deleted file mode 100644
index 022b4b8..0000000
--- a/services/core/java/com/android/server/integrity/serializer/RuleMetadataSerializer.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2019 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.integrity.serializer;
-
-import static com.android.server.integrity.parser.RuleMetadataParser.RULE_PROVIDER_TAG;
-import static com.android.server.integrity.parser.RuleMetadataParser.VERSION_TAG;
-
-import android.util.Xml;
-
-import com.android.modules.utils.TypedXmlSerializer;
-import com.android.server.integrity.model.RuleMetadata;
-
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.nio.charset.StandardCharsets;
-
-/** Helper class for writing rule metadata. */
-public class RuleMetadataSerializer {
-    /** Serialize the rule metadata to an output stream. */
-    public static void serialize(RuleMetadata ruleMetadata, OutputStream outputStream)
-            throws IOException {
-        TypedXmlSerializer xmlSerializer = Xml.resolveSerializer(outputStream);
-
-        serializeTaggedValue(xmlSerializer, RULE_PROVIDER_TAG, ruleMetadata.getRuleProvider());
-        serializeTaggedValue(xmlSerializer, VERSION_TAG, ruleMetadata.getVersion());
-
-        xmlSerializer.endDocument();
-    }
-
-    private static void serializeTaggedValue(TypedXmlSerializer xmlSerializer, String tag,
-            String value) throws IOException {
-        xmlSerializer.startTag(/* namespace= */ null, tag);
-        xmlSerializer.text(value);
-        xmlSerializer.endTag(/* namespace= */ null, tag);
-    }
-}
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleSerializeException.java b/services/core/java/com/android/server/integrity/serializer/RuleSerializeException.java
deleted file mode 100644
index 60cfc48..0000000
--- a/services/core/java/com/android/server/integrity/serializer/RuleSerializeException.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2019 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.integrity.serializer;
-
-import android.annotation.NonNull;
-
-/**
- * Thrown when rule serialization fails.
- */
-public class RuleSerializeException extends Exception {
-    public RuleSerializeException(@NonNull String message) {
-        super(message);
-    }
-
-    public RuleSerializeException(@NonNull String message, @NonNull Throwable cause) {
-        super(message, cause);
-    }
-}
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleSerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleSerializer.java
deleted file mode 100644
index 2941856..0000000
--- a/services/core/java/com/android/server/integrity/serializer/RuleSerializer.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2019 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.integrity.serializer;
-
-import android.content.integrity.Rule;
-
-import java.io.OutputStream;
-import java.util.List;
-import java.util.Optional;
-
-/** A helper class to serialize rules from the {@link Rule} model. */
-public interface RuleSerializer {
-
-    /** Serialize rules to an output stream */
-    void serialize(
-            List<Rule> rules,
-            Optional<Integer> formatVersion,
-            OutputStream ruleFileOutputStream,
-            OutputStream indexingFileOutputStream)
-            throws RuleSerializeException;
-
-    /** Serialize rules to a ByteArray. */
-    byte[] serialize(List<Rule> rules, Optional<Integer> formatVersion)
-            throws RuleSerializeException;
-}
diff --git a/services/core/java/com/android/server/pm/BackgroundInstallControlService.java b/services/core/java/com/android/server/pm/BackgroundInstallControlService.java
index 20cca969..af2bb17 100644
--- a/services/core/java/com/android/server/pm/BackgroundInstallControlService.java
+++ b/services/core/java/com/android/server/pm/BackgroundInstallControlService.java
@@ -404,9 +404,11 @@
 
     void handlePackageRemove(String packageName, int userId) {
         initBackgroundInstalledPackages();
+        if (mBackgroundInstalledPackages.contains(userId, packageName)) {
+            mCallbackHelper.notifyAllCallbacks(userId, packageName, INSTALL_EVENT_TYPE_UNINSTALL);
+        }
         mBackgroundInstalledPackages.remove(userId, packageName);
         writeBackgroundInstalledPackagesToDisk();
-        mCallbackHelper.notifyAllCallbacks(userId, packageName, INSTALL_EVENT_TYPE_UNINSTALL);
     }
 
     void handleUsageEvent(UsageEvents.Event event, int userId) {
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 05a96d9..f4b18ce 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1037,7 +1037,6 @@
         mLastStartReason = request.reason;
         mLastStartActivityTimeMs = System.currentTimeMillis();
 
-        final ActivityRecord previousStart = mLastStartActivityRecord;
         final IApplicationThread caller = request.caller;
         Intent intent = request.intent;
         NeededUriGrants intentGrants = request.intentGrants;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e827f44..07675b9 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -7072,7 +7072,7 @@
         @Override
         public void setImeInputTargetRequestedVisibility(boolean visible) {
             if (android.view.inputmethod.Flags.refactorInsetsController()) {
-                // TODO(b/329229469) we won't have the statsToken in all cases, but should still log
+                // TODO(b/353463205) we won't have the statsToken in all cases, but should still log
                 try {
                     mRemoteInsetsController.setImeInputTargetRequestedVisibility(visible);
                 } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 71adb80..5ed9612 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -258,7 +258,7 @@
             // Refer WindowState#getImeControlTarget().
             target = target.getWindow().getImeControlTarget();
         }
-        // TODO(b/329229469) make sure that the statsToken of all callers is non-null (currently
+        // TODO(b/353463205) make sure that the statsToken of all callers is non-null (currently
         //  not the case)
         super.updateControlForTarget(target, force, statsToken);
         if (Flags.refactorInsetsController()) {
@@ -294,12 +294,14 @@
         changed |= mDisplayContent.onImeInsetsClientVisibilityUpdate();
         if (Flags.refactorInsetsController()) {
             if (changed) {
+                ImeTracker.forLogging().onProgress(statsToken,
+                        ImeTracker.PHASE_SERVER_UPDATE_CLIENT_VISIBILITY);
                 invokeOnImeRequestedChangedListener(mDisplayContent.getImeInputTarget(),
                         statsToken);
             } else {
-                // TODO(b/329229469) change phase and check cancelled / failed
+                // TODO(b/353463205) check cancelled / failed
                 ImeTracker.forLogging().onCancelled(statsToken,
-                        ImeTracker.PHASE_CLIENT_REPORT_REQUESTED_VISIBLE_TYPES);
+                        ImeTracker.PHASE_SERVER_UPDATE_CLIENT_VISIBILITY);
             }
         }
         return changed;
@@ -464,7 +466,7 @@
             // This can later become ready, so we don't want to cancel the pending request here.
             return;
         }
-        // TODO(b/329229469) check if this is still triggered, as we don't go into STATE_SHOW_IME
+        // TODO(b/353463205) check if this is still triggered, as we don't go into STATE_SHOW_IME
         //  (DefaultImeVisibilityApplier)
         if (android.view.inputmethod.Flags.refactorInsetsController()) {
             // The IME is drawn, so call into {@link WindowState#notifyInsetsControlChanged}
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 5dddf36..4b2d454 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -317,9 +317,9 @@
             // aborted.
             provider.updateFakeControlTarget(target);
         } else {
-            // TODO(b/329229469) if the IME controlTarget changes, any pending requests should fail
+            // TODO(b/353463205) if the IME controlTarget changes, any pending requests should fail
             provider.updateControlForTarget(target, false /* force */,
-                    null /* TODO(b/329229469) check if needed here */);
+                    null /* TODO(b/353463205) check if needed here */);
 
             // Get control target again in case the provider didn't accept the one we passed to it.
             target = provider.getControlTarget();
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 077127c..1bb4c41 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -715,7 +715,7 @@
                 if (embeddedWindow != null) {
                     // If there is no WindowState for the IWindow, it could be still an
                     // EmbeddedWindow. Therefore, check the EmbeddedWindowController as well
-                    // TODO(b/329229469) Use different phase here
+                    // TODO(b/353463205) Use different phase here
                     ImeTracker.forLogging().onProgress(imeStatsToken,
                             ImeTracker.PHASE_WM_UPDATE_REQUESTED_VISIBLE_TYPES);
                     embeddedWindow.setRequestedVisibleTypes(
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index c741c6c..077bb03 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -2562,7 +2562,13 @@
         mTestLooper.dispatchAll();
 
         // User interacted with the DUT, so the device will not go to standby.
-        skipActiveSourceLostUi(0, true, true);
+        mHdmiControlService.oneTouchPlay(new IHdmiControlCallback.Stub() {
+            @Override
+            public void onComplete(int result) {
+            }
+        });
+        mTestLooper.dispatchAll();
+
         assertThat(mIsOnActiveSourceLostPopupActive).isFalse();
         assertThat(mPowerManager.isInteractive()).isTrue();
         assertThat(mNativeWrapper.getResultMessages().contains(activeSourceFromPlayback)).isTrue();
diff --git a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java
deleted file mode 100644
index 9ed2e88..0000000
--- a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java
+++ /dev/null
@@ -1,914 +0,0 @@
-/*
- * Copyright (C) 2019 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.integrity.serializer;
-
-import static com.android.server.integrity.model.ComponentBitSize.ATOMIC_FORMULA_START;
-import static com.android.server.integrity.model.ComponentBitSize.COMPOUND_FORMULA_END;
-import static com.android.server.integrity.model.ComponentBitSize.COMPOUND_FORMULA_START;
-import static com.android.server.integrity.model.ComponentBitSize.CONNECTOR_BITS;
-import static com.android.server.integrity.model.ComponentBitSize.DEFAULT_FORMAT_VERSION;
-import static com.android.server.integrity.model.ComponentBitSize.EFFECT_BITS;
-import static com.android.server.integrity.model.ComponentBitSize.FORMAT_VERSION_BITS;
-import static com.android.server.integrity.model.ComponentBitSize.KEY_BITS;
-import static com.android.server.integrity.model.ComponentBitSize.OPERATOR_BITS;
-import static com.android.server.integrity.model.ComponentBitSize.SEPARATOR_BITS;
-import static com.android.server.integrity.model.ComponentBitSize.VALUE_SIZE_BITS;
-import static com.android.server.integrity.model.IndexingFileConstants.END_INDEXING_KEY;
-import static com.android.server.integrity.model.IndexingFileConstants.INDEXING_BLOCK_SIZE;
-import static com.android.server.integrity.model.IndexingFileConstants.START_INDEXING_KEY;
-import static com.android.server.integrity.serializer.RuleBinarySerializer.INDEXED_RULE_SIZE_LIMIT;
-import static com.android.server.integrity.serializer.RuleBinarySerializer.NONINDEXED_RULE_SIZE_LIMIT;
-import static com.android.server.integrity.utils.TestUtils.getBits;
-import static com.android.server.integrity.utils.TestUtils.getBytes;
-import static com.android.server.integrity.utils.TestUtils.getValueBits;
-import static com.android.server.testutils.TestUtils.assertExpectException;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.integrity.AppInstallMetadata;
-import android.content.integrity.AtomicFormula;
-import android.content.integrity.CompoundFormula;
-import android.content.integrity.IntegrityFormula;
-import android.content.integrity.IntegrityUtils;
-import android.content.integrity.Rule;
-
-import androidx.annotation.NonNull;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.io.ByteArrayOutputStream;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
-
-@RunWith(JUnit4.class)
-public class RuleBinarySerializerTest {
-
-    private static final String SAMPLE_INSTALLER_NAME = "com.test.installer";
-    private static final String SAMPLE_INSTALLER_CERT = "installer_cert";
-
-    private static final String COMPOUND_FORMULA_START_BITS =
-            getBits(COMPOUND_FORMULA_START, SEPARATOR_BITS);
-    private static final String COMPOUND_FORMULA_END_BITS =
-            getBits(COMPOUND_FORMULA_END, SEPARATOR_BITS);
-    private static final String ATOMIC_FORMULA_START_BITS =
-            getBits(ATOMIC_FORMULA_START, SEPARATOR_BITS);
-
-    private static final String NOT = getBits(CompoundFormula.NOT, CONNECTOR_BITS);
-    private static final String AND = getBits(CompoundFormula.AND, CONNECTOR_BITS);
-    private static final String OR = getBits(CompoundFormula.OR, CONNECTOR_BITS);
-
-    private static final String PACKAGE_NAME = getBits(AtomicFormula.PACKAGE_NAME, KEY_BITS);
-    private static final String APP_CERTIFICATE = getBits(AtomicFormula.APP_CERTIFICATE, KEY_BITS);
-    private static final String INSTALLER_NAME = getBits(AtomicFormula.INSTALLER_NAME, KEY_BITS);
-    private static final String INSTALLER_CERTIFICATE =
-            getBits(AtomicFormula.INSTALLER_CERTIFICATE, KEY_BITS);
-    private static final String VERSION_CODE = getBits(AtomicFormula.VERSION_CODE, KEY_BITS);
-    private static final String PRE_INSTALLED = getBits(AtomicFormula.PRE_INSTALLED, KEY_BITS);
-
-    private static final String EQ = getBits(AtomicFormula.EQ, OPERATOR_BITS);
-
-    private static final String IS_NOT_HASHED = "0";
-    private static final String IS_HASHED = "1";
-
-    private static final String DENY = getBits(Rule.DENY, EFFECT_BITS);
-
-    private static final String START_BIT = "1";
-    private static final String END_BIT = "1";
-
-    private static final byte[] DEFAULT_FORMAT_VERSION_BYTES =
-            getBytes(getBits(DEFAULT_FORMAT_VERSION, FORMAT_VERSION_BITS));
-
-    private static final String SERIALIZED_START_INDEXING_KEY =
-            IS_NOT_HASHED
-                    + getBits(START_INDEXING_KEY.length(), VALUE_SIZE_BITS)
-                    + getValueBits(START_INDEXING_KEY);
-    private static final String SERIALIZED_END_INDEXING_KEY =
-            IS_NOT_HASHED
-                    + getBits(END_INDEXING_KEY.length(), VALUE_SIZE_BITS)
-                    + getValueBits(END_INDEXING_KEY);
-
-    @Test
-    public void testBinaryString_serializeNullRules() {
-        RuleSerializer binarySerializer = new RuleBinarySerializer();
-
-        assertExpectException(
-                RuleSerializeException.class,
-                /* expectedExceptionMessageRegex= */ "Null rules cannot be serialized.",
-                () -> binarySerializer.serialize(null, /* formatVersion= */ Optional.empty()));
-    }
-
-    @Test
-    public void testBinaryString_emptyRules() throws Exception {
-        ByteArrayOutputStream ruleOutputStream = new ByteArrayOutputStream();
-        ByteArrayOutputStream indexingOutputStream = new ByteArrayOutputStream();
-        RuleSerializer binarySerializer = new RuleBinarySerializer();
-
-        binarySerializer.serialize(
-                Collections.emptyList(),
-                /* formatVersion= */ Optional.empty(),
-                ruleOutputStream,
-                indexingOutputStream);
-
-        ByteArrayOutputStream expectedRuleOutputStream = new ByteArrayOutputStream();
-        expectedRuleOutputStream.write(DEFAULT_FORMAT_VERSION_BYTES);
-        assertThat(ruleOutputStream.toByteArray())
-                .isEqualTo(expectedRuleOutputStream.toByteArray());
-
-        ByteArrayOutputStream expectedIndexingOutputStream = new ByteArrayOutputStream();
-        String serializedIndexingBytes =
-                SERIALIZED_START_INDEXING_KEY
-                        + getBits(DEFAULT_FORMAT_VERSION_BYTES.length, /* numOfBits= */ 32)
-                        + SERIALIZED_END_INDEXING_KEY
-                        + getBits(DEFAULT_FORMAT_VERSION_BYTES.length, /* numOfBits= */ 32);
-        byte[] expectedIndexingBytes =
-                getBytes(
-                        serializedIndexingBytes
-                                + serializedIndexingBytes
-                                + serializedIndexingBytes);
-        expectedIndexingOutputStream.write(expectedIndexingBytes);
-        assertThat(indexingOutputStream.toByteArray())
-                .isEqualTo(expectedIndexingOutputStream.toByteArray());
-    }
-
-    @Test
-    public void testBinaryStream_serializeValidCompoundFormula() throws Exception {
-        String packageName = "com.test.app";
-        Rule rule =
-                new Rule(
-                        new CompoundFormula(
-                                CompoundFormula.NOT,
-                                Collections.singletonList(
-                                        new AtomicFormula.StringAtomicFormula(
-                                                AtomicFormula.PACKAGE_NAME,
-                                                packageName,
-                                                /* isHashedValue= */ false))),
-                        Rule.DENY);
-
-        ByteArrayOutputStream ruleOutputStream = new ByteArrayOutputStream();
-        ByteArrayOutputStream indexingOutputStream = new ByteArrayOutputStream();
-        RuleSerializer binarySerializer = new RuleBinarySerializer();
-        binarySerializer.serialize(
-                Collections.singletonList(rule),
-                /* formatVersion= */ Optional.empty(),
-                ruleOutputStream,
-                indexingOutputStream);
-
-        String expectedBits =
-                START_BIT
-                        + COMPOUND_FORMULA_START_BITS
-                        + NOT
-                        + ATOMIC_FORMULA_START_BITS
-                        + PACKAGE_NAME
-                        + EQ
-                        + IS_NOT_HASHED
-                        + getBits(packageName.length(), VALUE_SIZE_BITS)
-                        + getValueBits(packageName)
-                        + COMPOUND_FORMULA_END_BITS
-                        + DENY
-                        + END_BIT;
-        ByteArrayOutputStream expectedRuleOutputStream = new ByteArrayOutputStream();
-        expectedRuleOutputStream.write(DEFAULT_FORMAT_VERSION_BYTES);
-        expectedRuleOutputStream.write(getBytes(expectedBits));
-        assertThat(ruleOutputStream.toByteArray())
-                .isEqualTo(expectedRuleOutputStream.toByteArray());
-
-        ByteArrayOutputStream expectedIndexingOutputStream = new ByteArrayOutputStream();
-        String expectedIndexingBitsForIndexed =
-                SERIALIZED_START_INDEXING_KEY
-                        + getBits(DEFAULT_FORMAT_VERSION_BYTES.length, /* numOfBits= */ 32)
-                        + SERIALIZED_END_INDEXING_KEY
-                        + getBits(DEFAULT_FORMAT_VERSION_BYTES.length, /* numOfBits= */ 32);
-        String expectedIndexingBitsForUnindexed =
-                SERIALIZED_START_INDEXING_KEY
-                        + getBits(DEFAULT_FORMAT_VERSION_BYTES.length, /* numOfBits= */ 32)
-                        + SERIALIZED_END_INDEXING_KEY
-                        + getBits(
-                                DEFAULT_FORMAT_VERSION_BYTES.length + getBytes(expectedBits).length,
-                                /* numOfBits= */ 32);
-        expectedIndexingOutputStream.write(
-                getBytes(
-                        expectedIndexingBitsForIndexed
-                                + expectedIndexingBitsForIndexed
-                                + expectedIndexingBitsForUnindexed));
-
-        assertThat(indexingOutputStream.toByteArray())
-                .isEqualTo(expectedIndexingOutputStream.toByteArray());
-    }
-
-    @Test
-    public void testBinaryString_serializeValidCompoundFormula_notConnector() throws Exception {
-        String packageName = "com.test.app";
-        Rule rule =
-                new Rule(
-                        new CompoundFormula(
-                                CompoundFormula.NOT,
-                                Collections.singletonList(
-                                        new AtomicFormula.StringAtomicFormula(
-                                                AtomicFormula.PACKAGE_NAME,
-                                                packageName,
-                                                /* isHashedValue= */ false))),
-                        Rule.DENY);
-        RuleSerializer binarySerializer = new RuleBinarySerializer();
-        String expectedBits =
-                START_BIT
-                        + COMPOUND_FORMULA_START_BITS
-                        + NOT
-                        + ATOMIC_FORMULA_START_BITS
-                        + PACKAGE_NAME
-                        + EQ
-                        + IS_NOT_HASHED
-                        + getBits(packageName.length(), VALUE_SIZE_BITS)
-                        + getValueBits(packageName)
-                        + COMPOUND_FORMULA_END_BITS
-                        + DENY
-                        + END_BIT;
-        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
-        byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION_BYTES);
-        byteArrayOutputStream.write(getBytes(expectedBits));
-        byte[] expectedRules = byteArrayOutputStream.toByteArray();
-
-        byte[] actualRules =
-                binarySerializer.serialize(
-                        Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
-
-        assertThat(actualRules).isEqualTo(expectedRules);
-    }
-
-    @Test
-    public void testBinaryString_serializeValidCompoundFormula_andConnector() throws Exception {
-        String packageName = "com.test.app";
-        String appCertificate = "test_cert";
-        Rule rule =
-                new Rule(
-                        new CompoundFormula(
-                                CompoundFormula.AND,
-                                Arrays.asList(
-                                        new AtomicFormula.StringAtomicFormula(
-                                                AtomicFormula.PACKAGE_NAME,
-                                                packageName,
-                                                /* isHashedValue= */ false),
-                                        new AtomicFormula.StringAtomicFormula(
-                                                AtomicFormula.APP_CERTIFICATE,
-                                                appCertificate,
-                                                /* isHashedValue= */ false))),
-                        Rule.DENY);
-        RuleSerializer binarySerializer = new RuleBinarySerializer();
-        String expectedBits =
-                START_BIT
-                        + COMPOUND_FORMULA_START_BITS
-                        + AND
-                        + ATOMIC_FORMULA_START_BITS
-                        + PACKAGE_NAME
-                        + EQ
-                        + IS_NOT_HASHED
-                        + getBits(packageName.length(), VALUE_SIZE_BITS)
-                        + getValueBits(packageName)
-                        + ATOMIC_FORMULA_START_BITS
-                        + APP_CERTIFICATE
-                        + EQ
-                        + IS_NOT_HASHED
-                        + getBits(appCertificate.length(), VALUE_SIZE_BITS)
-                        + getValueBits(appCertificate)
-                        + COMPOUND_FORMULA_END_BITS
-                        + DENY
-                        + END_BIT;
-        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
-        byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION_BYTES);
-        byteArrayOutputStream.write(getBytes(expectedBits));
-        byte[] expectedRules = byteArrayOutputStream.toByteArray();
-
-        byte[] actualRules =
-                binarySerializer.serialize(
-                        Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
-
-        assertThat(actualRules).isEqualTo(expectedRules);
-    }
-
-    @Test
-    public void testBinaryString_serializeValidCompoundFormula_orConnector() throws Exception {
-        String packageName = "com.test.app";
-        String appCertificate = "test_cert";
-        Rule rule =
-                new Rule(
-                        new CompoundFormula(
-                                CompoundFormula.OR,
-                                Arrays.asList(
-                                        new AtomicFormula.StringAtomicFormula(
-                                                AtomicFormula.PACKAGE_NAME,
-                                                packageName,
-                                                /* isHashedValue= */ false),
-                                        new AtomicFormula.StringAtomicFormula(
-                                                AtomicFormula.APP_CERTIFICATE,
-                                                appCertificate,
-                                                /* isHashedValue= */ false))),
-                        Rule.DENY);
-        RuleSerializer binarySerializer = new RuleBinarySerializer();
-        String expectedBits =
-                START_BIT
-                        + COMPOUND_FORMULA_START_BITS
-                        + OR
-                        + ATOMIC_FORMULA_START_BITS
-                        + PACKAGE_NAME
-                        + EQ
-                        + IS_NOT_HASHED
-                        + getBits(packageName.length(), VALUE_SIZE_BITS)
-                        + getValueBits(packageName)
-                        + ATOMIC_FORMULA_START_BITS
-                        + APP_CERTIFICATE
-                        + EQ
-                        + IS_NOT_HASHED
-                        + getBits(appCertificate.length(), VALUE_SIZE_BITS)
-                        + getValueBits(appCertificate)
-                        + COMPOUND_FORMULA_END_BITS
-                        + DENY
-                        + END_BIT;
-        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
-        byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION_BYTES);
-        byteArrayOutputStream.write(getBytes(expectedBits));
-        byte[] expectedRules = byteArrayOutputStream.toByteArray();
-
-        byte[] actualRules =
-                binarySerializer.serialize(
-                        Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
-
-        assertThat(actualRules).isEqualTo(expectedRules);
-    }
-
-    @Test
-    public void testBinaryString_serializeValidAtomicFormula_stringValue() throws Exception {
-        String packageName = "com.test.app";
-        Rule rule =
-                new Rule(
-                        new AtomicFormula.StringAtomicFormula(
-                                AtomicFormula.PACKAGE_NAME,
-                                packageName,
-                                /* isHashedValue= */ false),
-                        Rule.DENY);
-        RuleSerializer binarySerializer = new RuleBinarySerializer();
-        String expectedBits =
-                START_BIT
-                        + ATOMIC_FORMULA_START_BITS
-                        + PACKAGE_NAME
-                        + EQ
-                        + IS_NOT_HASHED
-                        + getBits(packageName.length(), VALUE_SIZE_BITS)
-                        + getValueBits(packageName)
-                        + DENY
-                        + END_BIT;
-        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
-        byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION_BYTES);
-        byteArrayOutputStream.write(getBytes(expectedBits));
-        byte[] expectedRules = byteArrayOutputStream.toByteArray();
-
-        byte[] actualRules =
-                binarySerializer.serialize(
-                        Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
-
-        assertThat(actualRules).isEqualTo(expectedRules);
-    }
-
-    @Test
-    public void testBinaryString_serializeValidAtomicFormula_hashedValue() throws Exception {
-        String appCertificate = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
-        Rule rule =
-                new Rule(
-                        new AtomicFormula.StringAtomicFormula(
-                                AtomicFormula.APP_CERTIFICATE,
-                                IntegrityUtils.getHexDigest(
-                                        appCertificate.getBytes(StandardCharsets.UTF_8)),
-                                /* isHashedValue= */ true),
-                        Rule.DENY);
-        RuleSerializer binarySerializer = new RuleBinarySerializer();
-        String expectedBits =
-                START_BIT
-                        + ATOMIC_FORMULA_START_BITS
-                        + APP_CERTIFICATE
-                        + EQ
-                        + IS_HASHED
-                        + getBits(appCertificate.length(), VALUE_SIZE_BITS)
-                        + getValueBits(appCertificate)
-                        + DENY
-                        + END_BIT;
-        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
-        byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION_BYTES);
-        byteArrayOutputStream.write(getBytes(expectedBits));
-        byte[] expectedRules = byteArrayOutputStream.toByteArray();
-
-        byte[] actualRules =
-                binarySerializer.serialize(
-                        Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
-
-        assertThat(actualRules).isEqualTo(expectedRules);
-    }
-
-    @Test
-    public void testBinaryString_serializeValidAtomicFormula_integerValue() throws Exception {
-        long versionCode = 1;
-        Rule rule =
-                new Rule(
-                        new AtomicFormula.LongAtomicFormula(
-                                AtomicFormula.VERSION_CODE, AtomicFormula.EQ, versionCode),
-                        Rule.DENY);
-        RuleSerializer binarySerializer = new RuleBinarySerializer();
-        String expectedBits =
-                START_BIT
-                        + ATOMIC_FORMULA_START_BITS
-                        + VERSION_CODE
-                        + EQ
-                        + getBits(versionCode, /* numOfBits= */ 64)
-                        + DENY
-                        + END_BIT;
-        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
-        byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION_BYTES);
-        byteArrayOutputStream.write(getBytes(expectedBits));
-        byte[] expectedRules = byteArrayOutputStream.toByteArray();
-
-        byte[] actualRules =
-                binarySerializer.serialize(
-                        Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
-
-        assertThat(actualRules).isEqualTo(expectedRules);
-    }
-
-    @Test
-    public void testBinaryString_serializeValidAtomicFormula_booleanValue() throws Exception {
-        String preInstalled = "1";
-        Rule rule =
-                new Rule(
-                        new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true),
-                        Rule.DENY);
-        RuleSerializer binarySerializer = new RuleBinarySerializer();
-        String expectedBits =
-                START_BIT
-                        + ATOMIC_FORMULA_START_BITS
-                        + PRE_INSTALLED
-                        + EQ
-                        + preInstalled
-                        + DENY
-                        + END_BIT;
-        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
-        byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION_BYTES);
-        byteArrayOutputStream.write(getBytes(expectedBits));
-        byte[] expectedRules = byteArrayOutputStream.toByteArray();
-
-        byte[] actualRules =
-                binarySerializer.serialize(
-                        Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
-
-        assertThat(actualRules).isEqualTo(expectedRules);
-    }
-
-    @Test
-    public void testBinaryString_serializeInvalidFormulaType() throws Exception {
-        IntegrityFormula invalidFormula = getInvalidFormula();
-        Rule rule = new Rule(invalidFormula, Rule.DENY);
-        RuleSerializer binarySerializer = new RuleBinarySerializer();
-
-        assertExpectException(
-                RuleSerializeException.class,
-                /* expectedExceptionMessageRegex= */ "Malformed rule identified.",
-                () ->
-                        binarySerializer.serialize(
-                                Collections.singletonList(rule),
-                                /* formatVersion= */ Optional.empty()));
-    }
-
-    @Test
-    public void testBinaryString_serializeFormatVersion() throws Exception {
-        int formatVersion = 1;
-        RuleSerializer binarySerializer = new RuleBinarySerializer();
-        String expectedBits = getBits(formatVersion, FORMAT_VERSION_BITS);
-        byte[] expectedRules = getBytes(expectedBits);
-
-        byte[] actualRules =
-                binarySerializer.serialize(
-                        Collections.emptyList(), /* formatVersion= */ Optional.of(formatVersion));
-
-        assertThat(actualRules).isEqualTo(expectedRules);
-    }
-
-    @Test
-    public void testBinaryString_verifyManyRulesAreIndexedCorrectly() throws Exception {
-        int ruleCount = 225;
-        String packagePrefix = "package.name.";
-        String appCertificatePrefix = "app.cert.";
-        String installerNamePrefix = "installer.";
-
-        // Create the rule set with 225 package name based rules, 225 app certificate indexed rules,
-        // and 225 non-indexed rules..
-        List<Rule> ruleList = new ArrayList();
-        for (int count = 0; count < ruleCount; count++) {
-            ruleList.add(
-                    getRuleWithPackageNameAndSampleInstallerName(
-                            String.format("%s%04d", packagePrefix, count)));
-        }
-        for (int count = 0; count < ruleCount; count++) {
-            ruleList.add(
-                    getRuleWithAppCertificateAndSampleInstallerName(
-                            String.format("%s%04d", appCertificatePrefix, count)));
-        }
-        for (int count = 0; count < ruleCount; count++) {
-            ruleList.add(
-                    getNonIndexedRuleWithInstallerName(
-                            String.format("%s%04d", installerNamePrefix, count)));
-        }
-
-        // Serialize the rules.
-        ByteArrayOutputStream ruleOutputStream = new ByteArrayOutputStream();
-        ByteArrayOutputStream indexingOutputStream = new ByteArrayOutputStream();
-        RuleSerializer binarySerializer = new RuleBinarySerializer();
-        binarySerializer.serialize(
-                ruleList,
-                /* formatVersion= */ Optional.empty(),
-                ruleOutputStream,
-                indexingOutputStream);
-
-        // Verify the rules file and index files.
-        ByteArrayOutputStream expectedOrderedRuleOutputStream = new ByteArrayOutputStream();
-        ByteArrayOutputStream expectedIndexingOutputStream = new ByteArrayOutputStream();
-
-        expectedOrderedRuleOutputStream.write(DEFAULT_FORMAT_VERSION_BYTES);
-        int totalBytesWritten = DEFAULT_FORMAT_VERSION_BYTES.length;
-
-        String expectedIndexingBytesForPackageNameIndexed =
-                SERIALIZED_START_INDEXING_KEY + getBits(totalBytesWritten, /* numOfBits= */ 32);
-        for (int count = 0; count < ruleCount; count++) {
-            String packageName = String.format("%s%04d", packagePrefix, count);
-            if (count > 0 && count % INDEXING_BLOCK_SIZE == 0) {
-                expectedIndexingBytesForPackageNameIndexed +=
-                        IS_NOT_HASHED
-                                + getBits(packageName.length(), VALUE_SIZE_BITS)
-                                + getValueBits(packageName)
-                                + getBits(totalBytesWritten, /* numOfBits= */ 32);
-            }
-
-            byte[] bytesForPackage =
-                    getBytes(
-                            getSerializedCompoundRuleWithPackageNameAndSampleInstallerName(
-                                    packageName));
-            expectedOrderedRuleOutputStream.write(bytesForPackage);
-            totalBytesWritten += bytesForPackage.length;
-        }
-        expectedIndexingBytesForPackageNameIndexed +=
-                SERIALIZED_END_INDEXING_KEY + getBits(totalBytesWritten, /* numOfBits= */ 32);
-
-        String expectedIndexingBytesForAppCertificateIndexed =
-                SERIALIZED_START_INDEXING_KEY + getBits(totalBytesWritten, /* numOfBits= */ 32);
-        for (int count = 0; count < ruleCount; count++) {
-            String appCertificate = String.format("%s%04d", appCertificatePrefix, count);
-            if (count > 0 && count % INDEXING_BLOCK_SIZE == 0) {
-                expectedIndexingBytesForAppCertificateIndexed +=
-                        IS_NOT_HASHED
-                                + getBits(appCertificate.length(), VALUE_SIZE_BITS)
-                                + getValueBits(appCertificate)
-                                + getBits(totalBytesWritten, /* numOfBits= */ 32);
-            }
-
-            byte[] bytesForPackage =
-                    getBytes(
-                            getSerializedCompoundRuleWithCertificateNameAndSampleInstallerName(
-                                    appCertificate));
-            expectedOrderedRuleOutputStream.write(bytesForPackage);
-            totalBytesWritten += bytesForPackage.length;
-        }
-        expectedIndexingBytesForAppCertificateIndexed +=
-                SERIALIZED_END_INDEXING_KEY + getBits(totalBytesWritten, /* numOfBits= */ 32);
-
-        String expectedIndexingBytesForUnindexed =
-                SERIALIZED_START_INDEXING_KEY + getBits(totalBytesWritten, /* numOfBits= */ 32);
-        for (int count = 0; count < ruleCount; count++) {
-            byte[] bytesForPackage =
-                    getBytes(
-                            getSerializedCompoundRuleWithInstallerNameAndInstallerCert(
-                                    String.format("%s%04d", installerNamePrefix, count)));
-            expectedOrderedRuleOutputStream.write(bytesForPackage);
-            totalBytesWritten += bytesForPackage.length;
-        }
-        expectedIndexingBytesForUnindexed +=
-                SERIALIZED_END_INDEXING_KEY + getBits(totalBytesWritten, /* numOfBits= */ 32);
-        expectedIndexingOutputStream.write(
-                getBytes(
-                        expectedIndexingBytesForPackageNameIndexed
-                                + expectedIndexingBytesForAppCertificateIndexed
-                                + expectedIndexingBytesForUnindexed));
-
-        assertThat(ruleOutputStream.toByteArray())
-                .isEqualTo(expectedOrderedRuleOutputStream.toByteArray());
-        assertThat(indexingOutputStream.toByteArray())
-                .isEqualTo(expectedIndexingOutputStream.toByteArray());
-    }
-
-    @Test
-    public void testBinaryString_totalRuleSizeLimitReached() {
-        int ruleCount = INDEXED_RULE_SIZE_LIMIT - 1;
-        String packagePrefix = "package.name.";
-        String appCertificatePrefix = "app.cert.";
-        String installerNamePrefix = "installer.";
-
-        // Create the rule set with more rules than the system can handle in total.
-        List<Rule> ruleList = new ArrayList();
-        for (int count = 0; count < ruleCount; count++) {
-            ruleList.add(
-                    getRuleWithPackageNameAndSampleInstallerName(
-                            String.format("%s%04d", packagePrefix, count)));
-        }
-        for (int count = 0; count < ruleCount; count++) {
-            ruleList.add(
-                    getRuleWithAppCertificateAndSampleInstallerName(
-                            String.format("%s%04d", appCertificatePrefix, count)));
-        }
-        for (int count = 0; count < NONINDEXED_RULE_SIZE_LIMIT - 1; count++) {
-            ruleList.add(
-                    getNonIndexedRuleWithInstallerName(
-                            String.format("%s%04d", installerNamePrefix, count)));
-        }
-
-        // Serialize the rules.
-        ByteArrayOutputStream ruleOutputStream = new ByteArrayOutputStream();
-        ByteArrayOutputStream indexingOutputStream = new ByteArrayOutputStream();
-        RuleSerializer binarySerializer = new RuleBinarySerializer();
-
-        assertExpectException(
-                RuleSerializeException.class,
-                "Too many rules provided",
-                () ->
-                        binarySerializer.serialize(
-                                ruleList,
-                                /* formatVersion= */ Optional.empty(),
-                                ruleOutputStream,
-                                indexingOutputStream));
-    }
-
-    @Test
-    public void testBinaryString_tooManyPackageNameIndexedRules() {
-        String packagePrefix = "package.name.";
-
-        // Create a rule set with too many package name indexed rules.
-        List<Rule> ruleList = new ArrayList();
-        for (int count = 0; count < INDEXED_RULE_SIZE_LIMIT + 1; count++) {
-            ruleList.add(
-                    getRuleWithPackageNameAndSampleInstallerName(
-                            String.format("%s%04d", packagePrefix, count)));
-        }
-
-        // Serialize the rules.
-        ByteArrayOutputStream ruleOutputStream = new ByteArrayOutputStream();
-        ByteArrayOutputStream indexingOutputStream = new ByteArrayOutputStream();
-        RuleSerializer binarySerializer = new RuleBinarySerializer();
-
-        assertExpectException(
-                RuleSerializeException.class,
-                "Too many rules provided in the indexing group.",
-                () ->
-                        binarySerializer.serialize(
-                                ruleList,
-                                /* formatVersion= */ Optional.empty(),
-                                ruleOutputStream,
-                                indexingOutputStream));
-    }
-
-    @Test
-    public void testBinaryString_tooManyAppCertificateIndexedRules() {
-        String appCertificatePrefix = "app.cert.";
-
-        // Create a rule set with too many app certificate indexed rules.
-        List<Rule> ruleList = new ArrayList();
-        for (int count = 0; count < INDEXED_RULE_SIZE_LIMIT + 1; count++) {
-            ruleList.add(
-                    getRuleWithAppCertificateAndSampleInstallerName(
-                            String.format("%s%04d", appCertificatePrefix, count)));
-        }
-
-        // Serialize the rules.
-        ByteArrayOutputStream ruleOutputStream = new ByteArrayOutputStream();
-        ByteArrayOutputStream indexingOutputStream = new ByteArrayOutputStream();
-        RuleSerializer binarySerializer = new RuleBinarySerializer();
-
-        assertExpectException(
-                RuleSerializeException.class,
-                "Too many rules provided in the indexing group.",
-                () ->
-                        binarySerializer.serialize(
-                                ruleList,
-                                /* formatVersion= */ Optional.empty(),
-                                ruleOutputStream,
-                                indexingOutputStream));
-    }
-
-    @Test
-    public void testBinaryString_tooManyNonIndexedRules() {
-        String installerNamePrefix = "installer.";
-
-        // Create a rule set with too many unindexed rules.
-        List<Rule> ruleList = new ArrayList();
-        for (int count = 0; count < NONINDEXED_RULE_SIZE_LIMIT + 1; count++) {
-            ruleList.add(
-                    getNonIndexedRuleWithInstallerName(
-                            String.format("%s%04d", installerNamePrefix, count)));
-        }
-
-        // Serialize the rules.
-        ByteArrayOutputStream ruleOutputStream = new ByteArrayOutputStream();
-        ByteArrayOutputStream indexingOutputStream = new ByteArrayOutputStream();
-        RuleSerializer binarySerializer = new RuleBinarySerializer();
-
-        assertExpectException(
-                RuleSerializeException.class,
-                "Too many rules provided in the indexing group.",
-                () ->
-                        binarySerializer.serialize(
-                                ruleList,
-                                /* formatVersion= */ Optional.empty(),
-                                ruleOutputStream,
-                                indexingOutputStream));
-    }
-
-    private Rule getRuleWithPackageNameAndSampleInstallerName(String packageName) {
-        return new Rule(
-                new CompoundFormula(
-                        CompoundFormula.AND,
-                        Arrays.asList(
-                                new AtomicFormula.StringAtomicFormula(
-                                        AtomicFormula.PACKAGE_NAME,
-                                        packageName,
-                                        /* isHashedValue= */ false),
-                                new AtomicFormula.StringAtomicFormula(
-                                        AtomicFormula.INSTALLER_NAME,
-                                        SAMPLE_INSTALLER_NAME,
-                                        /* isHashedValue= */ false))),
-                Rule.DENY);
-    }
-
-    private String getSerializedCompoundRuleWithPackageNameAndSampleInstallerName(
-            String packageName) {
-        return START_BIT
-                + COMPOUND_FORMULA_START_BITS
-                + AND
-                + ATOMIC_FORMULA_START_BITS
-                + PACKAGE_NAME
-                + EQ
-                + IS_NOT_HASHED
-                + getBits(packageName.length(), VALUE_SIZE_BITS)
-                + getValueBits(packageName)
-                + ATOMIC_FORMULA_START_BITS
-                + INSTALLER_NAME
-                + EQ
-                + IS_NOT_HASHED
-                + getBits(SAMPLE_INSTALLER_NAME.length(), VALUE_SIZE_BITS)
-                + getValueBits(SAMPLE_INSTALLER_NAME)
-                + COMPOUND_FORMULA_END_BITS
-                + DENY
-                + END_BIT;
-    }
-
-    private Rule getRuleWithAppCertificateAndSampleInstallerName(String certificate) {
-        return new Rule(
-                new CompoundFormula(
-                        CompoundFormula.AND,
-                        Arrays.asList(
-                                new AtomicFormula.StringAtomicFormula(
-                                        AtomicFormula.APP_CERTIFICATE,
-                                        certificate,
-                                        /* isHashedValue= */ false),
-                                new AtomicFormula.StringAtomicFormula(
-                                        AtomicFormula.INSTALLER_NAME,
-                                        SAMPLE_INSTALLER_NAME,
-                                        /* isHashedValue= */ false))),
-                Rule.DENY);
-    }
-
-    private String getSerializedCompoundRuleWithCertificateNameAndSampleInstallerName(
-            String appCertificate) {
-        return START_BIT
-                + COMPOUND_FORMULA_START_BITS
-                + AND
-                + ATOMIC_FORMULA_START_BITS
-                + APP_CERTIFICATE
-                + EQ
-                + IS_NOT_HASHED
-                + getBits(appCertificate.length(), VALUE_SIZE_BITS)
-                + getValueBits(appCertificate)
-                + ATOMIC_FORMULA_START_BITS
-                + INSTALLER_NAME
-                + EQ
-                + IS_NOT_HASHED
-                + getBits(SAMPLE_INSTALLER_NAME.length(), VALUE_SIZE_BITS)
-                + getValueBits(SAMPLE_INSTALLER_NAME)
-                + COMPOUND_FORMULA_END_BITS
-                + DENY
-                + END_BIT;
-    }
-
-    private Rule getNonIndexedRuleWithInstallerName(String installerName) {
-        return new Rule(
-                new CompoundFormula(
-                        CompoundFormula.AND,
-                        Arrays.asList(
-                                new AtomicFormula.StringAtomicFormula(
-                                        AtomicFormula.INSTALLER_NAME,
-                                        installerName,
-                                        /* isHashedValue= */ false),
-                                new AtomicFormula.StringAtomicFormula(
-                                        AtomicFormula.INSTALLER_CERTIFICATE,
-                                        SAMPLE_INSTALLER_CERT,
-                                        /* isHashedValue= */ false))),
-                Rule.DENY);
-    }
-
-    private String getSerializedCompoundRuleWithInstallerNameAndInstallerCert(
-            String installerName) {
-        return START_BIT
-                + COMPOUND_FORMULA_START_BITS
-                + AND
-                + ATOMIC_FORMULA_START_BITS
-                + INSTALLER_NAME
-                + EQ
-                + IS_NOT_HASHED
-                + getBits(installerName.length(), VALUE_SIZE_BITS)
-                + getValueBits(installerName)
-                + ATOMIC_FORMULA_START_BITS
-                + INSTALLER_CERTIFICATE
-                + EQ
-                + IS_NOT_HASHED
-                + getBits(SAMPLE_INSTALLER_CERT.length(), VALUE_SIZE_BITS)
-                + getValueBits(SAMPLE_INSTALLER_CERT)
-                + COMPOUND_FORMULA_END_BITS
-                + DENY
-                + END_BIT;
-    }
-
-    private static IntegrityFormula getInvalidFormula() {
-        return new AtomicFormula(0) {
-            @Override
-            public int getTag() {
-                return 0;
-            }
-
-            @Override
-            public boolean matches(AppInstallMetadata appInstallMetadata) {
-                return false;
-            }
-
-            @Override
-            public boolean isAppCertificateFormula() {
-                return false;
-            }
-
-            @Override
-            public boolean isAppCertificateLineageFormula() {
-                return false;
-            }
-
-            @Override
-            public boolean isInstallerFormula() {
-                return false;
-            }
-
-            @Override
-            public int hashCode() {
-                return super.hashCode();
-            }
-
-            @Override
-            public boolean equals(Object obj) {
-                return super.equals(obj);
-            }
-
-            @NonNull
-            @Override
-            protected Object clone() throws CloneNotSupportedException {
-                return super.clone();
-            }
-
-            @Override
-            public String toString() {
-                return super.toString();
-            }
-
-            @Override
-            protected void finalize() throws Throwable {
-                super.finalize();
-            }
-        };
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifierTest.java b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifierTest.java
deleted file mode 100644
index 6dccdf5..0000000
--- a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifierTest.java
+++ /dev/null
@@ -1,344 +0,0 @@
-/*
- * Copyright (C) 2019 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.integrity.serializer;
-
-import static com.android.server.integrity.serializer.RuleIndexingDetails.APP_CERTIFICATE_INDEXED;
-import static com.android.server.integrity.serializer.RuleIndexingDetails.NOT_INDEXED;
-import static com.android.server.integrity.serializer.RuleIndexingDetails.PACKAGE_NAME_INDEXED;
-import static com.android.server.integrity.serializer.RuleIndexingDetailsIdentifier.splitRulesIntoIndexBuckets;
-import static com.android.server.testutils.TestUtils.assertExpectException;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.integrity.AppInstallMetadata;
-import android.content.integrity.AtomicFormula;
-import android.content.integrity.CompoundFormula;
-import android.content.integrity.IntegrityFormula;
-import android.content.integrity.Rule;
-
-import androidx.annotation.NonNull;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-
-/** Unit tests for {@link RuleIndexingDetailsIdentifier}. */
-@RunWith(JUnit4.class)
-public class RuleIndexingDetailsIdentifierTest {
-
-    private static final String SAMPLE_APP_CERTIFICATE = "testcert";
-    private static final String SAMPLE_INSTALLER_NAME = "com.test.installer";
-    private static final String SAMPLE_INSTALLER_CERTIFICATE = "installercert";
-    private static final String SAMPLE_PACKAGE_NAME = "com.test.package";
-
-    private static final AtomicFormula ATOMIC_FORMULA_WITH_PACKAGE_NAME =
-            new AtomicFormula.StringAtomicFormula(
-                    AtomicFormula.PACKAGE_NAME,
-                    SAMPLE_PACKAGE_NAME,
-                    /* isHashedValue= */ false);
-    private static final AtomicFormula ATOMIC_FORMULA_WITH_APP_CERTIFICATE =
-            new AtomicFormula.StringAtomicFormula(
-                    AtomicFormula.APP_CERTIFICATE,
-                    SAMPLE_APP_CERTIFICATE,
-                    /* isHashedValue= */ false);
-    private static final AtomicFormula ATOMIC_FORMULA_WITH_INSTALLER_NAME =
-            new AtomicFormula.StringAtomicFormula(
-                    AtomicFormula.INSTALLER_NAME,
-                    SAMPLE_INSTALLER_NAME,
-                    /* isHashedValue= */ false);
-    private static final AtomicFormula ATOMIC_FORMULA_WITH_INSTALLER_CERTIFICATE =
-            new AtomicFormula.StringAtomicFormula(
-                    AtomicFormula.INSTALLER_CERTIFICATE,
-                    SAMPLE_INSTALLER_CERTIFICATE,
-                    /* isHashedValue= */ false);
-    private static final AtomicFormula ATOMIC_FORMULA_WITH_VERSION_CODE =
-            new AtomicFormula.LongAtomicFormula(AtomicFormula.VERSION_CODE,
-                    AtomicFormula.EQ, 12);
-    private static final AtomicFormula ATOMIC_FORMULA_WITH_ISPREINSTALLED =
-            new AtomicFormula.BooleanAtomicFormula(
-                    AtomicFormula.PRE_INSTALLED, /* booleanValue= */
-                    true);
-
-
-    private static final Rule RULE_WITH_PACKAGE_NAME =
-            new Rule(
-                    new CompoundFormula(
-                            CompoundFormula.AND,
-                            Arrays.asList(
-                                    ATOMIC_FORMULA_WITH_PACKAGE_NAME,
-                                    ATOMIC_FORMULA_WITH_INSTALLER_NAME)),
-                    Rule.DENY);
-    private static final Rule RULE_WITH_APP_CERTIFICATE =
-            new Rule(
-                    new CompoundFormula(
-                            CompoundFormula.AND,
-                            Arrays.asList(
-                                    ATOMIC_FORMULA_WITH_APP_CERTIFICATE,
-                                    ATOMIC_FORMULA_WITH_INSTALLER_NAME)),
-                    Rule.DENY);
-    private static final Rule RULE_WITH_INSTALLER_RESTRICTIONS =
-            new Rule(
-                    new CompoundFormula(
-                            CompoundFormula.AND,
-                            Arrays.asList(
-                                    ATOMIC_FORMULA_WITH_INSTALLER_NAME,
-                                    ATOMIC_FORMULA_WITH_INSTALLER_CERTIFICATE)),
-                    Rule.DENY);
-
-    private static final Rule RULE_WITH_NONSTRING_RESTRICTIONS =
-            new Rule(
-                    new CompoundFormula(
-                            CompoundFormula.AND,
-                            Arrays.asList(
-                                    ATOMIC_FORMULA_WITH_VERSION_CODE,
-                                    ATOMIC_FORMULA_WITH_ISPREINSTALLED)),
-                    Rule.DENY);
-    public static final int INVALID_FORMULA_TAG = -1;
-
-    @Test
-    public void getIndexType_nullRule() {
-        List<Rule> ruleList = null;
-
-        assertExpectException(
-                IllegalArgumentException.class,
-                /* expectedExceptionMessageRegex= */
-                "Index buckets cannot be created for null rule list.",
-                () -> splitRulesIntoIndexBuckets(ruleList));
-    }
-
-    @Test
-    public void getIndexType_invalidFormula() {
-        List<Rule> ruleList = new ArrayList();
-        ruleList.add(new Rule(getInvalidFormula(), Rule.DENY));
-
-        assertExpectException(
-                IllegalArgumentException.class,
-                /* expectedExceptionMessageRegex= */ "Malformed rule identified.",
-                () -> splitRulesIntoIndexBuckets(ruleList));
-    }
-
-    @Test
-    public void getIndexType_ruleContainingPackageNameFormula() {
-        List<Rule> ruleList = new ArrayList();
-        ruleList.add(RULE_WITH_PACKAGE_NAME);
-
-        Map<Integer, Map<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList);
-
-        // Verify the resulting map content.
-        assertThat(result.keySet())
-                .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED);
-        assertThat(result.get(NOT_INDEXED)).isEmpty();
-        assertThat(result.get(APP_CERTIFICATE_INDEXED)).isEmpty();
-        assertThat(result.get(PACKAGE_NAME_INDEXED).keySet()).containsExactly(SAMPLE_PACKAGE_NAME);
-        assertThat(result.get(PACKAGE_NAME_INDEXED).get(SAMPLE_PACKAGE_NAME))
-                .containsExactly(RULE_WITH_PACKAGE_NAME);
-    }
-
-    @Test
-    public void getIndexType_ruleContainingAppCertificateFormula() {
-        List<Rule> ruleList = new ArrayList();
-        ruleList.add(RULE_WITH_APP_CERTIFICATE);
-
-        Map<Integer, Map<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList);
-
-        assertThat(result.keySet())
-                .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED);
-        assertThat(result.get(NOT_INDEXED)).isEmpty();
-        assertThat(result.get(PACKAGE_NAME_INDEXED)).isEmpty();
-        assertThat(result.get(APP_CERTIFICATE_INDEXED).keySet())
-                .containsExactly(SAMPLE_APP_CERTIFICATE);
-        assertThat(result.get(APP_CERTIFICATE_INDEXED).get(SAMPLE_APP_CERTIFICATE))
-                .containsExactly(RULE_WITH_APP_CERTIFICATE);
-    }
-
-    @Test
-    public void getIndexType_ruleWithUnindexedCompoundFormula() {
-        List<Rule> ruleList = new ArrayList();
-        ruleList.add(RULE_WITH_INSTALLER_RESTRICTIONS);
-
-        Map<Integer, Map<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList);
-
-        assertThat(result.keySet())
-                .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED);
-        assertThat(result.get(PACKAGE_NAME_INDEXED)).isEmpty();
-        assertThat(result.get(APP_CERTIFICATE_INDEXED)).isEmpty();
-        assertThat(result.get(NOT_INDEXED).get("N/A"))
-                .containsExactly(RULE_WITH_INSTALLER_RESTRICTIONS);
-    }
-
-    @Test
-    public void getIndexType_ruleContainingCompoundFormulaWithIntAndBoolean() {
-        List<Rule> ruleList = new ArrayList();
-        ruleList.add(RULE_WITH_NONSTRING_RESTRICTIONS);
-
-        Map<Integer, Map<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList);
-
-        assertThat(result.keySet())
-                .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED);
-        assertThat(result.get(PACKAGE_NAME_INDEXED)).isEmpty();
-        assertThat(result.get(APP_CERTIFICATE_INDEXED)).isEmpty();
-        assertThat(result.get(NOT_INDEXED).get("N/A"))
-                .containsExactly(RULE_WITH_NONSTRING_RESTRICTIONS);
-    }
-
-    @Test
-    public void getIndexType_negatedRuleContainingPackageNameFormula() {
-        Rule negatedRule =
-                new Rule(
-                        new CompoundFormula(
-                                CompoundFormula.NOT,
-                                Arrays.asList(
-                                        new CompoundFormula(
-                                                CompoundFormula.AND,
-                                                Arrays.asList(
-                                                        ATOMIC_FORMULA_WITH_PACKAGE_NAME,
-                                                        ATOMIC_FORMULA_WITH_APP_CERTIFICATE)))),
-                        Rule.DENY);
-        List<Rule> ruleList = new ArrayList();
-        ruleList.add(negatedRule);
-
-        Map<Integer, Map<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList);
-
-        assertThat(result.keySet())
-                .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED);
-        assertThat(result.get(PACKAGE_NAME_INDEXED)).isEmpty();
-        assertThat(result.get(APP_CERTIFICATE_INDEXED)).isEmpty();
-        assertThat(result.get(NOT_INDEXED).get("N/A")).containsExactly(negatedRule);
-    }
-
-    @Test
-    public void getIndexType_allRulesTogetherSplitCorrectly() {
-        Rule packageNameRuleA = getRuleWithPackageName("aaa");
-        Rule packageNameRuleB = getRuleWithPackageName("bbb");
-        Rule packageNameRuleC = getRuleWithPackageName("ccc");
-        Rule certificateRule1 = getRuleWithAppCertificate("cert1");
-        Rule certificateRule2 = getRuleWithAppCertificate("cert2");
-        Rule certificateRule3 = getRuleWithAppCertificate("cert3");
-
-        List<Rule> ruleList = new ArrayList();
-        ruleList.add(packageNameRuleB);
-        ruleList.add(packageNameRuleC);
-        ruleList.add(packageNameRuleA);
-        ruleList.add(certificateRule3);
-        ruleList.add(certificateRule2);
-        ruleList.add(certificateRule1);
-        ruleList.add(RULE_WITH_INSTALLER_RESTRICTIONS);
-        ruleList.add(RULE_WITH_NONSTRING_RESTRICTIONS);
-
-        Map<Integer, Map<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList);
-
-        assertThat(result.keySet())
-                .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED);
-
-        // We check asserts this way to ensure ordering based on package name.
-        assertThat(result.get(PACKAGE_NAME_INDEXED).keySet()).containsExactly("aaa", "bbb", "ccc");
-
-        // We check asserts this way to ensure ordering based on app certificate.
-        assertThat(result.get(APP_CERTIFICATE_INDEXED).keySet()).containsExactly("cert1", "cert2",
-                "cert3");
-
-        assertThat(result.get(NOT_INDEXED).get("N/A"))
-                .containsExactly(RULE_WITH_INSTALLER_RESTRICTIONS,
-                        RULE_WITH_NONSTRING_RESTRICTIONS);
-    }
-
-    private Rule getRuleWithPackageName(String packageName) {
-        return new Rule(
-                new CompoundFormula(
-                        CompoundFormula.AND,
-                        Arrays.asList(
-                                new AtomicFormula.StringAtomicFormula(
-                                        AtomicFormula.PACKAGE_NAME,
-                                        packageName,
-                                        /* isHashedValue= */ false),
-                                ATOMIC_FORMULA_WITH_INSTALLER_NAME)),
-                Rule.DENY);
-    }
-
-    private Rule getRuleWithAppCertificate(String certificate) {
-        return new Rule(
-                new CompoundFormula(
-                        CompoundFormula.AND,
-                        Arrays.asList(
-                                new AtomicFormula.StringAtomicFormula(
-                                        AtomicFormula.APP_CERTIFICATE,
-                                        certificate,
-                                        /* isHashedValue= */ false),
-                                ATOMIC_FORMULA_WITH_INSTALLER_NAME)),
-                Rule.DENY);
-    }
-
-    private IntegrityFormula getInvalidFormula() {
-        return new AtomicFormula(0) {
-            @Override
-            public int getTag() {
-                return INVALID_FORMULA_TAG;
-            }
-
-            @Override
-            public boolean matches(AppInstallMetadata appInstallMetadata) {
-                return false;
-            }
-
-            @Override
-            public boolean isAppCertificateFormula() {
-                return false;
-            }
-
-            @Override
-            public boolean isAppCertificateLineageFormula() {
-                return false;
-            }
-
-            @Override
-            public boolean isInstallerFormula() {
-                return false;
-            }
-
-            @Override
-            public int hashCode() {
-                return super.hashCode();
-            }
-
-            @Override
-            public boolean equals(Object obj) {
-                return super.equals(obj);
-            }
-
-            @NonNull
-            @Override
-            protected Object clone() throws CloneNotSupportedException {
-                return super.clone();
-            }
-
-            @Override
-            public String toString() {
-                return super.toString();
-            }
-
-            @Override
-            protected void finalize() throws Throwable {
-                super.finalize();
-            }
-        };
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/pm/BackgroundInstallControlServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/BackgroundInstallControlServiceTest.java
index 4a43c2e..9d7b6a1 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BackgroundInstallControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BackgroundInstallControlServiceTest.java
@@ -977,11 +977,19 @@
         assertEquals(USER_ID_1, UserHandle.getUserId(uid));
 
         mPackageListObserver.onPackageRemoved(PACKAGE_NAME_1, uid);
+        // Test that notifyAllCallbacks doesn't trigger for non-background-installed package
+        mPackageListObserver.onPackageRemoved(PACKAGE_NAME_3, uid);
         mTestLooper.dispatchAll();
 
         assertEquals(1, packages.size());
         assertFalse(packages.contains(USER_ID_1, PACKAGE_NAME_1));
         assertTrue(packages.contains(USER_ID_2, PACKAGE_NAME_2));
+
+        verify(mCallbackHelper)
+                .notifyAllCallbacks(
+                        USER_ID_1,
+                        PACKAGE_NAME_1,
+                        BackgroundInstallControlService.INSTALL_EVENT_TYPE_UNINSTALL);
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java b/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java
index ad11c26..f0b1c5c 100644
--- a/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java
@@ -331,6 +331,7 @@
         mPhoneWindowManager.setupAssistForLaunch();
         mPhoneWindowManager.overrideTogglePanel();
         mPhoneWindowManager.overrideInjectKeyEvent();
+        mPhoneWindowManager.overrideRoleManager();
     }
 
     @Test
diff --git a/services/usb/OWNERS b/services/usb/OWNERS
index d35dbb56..2dff392 100644
--- a/services/usb/OWNERS
+++ b/services/usb/OWNERS
@@ -1,9 +1,9 @@
-aprasath@google.com
-kumarashishg@google.com
-sarup@google.com
 anothermark@google.com
+febinthattil@google.com
+aprasath@google.com
 badhri@google.com
 elaurent@google.com
 albertccwang@google.com
 jameswei@google.com
-howardyen@google.com
\ No newline at end of file
+howardyen@google.com
+kumarashishg@google.com
\ No newline at end of file