Merge "Update lastUnconstraintedTextSize from setTextSize" into main
diff --git a/Android.bp b/Android.bp
index 59e903e..f6bfe65 100644
--- a/Android.bp
+++ b/Android.bp
@@ -389,7 +389,6 @@
         // TODO(b/120066492): remove gps_debug and protolog.conf.json when the build
         // system propagates "required" properly.
         "gps_debug.conf",
-        "core.protolog.pb",
         "framework-res",
         // any install dependencies should go into framework-minus-apex-install-dependencies
         // rather than here to avoid bloating incremental build time
diff --git a/Ravenwood.bp b/Ravenwood.bp
index 6237e3e..c3b22c4 100644
--- a/Ravenwood.bp
+++ b/Ravenwood.bp
@@ -30,7 +30,7 @@
     name: "framework-minus-apex.ravenwood-base",
     tools: ["hoststubgen"],
     cmd: "$(location hoststubgen) " +
-        "@$(location ravenwood/ravenwood-standard-options.txt) " +
+        "@$(location ravenwood/texts/ravenwood-standard-options.txt) " +
 
         "--debug-log $(location hoststubgen_framework-minus-apex.log) " +
         "--stats-file $(location hoststubgen_framework-minus-apex_stats.csv) " +
@@ -41,13 +41,13 @@
         "--gen-input-dump-file $(location hoststubgen_dump.txt) " +
 
         "--in-jar $(location :framework-minus-apex-for-hoststubgen) " +
-        "--policy-override-file $(location ravenwood/framework-minus-apex-ravenwood-policies.txt) " +
-        "--annotation-allowed-classes-file $(location ravenwood/ravenwood-annotation-allowed-classes.txt) ",
+        "--policy-override-file $(location ravenwood/texts/framework-minus-apex-ravenwood-policies.txt) " +
+        "--annotation-allowed-classes-file $(location ravenwood/texts/ravenwood-annotation-allowed-classes.txt) ",
     srcs: [
         ":framework-minus-apex-for-hoststubgen",
-        "ravenwood/framework-minus-apex-ravenwood-policies.txt",
-        "ravenwood/ravenwood-standard-options.txt",
-        "ravenwood/ravenwood-annotation-allowed-classes.txt",
+        "ravenwood/texts/framework-minus-apex-ravenwood-policies.txt",
+        "ravenwood/texts/ravenwood-standard-options.txt",
+        "ravenwood/texts/ravenwood-annotation-allowed-classes.txt",
     ],
     out: [
         "ravenwood.jar",
@@ -104,7 +104,7 @@
     name: "services.core.ravenwood-base",
     tools: ["hoststubgen"],
     cmd: "$(location hoststubgen) " +
-        "@$(location ravenwood/ravenwood-standard-options.txt) " +
+        "@$(location ravenwood/texts/ravenwood-standard-options.txt) " +
 
         "--debug-log $(location hoststubgen_services.core.log) " +
         "--stats-file $(location hoststubgen_services.core_stats.csv) " +
@@ -115,13 +115,13 @@
         "--gen-input-dump-file $(location hoststubgen_dump.txt) " +
 
         "--in-jar $(location :services.core-for-hoststubgen) " +
-        "--policy-override-file $(location ravenwood/services.core-ravenwood-policies.txt) " +
-        "--annotation-allowed-classes-file $(location ravenwood/ravenwood-annotation-allowed-classes.txt) ",
+        "--policy-override-file $(location ravenwood/texts/services.core-ravenwood-policies.txt) " +
+        "--annotation-allowed-classes-file $(location ravenwood/texts/ravenwood-annotation-allowed-classes.txt) ",
     srcs: [
         ":services.core-for-hoststubgen",
-        "ravenwood/services.core-ravenwood-policies.txt",
-        "ravenwood/ravenwood-standard-options.txt",
-        "ravenwood/ravenwood-annotation-allowed-classes.txt",
+        "ravenwood/texts/services.core-ravenwood-policies.txt",
+        "ravenwood/texts/ravenwood-standard-options.txt",
+        "ravenwood/texts/ravenwood-annotation-allowed-classes.txt",
     ],
     out: [
         "ravenwood.jar",
diff --git a/core/api/current.txt b/core/api/current.txt
index 1cfc025..b19c3ab 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -10147,17 +10147,17 @@
 
   public interface ComponentCallbacks {
     method public void onConfigurationChanged(@NonNull android.content.res.Configuration);
-    method public void onLowMemory();
+    method @Deprecated public void onLowMemory();
   }
 
   public interface ComponentCallbacks2 extends android.content.ComponentCallbacks {
     method public void onTrimMemory(int);
     field public static final int TRIM_MEMORY_BACKGROUND = 40; // 0x28
-    field public static final int TRIM_MEMORY_COMPLETE = 80; // 0x50
-    field public static final int TRIM_MEMORY_MODERATE = 60; // 0x3c
-    field public static final int TRIM_MEMORY_RUNNING_CRITICAL = 15; // 0xf
-    field public static final int TRIM_MEMORY_RUNNING_LOW = 10; // 0xa
-    field public static final int TRIM_MEMORY_RUNNING_MODERATE = 5; // 0x5
+    field @Deprecated public static final int TRIM_MEMORY_COMPLETE = 80; // 0x50
+    field @Deprecated public static final int TRIM_MEMORY_MODERATE = 60; // 0x3c
+    field @Deprecated public static final int TRIM_MEMORY_RUNNING_CRITICAL = 15; // 0xf
+    field @Deprecated public static final int TRIM_MEMORY_RUNNING_LOW = 10; // 0xa
+    field @Deprecated public static final int TRIM_MEMORY_RUNNING_MODERATE = 5; // 0x5
     field public static final int TRIM_MEMORY_UI_HIDDEN = 20; // 0x14
   }
 
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index ca5d3eb..6189703 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -3676,6 +3676,10 @@
     field public static final int FLAG_IS_ACCESSIBILITY_EVENT = 2048; // 0x800
   }
 
+  public final class PointerIcon implements android.os.Parcelable {
+    method @FlaggedApi("android.view.flags.enable_vector_cursors") public void setDrawNativeDropShadow(boolean);
+  }
+
   @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD}) public @interface RemotableViewMethod {
     method public abstract String asyncImpl() default "";
   }
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 0ed25eb..7ed10e7 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -18,7 +18,7 @@
 
 
 import static android.location.flags.Flags.FLAG_LOCATION_BYPASS;
-import static android.media.audio.Flags.foregroundAudioControl;
+import static android.media.audio.Flags.roForegroundAudioControl;
 import static android.permission.flags.Flags.FLAG_OP_ENABLE_MOBILE_DATA_BY_USER;
 import static android.view.contentprotection.flags.Flags.FLAG_CREATE_ACCESSIBILITY_OVERLAY_APP_OP_ENABLED;
 import static android.view.contentprotection.flags.Flags.FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED;
@@ -3246,7 +3246,7 @@
      * @hide
      */
     public static @Mode int opToDefaultMode(int op) {
-        if (op == OP_TAKE_AUDIO_FOCUS && foregroundAudioControl()) {
+        if (op == OP_TAKE_AUDIO_FOCUS && roForegroundAudioControl()) {
             // when removing the flag, change the entry in sAppOpInfos for OP_TAKE_AUDIO_FOCUS
             return AppOpsManager.MODE_FOREGROUND;
         }
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 08636ae..55ce90d 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -157,7 +157,6 @@
     ParceledListSlice<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum, int flags,
             int userId);
     boolean isTopActivityImmersive();
-    ActivityManager.TaskDescription getTaskDescription(int taskId);
     void reportAssistContextExtras(in IBinder assistToken, in Bundle extras,
             in AssistStructure structure, in AssistContent content, in Uri referrer);
 
diff --git a/core/java/android/content/ComponentCallbacks.java b/core/java/android/content/ComponentCallbacks.java
index 428545d..fb9536f 100644
--- a/core/java/android/content/ComponentCallbacks.java
+++ b/core/java/android/content/ComponentCallbacks.java
@@ -55,15 +55,11 @@
      * That is, before reaching the point of killing processes hosting
      * service and foreground UI that we would like to avoid killing.
      *
-     * <p>You should implement this method to release
-     * any caches or other unnecessary resources you may be holding on to.
-     * The system will perform a garbage collection for you after returning from this method.
-     * <p>Preferably, you should implement {@link ComponentCallbacks2#onTrimMemory} from
-     * {@link ComponentCallbacks2} to incrementally unload your resources based on various
-     * levels of memory demands.  That API is available for API level 14 and higher, so you should
-     * only use this {@link #onLowMemory} method as a fallback for older versions, which can be
-     * treated the same as {@link ComponentCallbacks2#onTrimMemory} with the {@link
-     * ComponentCallbacks2#TRIM_MEMORY_COMPLETE} level.</p>
+     * @deprecated Since API level 14 this is superseded by
+     *             {@link ComponentCallbacks2#onTrimMemory}.
+     *             Since API level 34 this is never called.
+     *             Apps targeting API level 34 and above may provide an empty implementation.
      */
+    @Deprecated
     void onLowMemory();
 }
diff --git a/core/java/android/content/ComponentCallbacks2.java b/core/java/android/content/ComponentCallbacks2.java
index 6576c0f..a165b18 100644
--- a/core/java/android/content/ComponentCallbacks2.java
+++ b/core/java/android/content/ComponentCallbacks2.java
@@ -105,14 +105,20 @@
      * Level for {@link #onTrimMemory(int)}: the process is nearing the end
      * of the background LRU list, and if more memory isn't found soon it will
      * be killed.
+     *
+     * @deprecated Apps are not notified of this level since API level 34
      */
+    @Deprecated
     static final int TRIM_MEMORY_COMPLETE = 80;
     
     /**
      * Level for {@link #onTrimMemory(int)}: the process is around the middle
      * of the background LRU list; freeing memory can help the system keep
      * other processes running later in the list for better overall performance.
+     *
+     * @deprecated Apps are not notified of this level since API level 34
      */
+    @Deprecated
     static final int TRIM_MEMORY_MODERATE = 60;
     
     /**
@@ -139,7 +145,10 @@
      * will happen after this is {@link #onLowMemory()} called to report that
      * nothing at all can be kept in the background, a situation that can start
      * to notably impact the user.
+     *
+     * @deprecated Apps are not notified of this level since API level 34
      */
+    @Deprecated
     static final int TRIM_MEMORY_RUNNING_CRITICAL = 15;
 
     /**
@@ -147,7 +156,10 @@
      * background process, but the device is running low on memory.
      * Your running process should free up unneeded resources to allow that
      * memory to be used elsewhere.
+     *
+     * @deprecated Apps are not notified of this level since API level 34
      */
+    @Deprecated
     static final int TRIM_MEMORY_RUNNING_LOW = 10;
 
     /**
@@ -155,17 +167,19 @@
      * background process, but the device is running moderately low on memory.
      * Your running process may want to release some unneeded resources for
      * use elsewhere.
+     *
+     * @deprecated Apps are not notified of this level since API level 34
      */
+    @Deprecated
     static final int TRIM_MEMORY_RUNNING_MODERATE = 5;
 
     /**
      * Called when the operating system has determined that it is a good
-     * time for a process to trim unneeded memory from its process.  This will
-     * happen for example when it goes in the background and there is not enough
-     * memory to keep as many background processes running as desired.  You
-     * should never compare to exact values of the level, since new intermediate
-     * values may be added -- you will typically want to compare if the value
-     * is greater or equal to a level you are interested in.
+     * time for a process to trim unneeded memory from its process.
+     *
+     * You should never compare to exact values of the level, since new
+     * intermediate values may be added -- you will typically want to compare if
+     * the value is greater or equal to a level you are interested in.
      *
      * <p>To retrieve the processes current trim level at any point, you can
      * use {@link android.app.ActivityManager#getMyMemoryState
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 4c0da7c..f5bff9d 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -4844,6 +4844,16 @@
     public static final String FEATURE_ROTARY_ENCODER_LOW_RES =
             "android.hardware.rotaryencoder.lowres";
 
+  /**
+   * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device has
+   * support for contextual search helper.
+   *
+   * @hide
+   */
+  @SdkConstant(SdkConstantType.FEATURE)
+  public static final String FEATURE_CONTEXTUAL_SEARCH_HELPER =
+      "android.software.contextualsearch";
+
     /** @hide */
     public static final boolean APP_ENUMERATION_ENABLED_BY_DEFAULT = true;
 
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 8feb133..ea7db4c 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -1081,6 +1081,12 @@
      * {@link java.util.concurrent.Executor} as an argument instead of
      * {@link android.os.Handler}.</p>
      *
+     * <p>Do note that typically callbacks are expected to be dispatched
+     * by the executor in a single thread. If the executor uses two or
+     * more threads to dispatch callbacks, then clients must ensure correct
+     * synchronization and must also be able to handle potentially different
+     * ordering of the incoming callbacks.</p>
+     *
      * @param cameraId
      *             The unique identifier of the camera device to open
      * @param executor
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 97c03ed..81bb9ac 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -290,6 +290,55 @@
         }
     };
 
+    private class ClientStateCallback extends StateCallback {
+        private final Executor mClientExecutor;
+        private final StateCallback mClientStateCallback;
+
+        private ClientStateCallback(@NonNull Executor clientExecutor,
+                @NonNull StateCallback clientStateCallback) {
+            mClientExecutor = clientExecutor;
+            mClientStateCallback = clientStateCallback;
+        }
+
+        public void onClosed(@NonNull CameraDevice camera) {
+            mClientExecutor.execute(new Runnable() {
+                @Override
+                public void run() {
+                    mClientStateCallback.onClosed(camera);
+                }
+            });
+        }
+        @Override
+        public void onOpened(@NonNull CameraDevice camera) {
+            mClientExecutor.execute(new Runnable() {
+                @Override
+                public void run() {
+                    mClientStateCallback.onOpened(camera);
+                }
+            });
+        }
+
+        @Override
+        public void onDisconnected(@NonNull CameraDevice camera) {
+            mClientExecutor.execute(new Runnable() {
+                @Override
+                public void run() {
+                    mClientStateCallback.onDisconnected(camera);
+                }
+            });
+        }
+
+        @Override
+        public void onError(@NonNull CameraDevice camera, int error) {
+            mClientExecutor.execute(new Runnable() {
+                @Override
+                public void run() {
+                    mClientStateCallback.onError(camera, error);
+                }
+            });
+        }
+    }
+
     public CameraDeviceImpl(String cameraId, StateCallback callback, Executor executor,
                         CameraCharacteristics characteristics,
                         Map<String, CameraCharacteristics> physicalIdsToChars,
@@ -300,8 +349,13 @@
             throw new IllegalArgumentException("Null argument given");
         }
         mCameraId = cameraId;
-        mDeviceCallback = callback;
-        mDeviceExecutor = executor;
+        if (Flags.singleThreadExecutor()) {
+            mDeviceCallback = new ClientStateCallback(executor, callback);
+            mDeviceExecutor = Executors.newSingleThreadExecutor();
+        } else {
+            mDeviceCallback = callback;
+            mDeviceExecutor = executor;
+        }
         mCharacteristics = characteristics;
         mPhysicalIdsToChars = physicalIdsToChars;
         mAppTargetSdkVersion = appTargetSdkVersion;
diff --git a/core/java/android/hardware/face/FaceSensorConfigurations.java b/core/java/android/hardware/face/FaceSensorConfigurations.java
index 6ef692f..1247168 100644
--- a/core/java/android/hardware/face/FaceSensorConfigurations.java
+++ b/core/java/android/hardware/face/FaceSensorConfigurations.java
@@ -22,11 +22,12 @@
 import android.content.Context;
 import android.hardware.biometrics.face.IFace;
 import android.hardware.biometrics.face.SensorProps;
+import android.os.Binder;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.util.Log;
-import android.util.Pair;
 import android.util.Slog;
 
 import androidx.annotation.NonNull;
@@ -36,7 +37,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
-import java.util.function.Function;
 
 /**
  * Provides the sensor props for face sensor, if available.
@@ -74,22 +74,10 @@
     /**
      * Process AIDL instances to extract sensor props and add it to the sensor map.
      * @param aidlInstances available face AIDL instances
-     * @param getIFace function that provides the daemon for the specific instance
      */
-    public void addAidlConfigs(@NonNull String[] aidlInstances,
-            @NonNull Function<String, IFace> getIFace) {
+    public void addAidlConfigs(@NonNull String[] aidlInstances) {
         for (String aidlInstance : aidlInstances) {
-            final String fqName = IFace.DESCRIPTOR + "/" + aidlInstance;
-            IFace face = getIFace.apply(fqName);
-            try {
-                if (face != null) {
-                    mSensorPropsMap.put(aidlInstance, face.getSensorProps());
-                } else {
-                    Slog.e(TAG, "Unable to get declared service: " + fqName);
-                }
-            } catch (RemoteException e) {
-                Log.d(TAG, "Unable to get sensor properties!");
-            }
+            mSensorPropsMap.put(aidlInstance, null);
         }
     }
 
@@ -131,38 +119,31 @@
     }
 
     /**
-     * Return sensor props for the given instance. If instance is not available,
-     * then null is returned.
+     * Checks if {@param instance} exists.
      */
     @Nullable
-    public Pair<String, SensorProps[]> getSensorPairForInstance(String instance) {
-        if (mSensorPropsMap.containsKey(instance)) {
-            return new Pair<>(instance, mSensorPropsMap.get(instance));
-        }
-
-        return null;
+    public boolean doesInstanceExist(String instance) {
+        return mSensorPropsMap.containsKey(instance);
     }
 
     /**
-     * Return the first pair of instance and sensor props, which does not correspond to the given
-     * If instance is not available, then null is returned.
+     * Return the first HAL instance, which does not correspond to the given {@param instance}.
+     * If another instance is not available, then null is returned.
      */
     @Nullable
-    public Pair<String, SensorProps[]> getSensorPairNotForInstance(String instance) {
+    public String getSensorNameNotForInstance(String instance) {
         Optional<String> notAVirtualInstance = mSensorPropsMap.keySet().stream().filter(
                 (instanceName) -> !instanceName.equals(instance)).findFirst();
-        return notAVirtualInstance.map(this::getSensorPairForInstance).orElseGet(
-                this::getSensorPair);
+        return notAVirtualInstance.orElse(null);
     }
 
     /**
-     * Returns the first pair of instance and sensor props that has been added to the map.
+     * Returns the first instance that has been added to the map.
      */
     @Nullable
-    public Pair<String, SensorProps[]> getSensorPair() {
+    public String getSensorInstance() {
         Optional<String> optionalInstance = mSensorPropsMap.keySet().stream().findFirst();
-        return optionalInstance.map(this::getSensorPairForInstance).orElse(null);
-
+        return optionalInstance.orElse(null);
     }
 
     public boolean getResetLockoutRequiresChallenge() {
@@ -179,4 +160,31 @@
         dest.writeByte((byte) (mResetLockoutRequiresChallenge ? 1 : 0));
         dest.writeMap(mSensorPropsMap);
     }
+
+    /**
+     * Returns face sensor props for the HAL {@param instance}.
+     */
+    @Nullable
+    public SensorProps[] getSensorPropForInstance(String instance) {
+        SensorProps[] props = mSensorPropsMap.get(instance);
+
+        //Props should not be null for HIDL configs
+        if (props != null) {
+            return props;
+        }
+
+        final String fqName = IFace.DESCRIPTOR + "/" + instance;
+        IFace face = IFace.Stub.asInterface(Binder.allowBlocking(
+                ServiceManager.waitForDeclaredService(fqName)));
+        try {
+            if (face != null) {
+                props = face.getSensorProps();
+            } else {
+                Slog.e(TAG, "Unable to get declared service: " + fqName);
+            }
+        } catch (RemoteException e) {
+            Log.d(TAG, "Unable to get sensor properties!");
+        }
+        return props;
+    }
 }
diff --git a/core/java/android/hardware/fingerprint/FingerprintSensorConfigurations.java b/core/java/android/hardware/fingerprint/FingerprintSensorConfigurations.java
index f214494a..43c0da9 100644
--- a/core/java/android/hardware/fingerprint/FingerprintSensorConfigurations.java
+++ b/core/java/android/hardware/fingerprint/FingerprintSensorConfigurations.java
@@ -23,18 +23,18 @@
 import android.content.Context;
 import android.hardware.biometrics.fingerprint.IFingerprint;
 import android.hardware.biometrics.fingerprint.SensorProps;
+import android.os.Binder;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.util.Log;
-import android.util.Pair;
 
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
-import java.util.function.Function;
 
 /**
  * Provides the sensor props for fingerprint sensor, if available.
@@ -68,23 +68,10 @@
     /**
      * Process AIDL instances to extract sensor props and add it to the sensor map.
      * @param aidlInstances available face AIDL instances
-     * @param getIFingerprint function that provides the daemon for the specific instance
      */
-    public void addAidlSensors(@NonNull String[] aidlInstances,
-            @NonNull Function<String, IFingerprint> getIFingerprint) {
+    public void addAidlSensors(@NonNull String[] aidlInstances) {
         for (String aidlInstance : aidlInstances) {
-            try {
-                final String fqName = IFingerprint.DESCRIPTOR + "/" + aidlInstance;
-                final IFingerprint fp = getIFingerprint.apply(fqName);
-                if (fp != null) {
-                    SensorProps[] props = fp.getSensorProps();
-                    mSensorPropsMap.put(aidlInstance, props);
-                } else {
-                    Log.d(TAG, "IFingerprint null for instance " + aidlInstance);
-                }
-            } catch (RemoteException e) {
-                Log.d(TAG, "Unable to get sensor properties!");
-            }
+            mSensorPropsMap.put(aidlInstance, null);
         }
     }
 
@@ -133,38 +120,31 @@
     }
 
     /**
-     * Return sensor props for the given instance. If instance is not available,
-     * then null is returned.
+     * Checks if {@param instance} exists.
      */
     @Nullable
-    public Pair<String, SensorProps[]> getSensorPairForInstance(String instance) {
-        if (mSensorPropsMap.containsKey(instance)) {
-            return new Pair<>(instance, mSensorPropsMap.get(instance));
-        }
-
-        return null;
+    public boolean doesInstanceExist(String instance) {
+        return mSensorPropsMap.containsKey(instance);
     }
 
     /**
-     * Return the first pair of instance and sensor props, which does not correspond to the given
-     * If instance is not available, then null is returned.
+     * Return the first HAL instance, which does not correspond to the given {@param instance}.
+     * If another instance is not available, then null is returned.
      */
     @Nullable
-    public Pair<String, SensorProps[]> getSensorPairNotForInstance(String instance) {
+    public String getSensorNameNotForInstance(String instance) {
         Optional<String> notAVirtualInstance = mSensorPropsMap.keySet().stream().filter(
                 (instanceName) -> !instanceName.equals(instance)).findFirst();
-        return notAVirtualInstance.map(this::getSensorPairForInstance).orElseGet(
-                this::getSensorPair);
+        return notAVirtualInstance.orElse(null);
     }
 
     /**
-     * Returns the first pair of instance and sensor props that has been added to the map.
+     * Returns the first instance that has been added to the map.
      */
     @Nullable
-    public Pair<String, SensorProps[]> getSensorPair() {
+    public String getSensorInstance() {
         Optional<String> optionalInstance = mSensorPropsMap.keySet().stream().findFirst();
-        return optionalInstance.map(this::getSensorPairForInstance).orElse(null);
-
+        return optionalInstance.orElse(null);
     }
 
     public boolean getResetLockoutRequiresHardwareAuthToken() {
@@ -181,4 +161,31 @@
         dest.writeByte((byte) (mResetLockoutRequiresHardwareAuthToken ? 1 : 0));
         dest.writeMap(mSensorPropsMap);
     }
+
+    /**
+     * Returns fingerprint sensor props for the HAL {@param instance}.
+     */
+    @Nullable
+    public SensorProps[] getSensorPropForInstance(String instance) {
+        SensorProps[] props = mSensorPropsMap.get(instance);
+
+        //Props should not be null for HIDL configs
+        if (props != null) {
+            return props;
+        }
+
+        try {
+            final String fqName = IFingerprint.DESCRIPTOR + "/" + instance;
+            final IFingerprint fp = IFingerprint.Stub.asInterface(Binder.allowBlocking(
+                    ServiceManager.waitForDeclaredService(fqName)));
+            if (fp != null) {
+                props = fp.getSensorProps();
+            } else {
+                Log.d(TAG, "IFingerprint null for instance " + instance);
+            }
+        } catch (RemoteException e) {
+            Log.d(TAG, "Unable to get sensor properties!");
+        }
+        return props;
+    }
 }
diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig
index 2710df2..3e4454f 100644
--- a/core/java/android/permission/flags.aconfig
+++ b/core/java/android/permission/flags.aconfig
@@ -116,6 +116,15 @@
 }
 
 flag {
+  name: "sensitive_content_improvements"
+  namespace: "permissions"
+  description: "Improvements to sensitive content/notification features, such as the Toast UX."
+  bug: "301960090"
+  # Referenced in WM where WM starts before DeviceConfig
+  is_fixed_read_only: true
+}
+
+flag {
     name: "device_aware_permissions_enabled"
     is_fixed_read_only: true
     namespace: "permissions"
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 363e252..d91b051 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -12451,7 +12451,7 @@
         /** @hide */
         public static final int PRIVATE_SPACE_AUTO_LOCK_AFTER_INACTIVITY = 1;
         /** @hide */
-        public static final int PRIVATE_SPACE_AUTO_LOCK_NEVER = 2;
+        public static final int PRIVATE_SPACE_AUTO_LOCK_AFTER_DEVICE_RESTART = 2;
 
         /**
          * The different auto lock options for private space.
@@ -12461,7 +12461,7 @@
         @IntDef(prefix = {"PRIVATE_SPACE_AUTO_LOCK_"}, value = {
                 PRIVATE_SPACE_AUTO_LOCK_ON_DEVICE_LOCK,
                 PRIVATE_SPACE_AUTO_LOCK_AFTER_INACTIVITY,
-                PRIVATE_SPACE_AUTO_LOCK_NEVER,
+                PRIVATE_SPACE_AUTO_LOCK_AFTER_DEVICE_RESTART,
         })
         @Retention(RetentionPolicy.SOURCE)
         public @interface PrivateSpaceAutoLockOption {
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 6dcbc8e..4e521d6 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -1050,12 +1050,10 @@
                     overlay.endDream();
                     mOverlayConnection.unbind();
                     mOverlayConnection = null;
-                    finish();
                 } catch (RemoteException e) {
                     Log.e(mTag, "could not inform overlay of dream end:" + e);
                 }
             });
-            return;
         }
 
         if (mDebug) Slog.v(mTag, "finish(): mFinished=" + mFinished);
diff --git a/core/java/android/service/quickaccesswallet/QuickAccessWalletServiceInfo.java b/core/java/android/service/quickaccesswallet/QuickAccessWalletServiceInfo.java
index e6d8fd0..8a3f6ce 100644
--- a/core/java/android/service/quickaccesswallet/QuickAccessWalletServiceInfo.java
+++ b/core/java/android/service/quickaccesswallet/QuickAccessWalletServiceInfo.java
@@ -71,9 +71,11 @@
 
     @Nullable
     static QuickAccessWalletServiceInfo tryCreate(@NonNull Context context) {
-        String defaultAppPackageName = getDefaultWalletApp(context);
+        String defaultAppPackageName = null;
 
-        if (defaultAppPackageName == null) {
+        if (isWalletRoleAvailable(context)) {
+            defaultAppPackageName = getDefaultWalletApp(context);
+        } else {
             ComponentName defaultPaymentApp = getDefaultPaymentApp(context);
             if (defaultPaymentApp == null) {
                 return null;
@@ -103,14 +105,21 @@
         final long token = Binder.clearCallingIdentity();
         try {
             RoleManager roleManager = context.getSystemService(RoleManager.class);
-            if (roleManager.isRoleAvailable(RoleManager.ROLE_WALLET)) {
-                List<String> roleHolders = roleManager.getRoleHolders(RoleManager.ROLE_WALLET);
-                return roleHolders.isEmpty() ? null : roleHolders.get(0);
-            }
+            List<String> roleHolders = roleManager.getRoleHolders(RoleManager.ROLE_WALLET);
+            return roleHolders.isEmpty() ? null : roleHolders.get(0);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
-        return null;
+    }
+
+    private static boolean isWalletRoleAvailable(Context context) {
+        final long token = Binder.clearCallingIdentity();
+        try {
+            RoleManager roleManager = context.getSystemService(RoleManager.class);
+            return roleManager.isRoleAvailable(RoleManager.ROLE_WALLET);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 
     private static ComponentName getDefaultPaymentApp(Context context) {
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index 147d562..17d1404 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -16,8 +16,10 @@
 
 package android.view;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.TestApi;
 import android.annotation.XmlRes;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
@@ -39,6 +41,7 @@
 import android.os.PointerIconType;
 import android.util.Log;
 import android.util.SparseArray;
+import android.view.flags.Flags;
 
 import com.android.internal.util.XmlUtils;
 
@@ -637,4 +640,15 @@
             default: return Integer.toString(type);
         }
     }
+
+    /**
+     * Sets whether drop shadow will draw in the native code.
+     *
+     * @hide
+     */
+    @TestApi
+    @FlaggedApi(Flags.FLAG_ENABLE_VECTOR_CURSORS)
+    public void setDrawNativeDropShadow(boolean drawNativeDropShadow) {
+        mDrawNativeDropShadow = drawNativeDropShadow;
+    }
 }
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
index c70febb..34b487f 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
@@ -37,7 +37,6 @@
 import android.view.Window;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.Flags;
 import android.widget.AdapterView;
 
 import com.android.internal.R;
@@ -248,12 +247,10 @@
 
         boolean allowEditing = isUserSetupCompleted(this);
         boolean showWhenLocked = false;
-        if (Flags.allowShortcutChooserOnLockscreen()) {
-            final KeyguardManager keyguardManager = getSystemService(KeyguardManager.class);
-            if (keyguardManager != null && keyguardManager.isKeyguardLocked()) {
-                allowEditing = false;
-                showWhenLocked = true;
-            }
+        final KeyguardManager keyguardManager = getSystemService(KeyguardManager.class);
+        if (keyguardManager != null && keyguardManager.isKeyguardLocked()) {
+            allowEditing = false;
+            showWhenLocked = true;
         }
         if (allowEditing) {
             final String positiveButtonText =
diff --git a/core/java/com/android/internal/os/BinderInternal.java b/core/java/com/android/internal/os/BinderInternal.java
index c14d8d8..8063be6 100644
--- a/core/java/com/android/internal/os/BinderInternal.java
+++ b/core/java/com/android/internal/os/BinderInternal.java
@@ -45,8 +45,8 @@
     static ArrayList<Runnable> sGcWatchers = new ArrayList<>();
     static Runnable[] sTmpWatchers = new Runnable[1];
     static long sLastGcTime;
-    static final BinderProxyLimitListenerDelegate sBinderProxyLimitListenerDelegate =
-            new BinderProxyLimitListenerDelegate();
+    static final BinderProxyCountEventListenerDelegate sBinderProxyCountEventListenerDelegate =
+            new BinderProxyCountEventListenerDelegate();
 
     static final class GcWatcher {
         @Override
@@ -226,15 +226,24 @@
      * @param low   The threshold a binder count must drop below before the callback
      *              can be called again. (This is to avoid many repeated calls to the
      *              callback in a brief period of time)
+     * @param warning The threshold between {@code high} and {@code low} where if the binder count
+     *                exceeds that, the warning callback would be triggered.
      */
-    public static final native void nSetBinderProxyCountWatermarks(int high, int low);
+    public static final native void nSetBinderProxyCountWatermarks(int high, int low, int warning);
 
     /**
      * Interface for callback invocation when the Binder Proxy limit is reached. onLimitReached will
      * be called with the uid of the app causing too many Binder Proxies
      */
-    public interface BinderProxyLimitListener {
+    public interface BinderProxyCountEventListener {
         public void onLimitReached(int uid);
+
+        /**
+         * Call when the number of binder proxies from the uid of the app reaches
+         * the warning threshold.
+         */
+        default void onWarningThresholdReached(int uid) {
+        }
     }
 
     /**
@@ -243,7 +252,17 @@
      * @param uid The uid of the bad behaving app sending too many binders
      */
     public static void binderProxyLimitCallbackFromNative(int uid) {
-       sBinderProxyLimitListenerDelegate.notifyClient(uid);
+        sBinderProxyCountEventListenerDelegate.notifyLimitReached(uid);
+    }
+
+    /**
+     * Callback used by native code to trigger a callback in java code. The callback will be
+     * triggered when too many binder proxies from a uid hits the warning limit.
+     * @param uid The uid of the bad behaving app sending too many binders
+     */
+    @SuppressWarnings("unused")
+    public static void binderProxyWarningCallbackFromNative(int uid) {
+        sBinderProxyCountEventListenerDelegate.notifyWarningReached(uid);
     }
 
     /**
@@ -252,41 +271,45 @@
      * @param handler must not be null, callback will be posted through the handler;
      *
      */
-    public static void setBinderProxyCountCallback(BinderProxyLimitListener listener,
+    public static void setBinderProxyCountCallback(BinderProxyCountEventListener listener,
             @NonNull Handler handler) {
         Preconditions.checkNotNull(handler,
                 "Must provide NonNull Handler to setBinderProxyCountCallback when setting "
-                        + "BinderProxyLimitListener");
-        sBinderProxyLimitListenerDelegate.setListener(listener, handler);
+                        + "BinderProxyCountEventListener");
+        sBinderProxyCountEventListenerDelegate.setListener(listener, handler);
     }
 
     /**
      * Clear the Binder Proxy callback
      */
     public static void clearBinderProxyCountCallback() {
-        sBinderProxyLimitListenerDelegate.setListener(null, null);
+        sBinderProxyCountEventListenerDelegate.setListener(null, null);
     }
 
-    static private class BinderProxyLimitListenerDelegate {
-        private BinderProxyLimitListener mBinderProxyLimitListener;
+    private static class BinderProxyCountEventListenerDelegate {
+        private BinderProxyCountEventListener mBinderProxyCountEventListener;
         private Handler mHandler;
 
-        void setListener(BinderProxyLimitListener listener, Handler handler) {
+        void setListener(BinderProxyCountEventListener listener, Handler handler) {
             synchronized (this) {
-                mBinderProxyLimitListener = listener;
+                mBinderProxyCountEventListener = listener;
                 mHandler = handler;
             }
         }
 
-        void notifyClient(final int uid) {
+        void notifyLimitReached(final int uid) {
             synchronized (this) {
-                if (mBinderProxyLimitListener != null) {
-                    mHandler.post(new Runnable() {
-                        @Override
-                        public void run() {
-                            mBinderProxyLimitListener.onLimitReached(uid);
-                        }
-                    });
+                if (mBinderProxyCountEventListener != null) {
+                    mHandler.post(() -> mBinderProxyCountEventListener.onLimitReached(uid));
+                }
+            }
+        }
+
+        void notifyWarningReached(final int uid) {
+            synchronized (this) {
+                if (mBinderProxyCountEventListener != null) {
+                    mHandler.post(() ->
+                            mBinderProxyCountEventListener.onWarningThresholdReached(uid));
                 }
             }
         }
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index d2d5186..2068bd7 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -88,6 +88,7 @@
     jclass mClass;
     jmethodID mForceGc;
     jmethodID mProxyLimitCallback;
+    jmethodID mProxyWarningCallback;
 
 } gBinderInternalOffsets;
 
@@ -1240,7 +1241,7 @@
     gCollectedAtRefs = gNumLocalRefsCreated + gNumDeathRefsCreated;
 }
 
-static void android_os_BinderInternal_proxyLimitcallback(int uid)
+static void android_os_BinderInternal_proxyLimitCallback(int uid)
 {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     env->CallStaticVoidMethod(gBinderInternalOffsets.mClass,
@@ -1254,6 +1255,20 @@
     }
 }
 
+static void android_os_BinderInternal_proxyWarningCallback(int uid)
+{
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    env->CallStaticVoidMethod(gBinderInternalOffsets.mClass,
+                              gBinderInternalOffsets.mProxyWarningCallback,
+                              uid);
+
+    if (env->ExceptionCheck()) {
+        ScopedLocalRef<jthrowable> excep(env, env->ExceptionOccurred());
+        binder_report_exception(env, excep.get(),
+                                "*** Uncaught exception in binderProxyWarningCallbackFromNative");
+    }
+}
+
 static void android_os_BinderInternal_setBinderProxyCountEnabled(JNIEnv* env, jobject clazz,
                                                                  jboolean enable)
 {
@@ -1278,9 +1293,10 @@
 }
 
 static void android_os_BinderInternal_setBinderProxyCountWatermarks(JNIEnv* env, jobject clazz,
-                                                                    jint high, jint low)
+                                                                    jint high, jint low,
+                                                                    jint warning)
 {
-    BpBinder::setBinderProxyCountWatermarks(high, low);
+    BpBinder::setBinderProxyCountWatermarks(high, low, warning);
 }
 
 // ----------------------------------------------------------------------------
@@ -1295,7 +1311,7 @@
     { "nSetBinderProxyCountEnabled", "(Z)V", (void*)android_os_BinderInternal_setBinderProxyCountEnabled },
     { "nGetBinderProxyPerUidCounts", "()Landroid/util/SparseIntArray;", (void*)android_os_BinderInternal_getBinderProxyPerUidCounts },
     { "nGetBinderProxyCount", "(I)I", (void*)android_os_BinderInternal_getBinderProxyCount },
-    { "nSetBinderProxyCountWatermarks", "(II)V", (void*)android_os_BinderInternal_setBinderProxyCountWatermarks}
+    { "nSetBinderProxyCountWatermarks", "(III)V", (void*)android_os_BinderInternal_setBinderProxyCountWatermarks}
 };
 
 const char* const kBinderInternalPathName = "com/android/internal/os/BinderInternal";
@@ -1307,6 +1323,8 @@
     gBinderInternalOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
     gBinderInternalOffsets.mForceGc = GetStaticMethodIDOrDie(env, clazz, "forceBinderGc", "()V");
     gBinderInternalOffsets.mProxyLimitCallback = GetStaticMethodIDOrDie(env, clazz, "binderProxyLimitCallbackFromNative", "(I)V");
+    gBinderInternalOffsets.mProxyWarningCallback =
+        GetStaticMethodIDOrDie(env, clazz, "binderProxyWarningCallbackFromNative", "(I)V");
 
     jclass SparseIntArrayClass = FindClassOrDie(env, "android/util/SparseIntArray");
     gSparseIntArrayOffsets.classObject = MakeGlobalRefOrDie(env, SparseIntArrayClass);
@@ -1315,7 +1333,8 @@
     gSparseIntArrayOffsets.put = GetMethodIDOrDie(env, gSparseIntArrayOffsets.classObject, "put",
                                                    "(II)V");
 
-    BpBinder::setLimitCallback(android_os_BinderInternal_proxyLimitcallback);
+    BpBinder::setBinderProxyCountEventCallback(android_os_BinderInternal_proxyLimitCallback,
+                                               android_os_BinderInternal_proxyWarningCallback);
 
     return RegisterMethodsOrDie(
         env, kBinderInternalPathName,
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 24031cad..4808204 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -134,6 +134,8 @@
         ":BinderDeathRecipientHelperApp1",
         ":BinderDeathRecipientHelperApp2",
         ":com.android.cts.helpers.aosp",
+        ":BinderProxyCountingTestApp",
+        ":BinderProxyCountingTestService",
     ],
 }
 
diff --git a/core/tests/coretests/AndroidTest.xml b/core/tests/coretests/AndroidTest.xml
index 05b309b..bf2a5b8 100644
--- a/core/tests/coretests/AndroidTest.xml
+++ b/core/tests/coretests/AndroidTest.xml
@@ -22,6 +22,8 @@
         <option name="test-file-name" value="FrameworksCoreTests.apk" />
         <option name="test-file-name" value="BinderDeathRecipientHelperApp1.apk" />
         <option name="test-file-name" value="BinderDeathRecipientHelperApp2.apk" />
+        <option name="test-file-name" value="BinderProxyCountingTestApp.apk" />
+        <option name="test-file-name" value="BinderProxyCountingTestService.apk" />
     </target_preparer>
 
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
diff --git a/core/tests/coretests/BinderProxyCountingTestApp/AndroidManifest.xml b/core/tests/coretests/BinderProxyCountingTestApp/AndroidManifest.xml
index a971730..c8407b8 100644
--- a/core/tests/coretests/BinderProxyCountingTestApp/AndroidManifest.xml
+++ b/core/tests/coretests/BinderProxyCountingTestApp/AndroidManifest.xml
@@ -16,6 +16,9 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.android.frameworks.coretests.binderproxycountingtestapp">
 
+    <queries>
+        <package android:name="com.android.frameworks.coretests.binderproxycountingtestservice" />
+    </queries>
     <application>
         <service android:name=".BpcTestAppCmdService"
                  android:exported="true"/>
diff --git a/core/tests/coretests/BinderProxyCountingTestApp/src/com/android/frameworks/coretests/binderproxycountingtestapp/BpcTestAppCmdService.java b/core/tests/coretests/BinderProxyCountingTestApp/src/com/android/frameworks/coretests/binderproxycountingtestapp/BpcTestAppCmdService.java
index 5aae1203..a7e97d3 100644
--- a/core/tests/coretests/BinderProxyCountingTestApp/src/com/android/frameworks/coretests/binderproxycountingtestapp/BpcTestAppCmdService.java
+++ b/core/tests/coretests/BinderProxyCountingTestApp/src/com/android/frameworks/coretests/binderproxycountingtestapp/BpcTestAppCmdService.java
@@ -17,14 +17,15 @@
 package com.android.frameworks.coretests.binderproxycountingtestapp;
 
 import android.app.Service;
-import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.ServiceConnection;
+import android.database.ContentObserver;
+import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.provider.Settings;
 import android.util.Log;
 
 import com.android.frameworks.coretests.aidl.IBinderProxyCountingService;
@@ -49,24 +50,20 @@
 
     private IBpcTestAppCmdService.Stub mBinder = new IBpcTestAppCmdService.Stub() {
 
-        private ArrayList<BroadcastReceiver> mBrList = new ArrayList();
+        private ArrayList<ContentObserver> mCoList = new ArrayList();
         private ArrayList<ITestRemoteCallback> mTrcList = new ArrayList();
+        private Handler mHandler = new Handler();
 
         @Override
         public void createSystemBinders(int count) {
             int i = 0;
             while (i++ < count) {
-                BroadcastReceiver br = new BroadcastReceiver() {
-                    @Override
-                    public void onReceive(Context context, Intent intent) {
-
-                    }
-                };
-                IntentFilter filt = new IntentFilter(Intent.ACTION_POWER_DISCONNECTED);
-                synchronized (mBrList) {
-                    mBrList.add(br);
+                final ContentObserver co = new ContentObserver(mHandler) {};
+                synchronized (mCoList) {
+                    mCoList.add(co);
                 }
-                registerReceiver(br, filt);
+                getContentResolver().registerContentObserver(
+                        Settings.System.CONTENT_URI, false, co);
             }
         }
 
@@ -74,11 +71,11 @@
         public void releaseSystemBinders(int count) {
             int i = 0;
             while (i++ < count) {
-                BroadcastReceiver br;
-                synchronized (mBrList) {
-                    br = mBrList.remove(0);
+                ContentObserver co;
+                synchronized (mCoList) {
+                    co = mCoList.remove(0);
                 }
-                unregisterReceiver(br);
+                getContentResolver().unregisterContentObserver(co);
             }
         }
 
@@ -117,9 +114,9 @@
 
         @Override
         public void releaseAllBinders() {
-            synchronized (mBrList) {
-                while (mBrList.size() > 0) {
-                    unregisterReceiver(mBrList.remove(0));
+            synchronized (mCoList) {
+                while (mCoList.size() > 0) {
+                    getContentResolver().unregisterContentObserver(mCoList.remove(0));
                 }
             }
             synchronized (mTrcList) {
@@ -179,4 +176,4 @@
     public IBinder onBind(Intent intent) {
         return mBinder;
     }
-}
\ No newline at end of file
+}
diff --git a/core/tests/coretests/BinderProxyCountingTestService/src/com/android/frameworks/coretests/binderproxycountingtestservice/BpcTestServiceCmdService.java b/core/tests/coretests/BinderProxyCountingTestService/src/com/android/frameworks/coretests/binderproxycountingtestservice/BpcTestServiceCmdService.java
index 6bed2a2..0f1accc 100644
--- a/core/tests/coretests/BinderProxyCountingTestService/src/com/android/frameworks/coretests/binderproxycountingtestservice/BpcTestServiceCmdService.java
+++ b/core/tests/coretests/BinderProxyCountingTestService/src/com/android/frameworks/coretests/binderproxycountingtestservice/BpcTestServiceCmdService.java
@@ -55,8 +55,8 @@
         }
 
         @Override
-        public void setBinderProxyWatermarks(int high, int low) {
-            BinderInternal.nSetBinderProxyCountWatermarks(high, low);
+        public void setBinderProxyWatermarks(int high, int low, int warning) {
+            BinderInternal.nSetBinderProxyCountWatermarks(high, low, warning);
         }
 
         @Override
@@ -68,12 +68,23 @@
         public void setBinderProxyCountCallback(IBpcCallbackObserver observer) {
             if (observer != null) {
                 BinderInternal.setBinderProxyCountCallback(
-                        new BinderInternal.BinderProxyLimitListener() {
+                        new BinderInternal.BinderProxyCountEventListener() {
                             @Override
                             public void onLimitReached(int uid) {
                                 try {
                                     synchronized (observer) {
-                                        observer.onCallback(uid);
+                                        observer.onLimitReached(uid);
+                                    }
+                                } catch (Exception e) {
+                                    Log.e(TAG, e.toString());
+                                }
+                            }
+
+                            @Override
+                            public void onWarningThresholdReached(int uid) {
+                                try {
+                                    synchronized (observer) {
+                                        observer.onWarningThresholdReached(uid);
                                     }
                                 } catch (Exception e) {
                                     Log.e(TAG, e.toString());
@@ -98,4 +109,4 @@
         mHandlerThread.start();
         mHandler = new Handler(mHandlerThread.getLooper());
     }
-}
\ No newline at end of file
+}
diff --git a/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcCallbackObserver.aidl b/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcCallbackObserver.aidl
index c4ebd56..ada7d92 100644
--- a/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcCallbackObserver.aidl
+++ b/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcCallbackObserver.aidl
@@ -17,5 +17,6 @@
 package com.android.frameworks.coretests.aidl;
 
 interface IBpcCallbackObserver {
-    void onCallback(int uid);
-}
\ No newline at end of file
+    void onLimitReached(int uid);
+    void onWarningThresholdReached(int uid);
+}
diff --git a/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcTestServiceCmdService.aidl b/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcTestServiceCmdService.aidl
index abdab41..cdcda9d 100644
--- a/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcTestServiceCmdService.aidl
+++ b/core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/IBpcTestServiceCmdService.aidl
@@ -20,7 +20,7 @@
 interface IBpcTestServiceCmdService {
    void forceGc();
    int getBinderProxyCount(int uid);
-   void setBinderProxyWatermarks(int high, int low);
+   void setBinderProxyWatermarks(int high, int low, int warning);
    void enableBinderProxyLimit(boolean enable);
    void setBinderProxyCountCallback(IBpcCallbackObserver observer);
-}
\ No newline at end of file
+}
diff --git a/core/tests/coretests/src/android/hardware/face/FaceSensorConfigurationsTest.java b/core/tests/coretests/src/android/hardware/face/FaceSensorConfigurationsTest.java
index b61104d..7d7f8ed 100644
--- a/core/tests/coretests/src/android/hardware/face/FaceSensorConfigurationsTest.java
+++ b/core/tests/coretests/src/android/hardware/face/FaceSensorConfigurationsTest.java
@@ -18,13 +18,10 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.content.res.Resources;
-import android.hardware.biometrics.face.IFace;
-import android.hardware.biometrics.face.SensorProps;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
 
@@ -37,8 +34,6 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
-import java.util.function.Function;
-
 @Presubmit
 @SmallTest
 public class FaceSensorConfigurationsTest {
@@ -48,10 +43,6 @@
     private Context mContext;
     @Mock
     private Resources mResources;
-    @Mock
-    private IFace mFace;
-    @Mock
-    private Function<String, IFace> mGetIFace;
 
     private final String[] mAidlInstances = new String[]{"default", "virtual"};
     private String[] mHidlConfigStrings = new String[]{"0:2:15", "0:8:15"};
@@ -59,15 +50,13 @@
 
     @Before
     public void setUp() throws RemoteException {
-        when(mGetIFace.apply(anyString())).thenReturn(mFace);
-        when(mFace.getSensorProps()).thenReturn(new SensorProps[]{});
         when(mContext.getResources()).thenReturn(mResources);
     }
 
     @Test
     public void testAidlInstanceSensorProps() {
         mFaceSensorConfigurations = new FaceSensorConfigurations(false);
-        mFaceSensorConfigurations.addAidlConfigs(mAidlInstances, mGetIFace);
+        mFaceSensorConfigurations.addAidlConfigs(mAidlInstances);
 
         assertThat(mFaceSensorConfigurations.hasSensorConfigurations()).isTrue();
         assertThat(!mFaceSensorConfigurations.isSingleSensorConfigurationPresent()).isTrue();
diff --git a/core/tests/coretests/src/android/hardware/fingerprint/FingerprintSensorConfigurationsTest.java b/core/tests/coretests/src/android/hardware/fingerprint/FingerprintSensorConfigurationsTest.java
index f058c16..b2f8299 100644
--- a/core/tests/coretests/src/android/hardware/fingerprint/FingerprintSensorConfigurationsTest.java
+++ b/core/tests/coretests/src/android/hardware/fingerprint/FingerprintSensorConfigurationsTest.java
@@ -18,13 +18,10 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.content.res.Resources;
-import android.hardware.biometrics.fingerprint.IFingerprint;
-import android.hardware.biometrics.fingerprint.SensorProps;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
 
@@ -37,8 +34,6 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
-import java.util.function.Function;
-
 @Presubmit
 @SmallTest
 public class FingerprintSensorConfigurationsTest {
@@ -48,10 +43,6 @@
     private Context mContext;
     @Mock
     private Resources mResources;
-    @Mock
-    private IFingerprint mFingerprint;
-    @Mock
-    private Function<String, IFingerprint> mGetIFingerprint;
 
     private final String[] mAidlInstances = new String[]{"default", "virtual"};
     private String[] mHidlConfigStrings = new String[]{"0:2:15", "0:8:15"};
@@ -59,8 +50,6 @@
 
     @Before
     public void setUp() throws RemoteException {
-        when(mGetIFingerprint.apply(anyString())).thenReturn(mFingerprint);
-        when(mFingerprint.getSensorProps()).thenReturn(new SensorProps[]{});
         when(mContext.getResources()).thenReturn(mResources);
     }
 
@@ -68,7 +57,7 @@
     public void testAidlInstanceSensorProps() {
         mFingerprintSensorConfigurations = new FingerprintSensorConfigurations(
                 true /* resetLockoutRequiresHardwareAuthToken */);
-        mFingerprintSensorConfigurations.addAidlSensors(mAidlInstances, mGetIFingerprint);
+        mFingerprintSensorConfigurations.addAidlSensors(mAidlInstances);
 
         assertThat(mFingerprintSensorConfigurations.hasSensorConfigurations()).isTrue();
         assertThat(!mFingerprintSensorConfigurations.isSingleSensorConfigurationPresent())
diff --git a/core/tests/coretests/src/android/os/BinderProxyCountingTest.java b/core/tests/coretests/src/android/os/BinderProxyCountingTest.java
index bcd9521..84d2995 100644
--- a/core/tests/coretests/src/android/os/BinderProxyCountingTest.java
+++ b/core/tests/coretests/src/android/os/BinderProxyCountingTest.java
@@ -88,9 +88,10 @@
 
     private static final int BIND_SERVICE_TIMEOUT_SEC = 5;
     private static final int TOO_MANY_BINDERS_TIMEOUT_SEC = 2;
+    private static final int TOO_MANY_BINDERS_WITH_KILL_TIMEOUT_SEC = 30;
 
-    // Keep in sync with sBinderProxyCountLimit in BpBinder.cpp
-    private static final int BINDER_PROXY_LIMIT = 2500;
+    // Keep in sync with BINDER_PROXY_HIGH_WATERMARK in ActivityManagerService.java
+    private static final int BINDER_PROXY_LIMIT = 6000;
 
     private static Context sContext;
     private static UiDevice sUiDevice;
@@ -175,18 +176,26 @@
         }
     }
 
-    private CountDownLatch createBinderLimitLatch() throws RemoteException {
-        final CountDownLatch latch = new CountDownLatch(1);
+    private CountDownLatch[] createBinderLimitLatch() throws RemoteException {
+        final CountDownLatch[] latches = new CountDownLatch[] {
+            new CountDownLatch(1), new CountDownLatch(1)
+        };
         sBpcTestServiceCmdService.setBinderProxyCountCallback(
                 new IBpcCallbackObserver.Stub() {
                     @Override
-                    public void onCallback(int uid) {
+                    public void onLimitReached(int uid) {
                         if (uid == sTestPkgUid) {
-                            latch.countDown();
+                            latches[0].countDown();
+                        }
+                    }
+                    @Override
+                    public void onWarningThresholdReached(int uid) {
+                        if (uid == sTestPkgUid) {
+                            latches[1].countDown();
                         }
                     }
                 });
-        return latch;
+        return latches;
     }
 
     /**
@@ -227,6 +236,7 @@
     @Test
     public void testBinderProxyLimitBoundary() throws Exception {
         final int binderProxyLimit = 2000;
+        final int binderProxyWarning = 1900;
         final int rearmThreshold = 1800;
         try {
             sTestAppConnection = bindService(sTestAppConsumer, sTestAppIntent);
@@ -238,19 +248,33 @@
             // Get the baseline of binders naturally held by the test Package
             int baseBinderCount = sBpcTestServiceCmdService.getBinderProxyCount(sTestPkgUid);
 
-            final CountDownLatch binderLimitLatch = createBinderLimitLatch();
-            sBpcTestServiceCmdService.setBinderProxyWatermarks(binderProxyLimit, rearmThreshold);
+            final CountDownLatch[] binderLatches = createBinderLimitLatch();
+            sBpcTestServiceCmdService.setBinderProxyWatermarks(binderProxyLimit, rearmThreshold,
+                    binderProxyWarning);
+
+            // Create Binder Proxies up to the warning;
+            sBpcTestAppCmdService.createTestBinders(binderProxyWarning - baseBinderCount);
+            if (binderLatches[1].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+                fail("Received BinderProxyLimitCallback for uid " + sTestPkgUid
+                        + " when proxy warning should not have been triggered");
+            }
+
+            // Create one more Binder to trigger the warning
+            sBpcTestAppCmdService.createTestBinders(1);
+            if (!binderLatches[1].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+                fail("Timed out waiting for uid " + sTestPkgUid + " to trigger the warning");
+            }
 
             // Create Binder Proxies up to the limit
-            sBpcTestAppCmdService.createTestBinders(binderProxyLimit - baseBinderCount);
-            if (binderLimitLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+            sBpcTestAppCmdService.createTestBinders(binderProxyLimit - binderProxyWarning - 1);
+            if (binderLatches[0].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
                 fail("Received BinderProxyLimitCallback for uid " + sTestPkgUid
                         + " when proxy limit should not have been reached");
             }
 
             // Create one more Binder to cross the limit
             sBpcTestAppCmdService.createTestBinders(1);
-            if (!binderLimitLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+            if (!binderLatches[0].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
                 fail("Timed out waiting for uid " + sTestPkgUid + " to hit limit");
             }
 
@@ -274,12 +298,20 @@
             sBpcTestServiceCmdService.forceGc();
             int baseBinderCount = sBpcTestServiceCmdService.getBinderProxyCount(sTestPkgUid);
             for (int testLimit : testLimits) {
-                final CountDownLatch binderLimitLatch = createBinderLimitLatch();
+                final CountDownLatch[] binderLatches = createBinderLimitLatch();
                 // Change the BinderProxyLimit
-                sBpcTestServiceCmdService.setBinderProxyWatermarks(testLimit, baseBinderCount + 10);
+                sBpcTestServiceCmdService.setBinderProxyWatermarks(testLimit, baseBinderCount + 10,
+                        testLimit - 10);
+
+                // Trigger the new Binder Proxy warning
+                sBpcTestAppCmdService.createTestBinders(testLimit - 9 - baseBinderCount);
+                if (!binderLatches[1].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+                    fail("Timed out waiting for uid " + sTestPkgUid + " to trigger the warning");
+                }
+
                 // Exceed the new Binder Proxy Limit
-                sBpcTestAppCmdService.createTestBinders(testLimit + 1);
-                if (!binderLimitLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+                sBpcTestAppCmdService.createTestBinders(10);
+                if (!binderLatches[0].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
                     fail("Timed out waiting for uid " + sTestPkgUid + " to hit limit");
                 }
 
@@ -297,6 +329,7 @@
     public void testRearmCallbackThreshold() throws Exception {
         final int binderProxyLimit = 2000;
         final int exceedBinderProxyLimit = binderProxyLimit + 10;
+        final int binderProxyWarning = 1900;
         final int rearmThreshold = 1800;
         try {
             sTestAppConnection = bindService(sTestAppConsumer, sTestAppIntent);
@@ -305,11 +338,19 @@
             sBpcTestServiceCmdService.enableBinderProxyLimit(true);
 
             sBpcTestServiceCmdService.forceGc();
-            final CountDownLatch firstBinderLimitLatch = createBinderLimitLatch();
-            sBpcTestServiceCmdService.setBinderProxyWatermarks(binderProxyLimit, rearmThreshold);
+            int baseBinderCount = sBpcTestServiceCmdService.getBinderProxyCount(sTestPkgUid);
+            final CountDownLatch[] firstBinderLatches = createBinderLimitLatch();
+            sBpcTestServiceCmdService.setBinderProxyWatermarks(binderProxyLimit, rearmThreshold,
+                    binderProxyWarning);
+            // Trigger the Binder Proxy Waring
+            sBpcTestAppCmdService.createTestBinders(binderProxyWarning - baseBinderCount + 1);
+            if (!firstBinderLatches[1].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+                fail("Timed out waiting for uid " + sTestPkgUid + " to trigger warning");
+            }
+
             // Exceed the Binder Proxy Limit
-            sBpcTestAppCmdService.createTestBinders(exceedBinderProxyLimit);
-            if (!firstBinderLimitLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+            sBpcTestAppCmdService.createTestBinders(exceedBinderProxyLimit - binderProxyWarning);
+            if (!firstBinderLatches[0].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
                 fail("Timed out waiting for uid " + sTestPkgUid + " to hit limit");
             }
 
@@ -321,11 +362,20 @@
             sBpcTestServiceCmdService.forceGc();
             currentBinderCount = sBpcTestServiceCmdService.getBinderProxyCount(sTestPkgUid);
 
-            final CountDownLatch secondBinderLimitLatch = createBinderLimitLatch();
+            final CountDownLatch[] secondBinderLatches = createBinderLimitLatch();
+
+            // Exceed the Binder Proxy warning which should not cause a callback since there has
+            // been no rearm
+            sBpcTestAppCmdService.createTestBinders(binderProxyWarning - currentBinderCount + 1);
+            if (secondBinderLatches[1].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+                fail("Received BinderProxyLimitCallback for uid " + sTestPkgUid
+                        + " when the callback has not been rearmed yet");
+            }
+
             // Exceed the Binder Proxy limit which should not cause a callback since there has
             // been no rearm
-            sBpcTestAppCmdService.createTestBinders(exceedBinderProxyLimit - currentBinderCount);
-            if (secondBinderLimitLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+            sBpcTestAppCmdService.createTestBinders(exceedBinderProxyLimit - binderProxyWarning);
+            if (secondBinderLatches[0].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
                 fail("Received BinderProxyLimitCallback for uid " + sTestPkgUid
                         + " when the callback has not been rearmed yet");
             }
@@ -337,10 +387,16 @@
 
             sBpcTestServiceCmdService.forceGc();
             currentBinderCount = sBpcTestServiceCmdService.getBinderProxyCount(sTestPkgUid);
+            // Trigger the Binder Proxy Waring
+            sBpcTestAppCmdService.createTestBinders(binderProxyWarning - currentBinderCount + 1);
+            if (!secondBinderLatches[1].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+                fail("Timed out waiting for uid " + sTestPkgUid + " to trigger warning");
+            }
+
             // Exceed the Binder Proxy limit for the last time
             sBpcTestAppCmdService.createTestBinders(exceedBinderProxyLimit - currentBinderCount);
 
-            if (!secondBinderLimitLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+            if (!secondBinderLatches[0].await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
                 fail("Timed out waiting for uid " + sTestPkgUid + " to hit limit");
             }
             sBpcTestAppCmdService.releaseTestBinders(currentBinderCount);
@@ -373,7 +429,7 @@
                 // is not unexpected
             }
 
-            if (!binderDeathLatch.await(TOO_MANY_BINDERS_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+            if (!binderDeathLatch.await(TOO_MANY_BINDERS_WITH_KILL_TIMEOUT_SEC, TimeUnit.SECONDS)) {
                 sBpcTestAppCmdService.releaseSystemBinders(exceedBinderProxyLimit);
                 fail("Timed out waiting for uid " + sTestPkgUid + " to die.");
             }
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
index 745390d..9f5ed29 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutChooserActivityTest.java
@@ -53,7 +53,6 @@
 import android.content.pm.ServiceInfo;
 import android.os.Bundle;
 import android.os.Handler;
-import android.platform.test.annotations.RequiresFlagsEnabled;
 import android.platform.test.flag.junit.CheckFlagsRule;
 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.support.test.uiautomator.By;
@@ -63,7 +62,6 @@
 import android.view.View;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.Flags;
 import android.view.accessibility.IAccessibilityManager;
 import android.widget.Button;
 
@@ -298,7 +296,6 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(Flags.FLAG_ALLOW_SHORTCUT_CHOOSER_ON_LOCKSCREEN)
     public void createDialog_onLockscreen_hasExpectedContent() {
         when(mKeyguardManager.isKeyguardLocked()).thenReturn(true);
         launchActivity();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index ad3be3d..59c841f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -686,7 +686,11 @@
         }
     }
 
-    private void dispatchOnBackCancelled(IOnBackInvokedCallback callback) {
+    private void tryDispatchOnBackCancelled(IOnBackInvokedCallback callback) {
+        if (!mOnBackStartDispatched) {
+            Log.e(TAG, "Skipping dispatching onBackCancelled. Start was never dispatched.");
+            return;
+        }
         if (callback == null) {
             return;
         }
@@ -745,7 +749,7 @@
             if (touchTracker.getTriggerBack()) {
                 dispatchOrAnimateOnBackInvoked(callback, touchTracker);
             } else {
-                dispatchOnBackCancelled(callback);
+                tryDispatchOnBackCancelled(callback);
             }
         }
         finishBackNavigation(touchTracker.getTriggerBack());
@@ -824,7 +828,7 @@
         if (mCurrentTracker.getTriggerBack()) {
             dispatchOrAnimateOnBackInvoked(mActiveCallback, mCurrentTracker);
         } else {
-            dispatchOnBackCancelled(mActiveCallback);
+            tryDispatchOnBackCancelled(mActiveCallback);
         }
     }
 
@@ -876,7 +880,7 @@
         if (mCurrentTracker.isInInitialState()) {
             if (mBackGestureStarted) {
                 mBackGestureStarted = false;
-                dispatchOnBackCancelled(mActiveCallback);
+                tryDispatchOnBackCancelled(mActiveCallback);
                 finishBackNavigation(false);
                 ProtoLog.d(WM_SHELL_BACK_PREVIEW,
                         "resetTouchTracker -> reset an unfinished gesture");
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt
index 3253cac..772eae7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt
@@ -65,7 +65,7 @@
     private val targetEnteringRect = RectF()
     private val currentEnteringRect = RectF()
 
-    private val taskBoundsRect = Rect()
+    private val backAnimRect = Rect()
 
     private val cornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context)
 
@@ -109,10 +109,10 @@
         transaction.setAnimationTransaction()
 
         // Offset start rectangle to align task bounds.
-        taskBoundsRect.set(closingTarget!!.windowConfiguration.bounds)
-        taskBoundsRect.offsetTo(0, 0)
+        backAnimRect.set(closingTarget!!.localBounds)
+        backAnimRect.offsetTo(0, 0)
 
-        startClosingRect.set(taskBoundsRect)
+        startClosingRect.set(backAnimRect)
 
         // scale closing target into the middle for rhs and to the right for lhs
         targetClosingRect.set(startClosingRect)
@@ -154,7 +154,7 @@
     }
 
     private fun getYOffset(centeredRect: RectF, touchY: Float): Float {
-        val screenHeight = taskBoundsRect.height()
+        val screenHeight = backAnimRect.height()
         // Base the window movement in the Y axis on the touch movement in the Y axis.
         val rawYDelta = touchY - initialTouchPos.y
         val yDirection = (if (rawYDelta < 0) -1 else 1)
@@ -181,8 +181,8 @@
         // off the animator
         startClosingRect.set(currentClosingRect)
         startEnteringRect.set(currentEnteringRect)
-        targetEnteringRect.set(taskBoundsRect)
-        targetClosingRect.set(taskBoundsRect)
+        targetEnteringRect.set(backAnimRect)
+        targetClosingRect.set(backAnimRect)
         targetClosingRect.offset(currentClosingRect.left + enteringStartOffset, 0f)
 
         val valueAnimator = ValueAnimator.ofFloat(1f, 0f).setDuration(POST_ANIMATION_DURATION)
@@ -240,13 +240,13 @@
 
     private fun applyTransform(leash: SurfaceControl?, rect: RectF, alpha: Float) {
         if (leash == null || !leash.isValid) return
-        val scale = rect.width() / taskBoundsRect.width()
+        val scale = rect.width() / backAnimRect.width()
         transformMatrix.reset()
         transformMatrix.setScale(scale, scale)
         transformMatrix.postTranslate(rect.left, rect.top)
         transaction.setAlpha(leash, alpha)
             .setMatrix(leash, transformMatrix, tmpFloat9)
-            .setCrop(leash, taskBoundsRect)
+            .setCrop(leash, backAnimRect)
             .setCornerRadius(leash, cornerRadius)
     }
 
@@ -267,6 +267,7 @@
         transaction
             .setColor(scrimLayer, colorComponents)
             .setAlpha(scrimLayer!!, maxScrimAlpha)
+            .setCrop(scrimLayer!!, closingTarget!!.localBounds)
             .setRelativeLayer(scrimLayer!!, closingTarget!!.leash, -1)
             .show(scrimLayer)
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
index ae07812..b86e39f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
@@ -93,8 +93,9 @@
     @Provides
     static PipScheduler providePipScheduler(Context context,
             PipBoundsState pipBoundsState,
-            @ShellMainThread ShellExecutor mainExecutor) {
-        return new PipScheduler(context, pipBoundsState, mainExecutor);
+            @ShellMainThread ShellExecutor mainExecutor,
+            ShellTaskOrganizer shellTaskOrganizer) {
+        return new PipScheduler(context, pipBoundsState, mainExecutor, shellTaskOrganizer);
     }
 
     @WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
index 7c8fcbb..99a00b8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt
@@ -20,6 +20,7 @@
 import android.util.ArrayMap
 import android.util.ArraySet
 import android.util.SparseArray
+import android.view.Display.INVALID_DISPLAY
 import androidx.core.util.forEach
 import androidx.core.util.keyIterator
 import androidx.core.util.valueIterator
@@ -226,6 +227,14 @@
                         displayData[otherDisplayId].visibleTasks.size)
                 }
             }
+        } else if (displayId == INVALID_DISPLAY) {
+            // Task has vanished. Check which display to remove the task from.
+            displayData.forEach { displayId, data ->
+                if (data.visibleTasks.remove(taskId)) {
+                    notifyVisibleTaskListeners(displayId, data.visibleTasks.size)
+                }
+            }
+            return
         }
 
         val prevCount = getVisibleTaskCount(displayId)
@@ -236,6 +245,7 @@
         }
         val newCount = getVisibleTaskCount(displayId)
 
+        // Check if count changed
         if (prevCount != newCount) {
             KtProtoLog.d(
                 WM_SHELL_DESKTOP_MODE,
@@ -244,10 +254,6 @@
                 visible,
                 displayId
             )
-        }
-
-        // Check if count changed
-        if (prevCount != newCount) {
             KtProtoLog.d(
                 WM_SHELL_DESKTOP_MODE,
                 "DesktopTaskRepo: visibleTaskCount has changed from %d to %d",
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
index 4c69cc3..1e18b8c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
@@ -245,9 +245,9 @@
             Rect destinationBounds, SurfaceControl overlay, Rect appBounds) {
         ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                 "onSwipePipToHomeAnimationStart: %s", componentName);
-        mPipScheduler.setInSwipePipToHomeTransition(true);
+        mPipScheduler.onSwipePipToHomeAnimationStart(taskId, componentName, destinationBounds,
+                overlay, appBounds);
         mPipRecentsAnimationListener.onPipAnimationStarted();
-        // TODO: cache the overlay if provided for reparenting later.
     }
 
     //
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
index 6665013..b4ca7df 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
@@ -21,6 +21,7 @@
 import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP;
 
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -30,9 +31,11 @@
 import android.window.WindowContainerTransaction;
 
 import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.core.content.ContextCompat;
 
+import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.pip.PipBoundsState;
 import com.android.wm.shell.common.pip.PipUtils;
@@ -52,6 +55,7 @@
     private final Context mContext;
     private final PipBoundsState mPipBoundsState;
     private final ShellExecutor mMainExecutor;
+    private final ShellTaskOrganizer mShellTaskOrganizer;
     private PipSchedulerReceiver mSchedulerReceiver;
     private PipTransitionController mPipTransitionController;
 
@@ -66,6 +70,16 @@
     // true if Launcher has started swipe PiP to home animation
     private boolean mInSwipePipToHomeTransition;
 
+    // Overlay leash potentially used during swipe PiP to home transition;
+    // if null while mInSwipePipToHomeTransition is true, then srcRectHint was invalid.
+    @Nullable
+    SurfaceControl mSwipePipToHomeOverlay;
+
+    // App bounds used when as a starting point to swipe PiP to home animation in Launcher;
+    // these are also used to calculate the app icon overlay buffer size.
+    @NonNull
+    final Rect mSwipePipToHomeAppBounds = new Rect();
+
     /**
      * Temporary PiP CUJ codes to schedule PiP related transitions directly from Shell.
      * This is used for a broadcast receiver to resolve intents. This should be removed once
@@ -101,11 +115,14 @@
         }
     }
 
-    public PipScheduler(Context context, PipBoundsState pipBoundsState,
-            ShellExecutor mainExecutor) {
+    public PipScheduler(Context context,
+            PipBoundsState pipBoundsState,
+            ShellExecutor mainExecutor,
+            ShellTaskOrganizer shellTaskOrganizer) {
         mContext = context;
         mPipBoundsState = pipBoundsState;
         mMainExecutor = mainExecutor;
+        mShellTaskOrganizer = shellTaskOrganizer;
 
         if (PipUtils.isPip2ExperimentEnabled()) {
             // temporary broadcast receiver to initiate exit PiP via expand
@@ -115,6 +132,10 @@
         }
     }
 
+    ShellExecutor getMainExecutor() {
+        return mMainExecutor;
+    }
+
     void setPipTransitionController(PipTransitionController pipTransitionController) {
         mPipTransitionController = pipTransitionController;
     }
@@ -171,6 +192,24 @@
         mPipTransitionController.startResizeTransition(wct, onFinishResizeCallback);
     }
 
+    void onSwipePipToHomeAnimationStart(int taskId, ComponentName componentName,
+            Rect destinationBounds, SurfaceControl overlay, Rect appBounds) {
+        mInSwipePipToHomeTransition = true;
+        mSwipePipToHomeOverlay = overlay;
+        mSwipePipToHomeAppBounds.set(appBounds);
+        if (overlay != null) {
+            // Shell transitions might use a root animation leash, which will be removed when
+            // the Recents transition is finished. Launcher attaches the overlay leash to this
+            // animation target leash; thus, we need to reparent it to the actual Task surface now.
+            // PipTransition is responsible to fade it out and cleanup when finishing the enter PIP
+            // transition.
+            SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
+            mShellTaskOrganizer.reparentChildSurfaceToTask(taskId, overlay, tx);
+            tx.setLayer(overlay, Integer.MAX_VALUE);
+            tx.apply();
+        }
+    }
+
     void setInSwipePipToHomeTransition(boolean inSwipePipToHome) {
         mInSwipePipToHomeTransition = inSwipePipToHome;
     }
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 d15da4a..b179b5b 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
@@ -24,6 +24,9 @@
 import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP;
 import static com.android.wm.shell.transition.Transitions.TRANSIT_RESIZE_PIP;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
 import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.PictureInPictureParams;
@@ -44,6 +47,7 @@
 import com.android.wm.shell.common.pip.PipBoundsState;
 import com.android.wm.shell.common.pip.PipMenuController;
 import com.android.wm.shell.common.pip.PipUtils;
+import com.android.wm.shell.pip.PipContentOverlay;
 import com.android.wm.shell.pip.PipTransitionController;
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.transition.Transitions;
@@ -55,6 +59,11 @@
  */
 public class PipTransition extends PipTransitionController {
     private static final String TAG = PipTransition.class.getSimpleName();
+    /**
+     * The fixed start delay in ms when fading out the content overlay from bounds animation.
+     * The fadeout animation is guaranteed to start after the client has drawn under the new config.
+     */
+    private static final int CONTENT_OVERLAY_FADE_OUT_DELAY_MS = 400;
 
     private final Context mContext;
     private final PipScheduler mPipScheduler;
@@ -230,10 +239,13 @@
 
         PictureInPictureParams params = pipChange.getTaskInfo().pictureInPictureParams;
         Rect srcRectHint = params.getSourceRectHint();
+        Rect startBounds = pipChange.getStartAbsBounds();
         Rect destinationBounds = pipChange.getEndAbsBounds();
 
+        WindowContainerTransaction finishWct = new WindowContainerTransaction();
+
         if (PipBoundsAlgorithm.isSourceRectHintValidForEnterPip(srcRectHint, destinationBounds)) {
-            float scale = (float) destinationBounds.width() / srcRectHint.width();
+            final float scale = (float) destinationBounds.width() / srcRectHint.width();
             startTransaction.setWindowCrop(pipLeash, srcRectHint);
             startTransaction.setPosition(pipLeash,
                     destinationBounds.left - srcRectHint.left * scale,
@@ -244,13 +256,62 @@
             // in multi-activity case, reparenting yields new reset scales coming from pinned task.
             startTransaction.setScale(pipLeash, scale, scale);
         } else {
-            // TODO(b/325481148): handle the case with invalid srcRectHint (using overlay).
+            final float scaleX = (float) destinationBounds.width() / startBounds.width();
+            final float scaleY = (float) destinationBounds.height() / startBounds.height();
+            final int overlaySize = PipContentOverlay.PipAppIconOverlay
+                    .getOverlaySize(mPipScheduler.mSwipePipToHomeAppBounds, destinationBounds);
+            SurfaceControl overlayLeash = mPipScheduler.mSwipePipToHomeOverlay;
+
+            startTransaction.setPosition(pipLeash, destinationBounds.left, destinationBounds.top)
+                    .setScale(pipLeash, scaleX, scaleY)
+                    .setWindowCrop(pipLeash, startBounds)
+                    .reparent(overlayLeash, pipLeash)
+                    .setLayer(overlayLeash, Integer.MAX_VALUE);
+
+            if (mPipTaskToken != null) {
+                SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
+                tx.addTransactionCommittedListener(mPipScheduler.getMainExecutor(),
+                                this::onClientDrawAtTransitionEnd)
+                        .setScale(overlayLeash, 1f, 1f)
+                        .setPosition(overlayLeash,
+                                (destinationBounds.width() - overlaySize) / 2f,
+                                (destinationBounds.height() - overlaySize) / 2f);
+                finishWct.setBoundsChangeTransaction(mPipTaskToken, tx);
+            }
         }
         startTransaction.apply();
-        finishCallback.onTransitionFinished(null);
+
+        // Note that finishWct should be free of any actual WM state changes; we are using
+        // it for syncing with the client draw after delayed configuration changes are dispatched.
+        finishCallback.onTransitionFinished(finishWct.isEmpty() ? null : finishWct);
         return true;
     }
 
+    private void onClientDrawAtTransitionEnd() {
+        startOverlayFadeoutAnimation();
+    }
+
+    private void startOverlayFadeoutAnimation() {
+        ValueAnimator animator = ValueAnimator.ofFloat(1f, 0f);
+        animator.setDuration(CONTENT_OVERLAY_FADE_OUT_DELAY_MS);
+        animator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                super.onAnimationEnd(animation);
+                SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
+                tx.remove(mPipScheduler.mSwipePipToHomeOverlay);
+                tx.apply();
+                mPipScheduler.mSwipePipToHomeOverlay = null;
+            }
+        });
+        animator.addUpdateListener(animation -> {
+            float alpha = (float) animation.getAnimatedValue();
+            SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
+            tx.setAlpha(mPipScheduler.mSwipePipToHomeOverlay, alpha).apply();
+        });
+        animator.start();
+    }
+
     private boolean startBoundsTypeEnterAnimation(@NonNull TransitionInfo info,
             @NonNull SurfaceControl.Transaction startTransaction,
             @NonNull SurfaceControl.Transaction finishTransaction,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index 2919782..d839eae 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -557,6 +557,23 @@
     }
 
     @Test
+    public void skipsCancelWithoutStart() throws RemoteException {
+        final int type = BackNavigationInfo.TYPE_CALLBACK;
+        final ResultListener result = new ResultListener();
+        createNavigationInfo(new BackNavigationInfo.Builder()
+                .setType(type)
+                .setOnBackInvokedCallback(mAppCallback)
+                .setOnBackNavigationDone(new RemoteCallback(result)));
+        doMotionEvent(MotionEvent.ACTION_CANCEL, 0);
+        mShellExecutor.flushAll();
+
+        verify(mAppCallback, never()).onBackStarted(any());
+        verify(mAppCallback, never()).onBackProgressed(any());
+        verify(mAppCallback, never()).onBackInvoked();
+        verify(mAppCallback, never()).onBackCancelled();
+    }
+
+    @Test
     public void testBackToActivity() throws RemoteException {
         final CrossActivityBackAnimation animation = new CrossActivityBackAnimation(
                 mContext, mAnimationBackground, mRootTaskDisplayAreaOrganizer);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt
index 445f74a..9f3a4d9 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt
@@ -18,6 +18,7 @@
 
 import android.testing.AndroidTestingRunner
 import android.view.Display.DEFAULT_DISPLAY
+import android.view.Display.INVALID_DISPLAY
 import androidx.test.filters.SmallTest
 import com.android.wm.shell.ShellTestCase
 import com.android.wm.shell.TestShellExecutor
@@ -237,6 +238,27 @@
         assertThat(listener.visibleChangesOnDefaultDisplay).isEqualTo(4)
     }
 
+    /**
+     * When a task vanishes, the displayId of the task is set to INVALID_DISPLAY.
+     * This tests that task is removed from the last parent display when it vanishes.
+     */
+    @Test
+    fun updateVisibleFreeformTasks_removeVisibleTasksRemovesTaskWithInvalidDisplay() {
+        val listener = TestVisibilityListener()
+        val executor = TestShellExecutor()
+        repo.addVisibleTasksListener(listener, executor)
+        repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = true)
+        repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 2, visible = true)
+        executor.flushAll()
+
+        assertThat(listener.visibleTasksCountOnDefaultDisplay).isEqualTo(2)
+        repo.updateVisibleFreeformTasks(INVALID_DISPLAY, taskId = 1, visible = false)
+        executor.flushAll()
+
+        assertThat(listener.visibleChangesOnDefaultDisplay).isEqualTo(3)
+        assertThat(listener.visibleTasksCountOnDefaultDisplay).isEqualTo(1)
+    }
+
     @Test
     fun getVisibleTaskCount() {
         // No tasks, count is 0
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsColors.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsColors.kt
index d72ec26..69aba71 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsColors.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsColors.kt
@@ -33,10 +33,6 @@
     val secondaryText: Color = Color.Unspecified,
     val primaryContainer: Color = Color.Unspecified,
     val onPrimaryContainer: Color = Color.Unspecified,
-    val spinnerHeaderContainer: Color = Color.Unspecified,
-    val onSpinnerHeaderContainer: Color = Color.Unspecified,
-    val spinnerItemContainer: Color = Color.Unspecified,
-    val onSpinnerItemContainer: Color = Color.Unspecified,
 )
 
 internal val LocalColorScheme = staticCompositionLocalOf { SettingsColorScheme() }
@@ -76,10 +72,6 @@
         secondaryText = tonalPalette.neutralVariant30,
         primaryContainer = tonalPalette.primary90,
         onPrimaryContainer = tonalPalette.neutral10,
-        spinnerHeaderContainer = tonalPalette.primary90,
-        onSpinnerHeaderContainer = tonalPalette.neutral10,
-        spinnerItemContainer = tonalPalette.secondary90,
-        onSpinnerItemContainer = tonalPalette.neutralVariant30,
     )
 }
 
@@ -103,10 +95,6 @@
         secondaryText = tonalPalette.neutralVariant80,
         primaryContainer = tonalPalette.secondary90,
         onPrimaryContainer = tonalPalette.neutral10,
-        spinnerHeaderContainer = tonalPalette.primary90,
-        onSpinnerHeaderContainer = tonalPalette.neutral10,
-        spinnerItemContainer = tonalPalette.secondary90,
-        onSpinnerItemContainer = tonalPalette.neutralVariant30,
     )
 }
 
@@ -121,10 +109,6 @@
         secondaryText = tonalPalette.neutralVariant80,
         primaryContainer = tonalPalette.secondary90,
         onPrimaryContainer = tonalPalette.neutral10,
-        spinnerHeaderContainer = tonalPalette.primary90,
-        onSpinnerHeaderContainer = tonalPalette.neutral10,
-        spinnerItemContainer = tonalPalette.secondary90,
-        onSpinnerItemContainer = tonalPalette.neutralVariant30,
     )
 }
 
@@ -139,9 +123,5 @@
         secondaryText = tonalPalette.neutralVariant30,
         primaryContainer = tonalPalette.primary90,
         onPrimaryContainer = tonalPalette.neutral10,
-        spinnerHeaderContainer = tonalPalette.primary90,
-        onSpinnerHeaderContainer = tonalPalette.neutral10,
-        spinnerItemContainer = tonalPalette.secondary90,
-        onSpinnerItemContainer = tonalPalette.neutralVariant30,
     )
 }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt
index 514ad669..c48a147 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt
@@ -33,6 +33,7 @@
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableIntStateOf
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.saveable.rememberSaveable
 import androidx.compose.runtime.setValue
@@ -74,8 +75,8 @@
             modifier = Modifier.semantics { role = Role.DropdownList },
             onClick = { expanded = true },
             colors = ButtonDefaults.buttonColors(
-                containerColor = SettingsTheme.colorScheme.spinnerHeaderContainer,
-                contentColor = SettingsTheme.colorScheme.onSpinnerHeaderContainer,
+                containerColor = MaterialTheme.colorScheme.primaryContainer,
+                contentColor = MaterialTheme.colorScheme.onPrimaryContainer,
             ),
             contentPadding = contentPadding,
         ) {
@@ -85,7 +86,7 @@
         DropdownMenu(
             expanded = expanded,
             onDismissRequest = { expanded = false },
-            modifier = Modifier.background(SettingsTheme.colorScheme.spinnerItemContainer),
+            modifier = Modifier.background(MaterialTheme.colorScheme.secondaryContainer),
         ) {
             for (option in options) {
                 DropdownMenuItem(
@@ -93,7 +94,7 @@
                         SpinnerText(
                             option = option,
                             modifier = Modifier.padding(end = 24.dp),
-                            color = SettingsTheme.colorScheme.onSpinnerItemContainer,
+                            color = MaterialTheme.colorScheme.onSecondaryContainer,
                         )
                     },
                     onClick = {
@@ -138,7 +139,7 @@
 @Composable
 private fun SpinnerPreview() {
     SettingsTheme {
-        var selectedId by rememberSaveable { mutableStateOf(1) }
+        var selectedId by rememberSaveable { mutableIntStateOf(1) }
         Spinner(
             options = (1..3).map { SpinnerOption(id = it, text = "Option $it") },
             selectedId = selectedId,
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/theme/SettingsColorsTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/theme/SettingsColorsTest.kt
index 5ea92ab..625663d 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/theme/SettingsColorsTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/theme/SettingsColorsTest.kt
@@ -37,15 +37,11 @@
         assertThat(ls.categoryTitle).isNotEqualTo(ls.background)
         assertThat(ls.secondaryText).isNotEqualTo(ls.background)
         assertThat(ls.primaryContainer).isNotEqualTo(ls.onPrimaryContainer)
-        assertThat(ls.spinnerHeaderContainer).isNotEqualTo(ls.onSpinnerHeaderContainer)
-        assertThat(ls.spinnerItemContainer).isNotEqualTo(ls.onSpinnerItemContainer)
 
         val ds = dynamicDarkColorScheme(context)
         assertThat(ds.categoryTitle).isNotEqualTo(ds.background)
         assertThat(ds.secondaryText).isNotEqualTo(ds.background)
         assertThat(ds.primaryContainer).isNotEqualTo(ds.onPrimaryContainer)
-        assertThat(ds.spinnerHeaderContainer).isNotEqualTo(ds.onSpinnerHeaderContainer)
-        assertThat(ds.spinnerItemContainer).isNotEqualTo(ds.onSpinnerItemContainer)
     }
 
     @Test
@@ -58,10 +54,6 @@
         assertThat(ls.secondaryText).isEqualTo(Color(red = 73, green = 69, blue = 79))
         assertThat(ls.primaryContainer).isEqualTo(Color(red = 234, green = 221, blue = 255))
         assertThat(ls.onPrimaryContainer).isEqualTo(Color(red = 28, green = 27, blue = 31))
-        assertThat(ls.spinnerHeaderContainer).isEqualTo(Color(red = 234, green = 221, blue = 255))
-        assertThat(ls.onSpinnerHeaderContainer).isEqualTo(Color(red = 28, green = 27, blue = 31))
-        assertThat(ls.spinnerItemContainer).isEqualTo(Color(red = 232, green = 222, blue = 248))
-        assertThat(ls.onSpinnerItemContainer).isEqualTo(Color(red = 73, green = 69, blue = 79))
 
         val ds = darkColorScheme()
         assertThat(ds.background).isEqualTo(Color(red = 28, green = 27, blue = 31))
@@ -71,9 +63,5 @@
         assertThat(ds.secondaryText).isEqualTo(Color(red = 202, green = 196, blue = 208))
         assertThat(ds.primaryContainer).isEqualTo(Color(red = 232, green = 222, blue = 248))
         assertThat(ds.onPrimaryContainer).isEqualTo(Color(red = 28, green = 27, blue = 31))
-        assertThat(ds.spinnerHeaderContainer).isEqualTo(Color(red = 234, green = 221, blue = 255))
-        assertThat(ds.onSpinnerHeaderContainer).isEqualTo(Color(red = 28, green = 27, blue = 31))
-        assertThat(ds.spinnerItemContainer).isEqualTo(Color(red = 232, green = 222, blue = 248))
-        assertThat(ds.onSpinnerItemContainer).isEqualTo(Color(red = 73, green = 69, blue = 79))
     }
 }
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 69e4bd7..46c6494 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -222,6 +222,30 @@
     <!-- Connected device settings. Message when the left-side and right-side hearing aids device are active. [CHAR LIMIT=NONE] -->
     <string name="bluetooth_hearing_aid_left_and_right_active">Active, left and right</string>
 
+    <!-- Connected devices settings. Message when Bluetooth is connected and active for media only, showing remote device status and battery level. [CHAR LIMIT=NONE] -->
+    <string name="bluetooth_active_media_only_battery_level">Active (media only), <xliff:g id="battery_level_as_percentage">%1$s</xliff:g> battery</string>
+    <!-- Connected devices settings. Message when Bluetooth is connected and active for media only, showing remote device status and battery level for untethered headset. [CHAR LIMIT=NONE] -->
+    <string name="bluetooth_active_media_only_battery_level_untethered">Active (media only), L: <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g> battery, R: <xliff:g id="battery_level_as_percentage" example="25%">%2$s</xliff:g> battery</string>
+    <!-- Connected devices settings. Message when Bluetooth is connected but not in use, showing remote device battery level, supports audio sharing. [CHAR LIMIT=NONE] -->
+    <string name="bluetooth_battery_level_lea_support">Connected (supports audio sharing), <xliff:g id="battery_level_as_percentage">%1$s</xliff:g> battery</string>
+    <!-- Connected devices settings. Message when Bluetooth is connected but not in use, showing remote device battery level for untethered headset, supports audio sharing. [CHAR LIMIT=NONE] -->
+    <string name="bluetooth_battery_level_untethered_lea_support">Connected (supports audio sharing), L: <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g> battery, R: <xliff:g id="battery_level_as_percentage" example="25%">%2$s</xliff:g> battery</string>
+    <!-- Connected devices settings. Message when Bluetooth is connected but not in use, showing remote device battery level for the left part of the untethered headset, supports audio sharing. [CHAR LIMIT=NONE] -->
+    <string name="bluetooth_battery_level_untethered_left_lea_support">Connected (supports audio sharing), left <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g></string>
+    <!-- Connected devices settings. Message when Bluetooth is connected but not in use, showing remote device battery level for the right part of the untethered headset, supports audio sharing. [CHAR LIMIT=NONE] -->
+    <string name="bluetooth_battery_level_untethered_right_lea_support">Connected (supports audio sharing), right <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g></string>
+    <!-- Connected devices settings. Message when Bluetooth is connected and active for media only but no battery information, showing remote device status. [CHAR LIMIT=NONE] -->
+    <string name="bluetooth_active_media_only_no_battery_level">Active (media only)</string>
+    <!-- Connected devices settings. Message shown when bluetooth device is disconnected but is a known, previously connected device, supports audio sharing [CHAR LIMIT=NONE] -->
+    <string name="bluetooth_saved_device_lea_support">Supports audio sharing</string>
+
+    <!-- Connected device settings. Message when the left-side hearing aid device is active for media only. [CHAR LIMIT=NONE] -->
+    <string name="bluetooth_hearing_aid_media_only_left_active">Active (media only), left only</string>
+    <!-- Connected device settings. Message when the right-side hearing aid device is active for media only. [CHAR LIMIT=NONE] -->
+    <string name="bluetooth_hearing_aid_media_only_right_active">Active (media only), right only</string>
+    <!-- Connected device settings. Message when the left-side and right-side hearing aids device are active for media only. [CHAR LIMIT=NONE] -->
+    <string name="bluetooth_hearing_aid_media_only_left_and_right_active">Active (media only), left and right</string>
+
     <!-- Bluetooth settings.  The user-visible string that is used whenever referring to the A2DP profile. -->
     <string name="bluetooth_profile_a2dp">Media audio</string>
     <!-- Bluetooth settings.  The user-visible string that is used whenever referring to the headset or handsfree profile. -->
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
index 1178cc8..4bef9ef 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
@@ -16,7 +16,6 @@
 
 package com.android.systemui.keyguard.ui.composable
 
-import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.collectAsState
@@ -24,9 +23,7 @@
 import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.platform.LocalView
-import com.android.compose.animation.scene.SceneKey
-import com.android.compose.animation.scene.SceneTransitionLayout
-import com.android.compose.animation.scene.transitions
+import com.android.compose.animation.scene.SceneScope
 import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
 import com.android.systemui.keyguard.ui.composable.blueprint.ComposableLockscreenSceneBlueprint
 import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
@@ -45,16 +42,12 @@
     private val blueprints: Set<@JvmSuppressWildcards ComposableLockscreenSceneBlueprint>,
     private val clockInteractor: KeyguardClockInteractor,
 ) {
-
-    private val sceneKeyByBlueprint: Map<ComposableLockscreenSceneBlueprint, SceneKey> by lazy {
-        blueprints.associateWith { blueprint -> SceneKey(blueprint.id) }
-    }
-    private val sceneKeyByBlueprintId: Map<String, SceneKey> by lazy {
-        sceneKeyByBlueprint.entries.associate { (blueprint, sceneKey) -> blueprint.id to sceneKey }
+    private val blueprintByBlueprintId: Map<String, ComposableLockscreenSceneBlueprint> by lazy {
+        blueprints.associateBy { it.id }
     }
 
     @Composable
-    fun Content(
+    fun SceneScope.Content(
         modifier: Modifier = Modifier,
     ) {
         val coroutineScope = rememberCoroutineScope()
@@ -66,19 +59,7 @@
             onDispose { clockInteractor.clockEventController.unregisterListeners() }
         }
 
-        // Switch smoothly between blueprints, any composable tagged with element() will be
-        // transition-animated between any two blueprints, if they both display the same element.
-        SceneTransitionLayout(
-            currentScene = checkNotNull(sceneKeyByBlueprintId[blueprintId]),
-            onChangeScene = {},
-            transitions =
-                transitions { sceneKeyByBlueprintId.values.forEach { sceneKey -> to(sceneKey) } },
-            modifier = modifier,
-            enableInterruptions = false,
-        ) {
-            sceneKeyByBlueprint.entries.forEach { (blueprint, sceneKey) ->
-                scene(sceneKey) { with(blueprint) { Content(Modifier.fillMaxSize()) } }
-            }
-        }
+        val blueprint = blueprintByBlueprintId[blueprintId] ?: return
+        with(blueprint) { Content(modifier) }
     }
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
index 7acb4d5..c241f9c 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
@@ -66,9 +66,5 @@
         key = QuickSettings.SharedValues.TilesSquishiness,
     )
 
-    lockscreenContent
-        .get()
-        .Content(
-            modifier = modifier.fillMaxSize(),
-        )
+    with(lockscreenContent.get()) { Content(modifier = modifier.fillMaxSize()) }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerBaseTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerBaseTest.java
index 324534f..7986051 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerBaseTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardViewLegacyControllerBaseTest.java
@@ -105,7 +105,7 @@
         when(mKeyguardViewMediator.isAnimatingScreenOff()).thenReturn(false);
         when(mView.getUnpausedAlpha()).thenReturn(255);
         when(mShadeExpansionStateManager.addExpansionListener(any())).thenReturn(
-                new ShadeExpansionChangeEvent(0, false, false, 0));
+                new ShadeExpansionChangeEvent(0, false, false));
         mController = createUdfpsKeyguardViewController();
     }
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
index 5827671..6a86801 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
@@ -376,7 +376,7 @@
         // Ensure correct expansion passed in.
         ShadeExpansionChangeEvent event =
                 new ShadeExpansionChangeEvent(
-                        expansion, /* expanded= */ false, /* tracking= */ true, dragDownAmount);
+                        expansion, /* expanded= */ false, /* tracking= */ true);
         verify(mScrimController).expand(event);
     }
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java
index 97052a8..7cdd478 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/scrim/BouncerlessScrimControllerTest.java
@@ -59,7 +59,7 @@
         final BouncerlessScrimController scrimController =
                 new BouncerlessScrimController(mExecutor, mPowerManager);
         scrimController.addCallback(mCallback);
-        scrimController.expand(new ShadeExpansionChangeEvent(.5f, true, false, 0.0f));
+        scrimController.expand(new ShadeExpansionChangeEvent(.5f, true, false));
         mExecutor.runAllReady();
         verify(mPowerManager).wakeUp(anyLong(), eq(PowerManager.WAKE_REASON_GESTURE), any());
         verify(mCallback).onWakeup();
@@ -71,7 +71,7 @@
                 new BouncerlessScrimController(mExecutor, mPowerManager);
         scrimController.addCallback(mCallback);
         final ShadeExpansionChangeEvent expansionEvent =
-                new ShadeExpansionChangeEvent(0.5f, false, false, 0.0f);
+                new ShadeExpansionChangeEvent(0.5f, false, false);
         scrimController.expand(expansionEvent);
         mExecutor.runAllReady();
         verify(mCallback).onExpansion(eq(expansionEvent));
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImplTest.kt
index 16b68cc..ad40f8e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImplTest.kt
@@ -52,6 +52,7 @@
     private val deviceEntryRepository = kosmos.fakeDeviceEntryRepository
     private val deviceUnlockedInteractor = kosmos.deviceUnlockedInteractor
     private val sceneInteractor = kosmos.sceneInteractor
+    private val shadeAnimationInteractor = kosmos.shadeAnimationInteractor
     private val transitionState =
         MutableStateFlow<ObservableTransitionState>(
             ObservableTransitionState.Idle(Scenes.Lockscreen)
@@ -112,6 +113,40 @@
             changeScene(Scenes.Communal) { assertThat(panelExpansion).isEqualTo(1f) }
             assertThat(panelExpansion).isEqualTo(1f)
         }
+
+    @Test
+    @EnableSceneContainer
+    fun shouldHideStatusBarIconsWhenExpanded_goneScene() =
+        testScope.runTest {
+            underTest = kosmos.panelExpansionInteractorImpl
+            shadeAnimationInteractor.setIsLaunchingActivity(false)
+            changeScene(Scenes.Gone)
+
+            assertThat(underTest.shouldHideStatusBarIconsWhenExpanded()).isFalse()
+        }
+
+    @Test
+    @EnableSceneContainer
+    fun shouldHideStatusBarIconsWhenExpanded_lockscreenScene() =
+        testScope.runTest {
+            underTest = kosmos.panelExpansionInteractorImpl
+            shadeAnimationInteractor.setIsLaunchingActivity(false)
+            changeScene(Scenes.Lockscreen)
+
+            assertThat(underTest.shouldHideStatusBarIconsWhenExpanded()).isTrue()
+        }
+
+    @Test
+    @EnableSceneContainer
+    fun shouldHideStatusBarIconsWhenExpanded_activityLaunch() =
+        testScope.runTest {
+            underTest = kosmos.panelExpansionInteractorImpl
+            changeScene(Scenes.Gone)
+            shadeAnimationInteractor.setIsLaunchingActivity(true)
+
+            assertThat(underTest.shouldHideStatusBarIconsWhenExpanded()).isFalse()
+        }
+
     private fun TestScope.setUnlocked(isUnlocked: Boolean) {
         val isDeviceUnlocked by collectLastValue(deviceUnlockedInteractor.isDeviceUnlocked)
         deviceEntryRepository.setUnlocked(isUnlocked)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/startable/ShadeStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/startable/ShadeStartableTest.kt
index 31dacdd..52caa78 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/startable/ShadeStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/startable/ShadeStartableTest.kt
@@ -18,15 +18,32 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
+import com.android.compose.animation.scene.SceneKey
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
 import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
+import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
+import com.android.systemui.flags.EnableSceneContainer
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.res.R
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.scene.shared.model.fakeSceneDataSource
+import com.android.systemui.shade.ShadeExpansionChangeEvent
+import com.android.systemui.shade.ShadeExpansionListener
 import com.android.systemui.shade.domain.interactor.shadeInteractor
 import com.android.systemui.shade.shared.model.ShadeMode
 import com.android.systemui.testKosmos
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -34,11 +51,15 @@
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class ShadeStartableTest : SysuiTestCase() {
-
     private val kosmos = testKosmos()
     private val testScope = kosmos.testScope
     private val shadeInteractor = kosmos.shadeInteractor
+    private val sceneInteractor = kosmos.sceneInteractor
+    private val shadeExpansionStateManager = kosmos.shadeExpansionStateManager
+    private val deviceEntryRepository = kosmos.fakeDeviceEntryRepository
+    private val deviceUnlockedInteractor = kosmos.deviceUnlockedInteractor
     private val fakeConfigurationRepository = kosmos.fakeConfigurationRepository
+    private val fakeSceneDataSource = kosmos.fakeSceneDataSource
 
     private val underTest = kosmos.shadeStartable
 
@@ -59,4 +80,89 @@
             fakeConfigurationRepository.onAnyConfigurationChange()
             assertThat(shadeMode).isEqualTo(ShadeMode.Single)
         }
+
+    @Test
+    @EnableSceneContainer
+    fun hydrateShadeExpansionStateManager() =
+        testScope.runTest {
+            val expansionListener = mock<ShadeExpansionListener>()
+            var latestChangeEvent: ShadeExpansionChangeEvent? = null
+            whenever(expansionListener.onPanelExpansionChanged(any())).thenAnswer {
+                latestChangeEvent = it.arguments[0] as ShadeExpansionChangeEvent
+                Unit
+            }
+            shadeExpansionStateManager.addExpansionListener(expansionListener)
+
+            underTest.start()
+
+            setUnlocked(true)
+            val transitionState =
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Idle(Scenes.Gone)
+                )
+            sceneInteractor.setTransitionState(transitionState)
+
+            changeScene(Scenes.Gone, transitionState)
+            val currentScene by collectLastValue(sceneInteractor.currentScene)
+            assertThat(currentScene).isEqualTo(Scenes.Gone)
+
+            assertThat(latestChangeEvent)
+                .isEqualTo(
+                    ShadeExpansionChangeEvent(
+                        fraction = 0f,
+                        expanded = false,
+                        tracking = false,
+                    )
+                )
+
+            changeScene(Scenes.Shade, transitionState) { progress ->
+                assertThat(latestChangeEvent?.fraction).isEqualTo(progress)
+            }
+        }
+
+    private fun TestScope.setUnlocked(isUnlocked: Boolean) {
+        val isDeviceUnlocked by collectLastValue(deviceUnlockedInteractor.isDeviceUnlocked)
+        deviceEntryRepository.setUnlocked(isUnlocked)
+        runCurrent()
+
+        assertThat(isDeviceUnlocked).isEqualTo(isUnlocked)
+    }
+
+    private fun TestScope.changeScene(
+        toScene: SceneKey,
+        transitionState: MutableStateFlow<ObservableTransitionState>,
+        assertDuringProgress: ((progress: Float) -> Unit) = {},
+    ) {
+        val currentScene by collectLastValue(sceneInteractor.currentScene)
+        val progressFlow = MutableStateFlow(0f)
+        transitionState.value =
+            ObservableTransitionState.Transition(
+                fromScene = checkNotNull(currentScene),
+                toScene = toScene,
+                progress = progressFlow,
+                isInitiatedByUserInput = true,
+                isUserInputOngoing = flowOf(true),
+            )
+        runCurrent()
+        assertDuringProgress(progressFlow.value)
+
+        progressFlow.value = 0.2f
+        runCurrent()
+        assertDuringProgress(progressFlow.value)
+
+        progressFlow.value = 0.6f
+        runCurrent()
+        assertDuringProgress(progressFlow.value)
+
+        progressFlow.value = 1f
+        runCurrent()
+        assertDuringProgress(progressFlow.value)
+
+        transitionState.value = ObservableTransitionState.Idle(toScene)
+        fakeSceneDataSource.changeScene(toScene)
+        runCurrent()
+        assertDuringProgress(progressFlow.value)
+
+        assertThat(currentScene).isEqualTo(toScene)
+    }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
index 781a9a8..7e5205b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
@@ -36,7 +36,6 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.LockIconViewController;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.biometrics.AuthController;
@@ -93,7 +92,6 @@
     @Mock private NotificationShadeWindowViewController mNotificationShadeWindowViewController;
     @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
     @Mock private ShadeLockscreenInteractor mShadeLockscreenInteractor;
-    @Mock private LockIconViewController mLockIconViewController;
     @Mock private View mAmbientIndicationContainer;
     @Mock private BiometricUnlockController mBiometricUnlockController;
     @Mock private AuthController mAuthController;
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModelTest.kt
index 8e92557..2cc1ad3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModelTest.kt
@@ -84,8 +84,17 @@
 
                 runCurrent()
 
-                verify(activityStarter).startActivity(capture(intentCaptor), eq(true),
-                        capture(activityStartedCaptor))
+                verify(activityStarter)
+                    .startActivityDismissingKeyguard(
+                        /* intent = */ capture(intentCaptor),
+                        /* onlyProvisioned = */ eq(false),
+                        /* dismissShade = */ eq(true),
+                        /* disallowEnterPictureInPictureWhileLaunching = */ eq(false),
+                        /* callback = */ capture(activityStartedCaptor),
+                        /* flags = */ eq(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT),
+                        /* animationController = */ eq(null),
+                        /* userHandle = */ eq(null),
+                    )
                 assertThat(intentCaptor.value.action).isEqualTo(Settings.ACTION_SOUND_SETTINGS)
 
                 activityStartedCaptor.value.onActivityStarted(ActivityManager.START_SUCCESS)
diff --git a/packages/SystemUI/src/com/android/keyguard/EmptyLockIconViewController.kt b/packages/SystemUI/src/com/android/keyguard/EmptyLockIconViewController.kt
new file mode 100644
index 0000000..b792db3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/EmptyLockIconViewController.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard
+
+import android.view.MotionEvent
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.ui.view.KeyguardRootView
+import com.android.systemui.res.R
+import dagger.Lazy
+import javax.inject.Inject
+
+/**
+ * Lock icon view logic now lives in DeviceEntryIconViewBinder and ViewModels. Icon is positioned in
+ * [com.android.systemui.keyguard.ui.view.layout.sections.DefaultDeviceEntrySection].
+ *
+ * This class is to bridge the gap between the logic when the DeviceEntryUdfpsRefactor is enabled
+ * and the KeyguardBottomAreaRefactor is NOT enabled. This class can and should be removed when both
+ * flags are enabled.
+ */
+@SysUISingleton
+class EmptyLockIconViewController
+@Inject
+constructor(
+    private val keyguardRootView: Lazy<KeyguardRootView>,
+) : LockIconViewController {
+    private val deviceEntryIconViewId = R.id.device_entry_icon_view
+    override fun setLockIconView(lockIconView: LockIconView) {
+        // no-op
+    }
+
+    override fun getTop(): Float {
+        return keyguardRootView.get().getViewById(deviceEntryIconViewId)?.top?.toFloat() ?: 0f
+    }
+
+    override fun getBottom(): Float {
+        return keyguardRootView.get().getViewById(deviceEntryIconViewId)?.bottom?.toFloat() ?: 0f
+    }
+
+    override fun dozeTimeTick() {
+        // no-op
+    }
+
+    override fun setAlpha(alpha: Float) {
+        // no-op
+    }
+
+    override fun willHandleTouchWhileDozing(event: MotionEvent): Boolean {
+        return false
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LegacyLockIconViewController.java
similarity index 99%
rename from packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
rename to packages/SystemUI/src/com/android/keyguard/LegacyLockIconViewController.java
index 985f6c8..4e5df35 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LegacyLockIconViewController.java
@@ -98,7 +98,7 @@
  * icon will show a set distance from the bottom of the device.
  */
 @SysUISingleton
-public class LockIconViewController implements Dumpable {
+public class LegacyLockIconViewController implements Dumpable, LockIconViewController {
     private static final String TAG = "LockIconViewController";
     private static final float sDefaultDensity =
             (float) DisplayMetrics.DENSITY_DEVICE_STABLE / (float) DisplayMetrics.DENSITY_DEFAULT;
@@ -189,7 +189,7 @@
             };
 
     @Inject
-    public LockIconViewController(
+    public LegacyLockIconViewController(
             @NonNull StatusBarStateController statusBarStateController,
             @NonNull KeyguardUpdateMonitor keyguardUpdateMonitor,
             @NonNull KeyguardViewController keyguardViewController,
@@ -262,6 +262,7 @@
 
     /** Sets the LockIconView to the controller and rebinds any that depend on it. */
     @SuppressLint("ClickableViewAccessibility")
+    @Override
     public void setLockIconView(LockIconView lockIconView) {
         mView = lockIconView;
         mView.setAccessibilityDelegate(mAccessibilityDelegate);
@@ -344,10 +345,12 @@
         }
     }
 
+    @Override
     public float getTop() {
         return mView.getLocationTop();
     }
 
+    @Override
     public float getBottom() {
         return mView.getLocationBottom();
     }
@@ -499,6 +502,7 @@
     }
 
     /** Every minute, update the aod icon's burn in offset */
+    @Override
     public void dozeTimeTick() {
         updateBurnInOffsets();
     }
@@ -774,6 +778,7 @@
     /**
      * Set the alpha of this view.
      */
+    @Override
     public void setAlpha(float alpha) {
         mView.setAlpha(alpha);
     }
@@ -823,6 +828,7 @@
     /**
      * Whether the lock icon will handle a touch while dozing.
      */
+    @Override
     public boolean willHandleTouchWhileDozing(MotionEvent event) {
         // is in lock icon area
         mView.getHitRect(mSensorTouchLocation);
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.kt b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.kt
new file mode 100644
index 0000000..10d5a0c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.kt
@@ -0,0 +1,29 @@
+/*
+ * 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.keyguard
+
+import android.view.MotionEvent
+
+/** Controls the [LockIconView]. */
+interface LockIconViewController {
+    fun setLockIconView(lockIconView: LockIconView)
+    fun getTop(): Float
+    fun getBottom(): Float
+    fun dozeTimeTick()
+    fun setAlpha(alpha: Float)
+    fun willHandleTouchWhileDozing(event: MotionEvent): Boolean
+}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIService.java b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
index b26be0c..0cc3be2 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIService.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
@@ -99,9 +99,10 @@
         if (Build.IS_DEBUGGABLE) {
             // b/71353150 - looking for leaked binder proxies
             BinderInternal.nSetBinderProxyCountEnabled(true);
-            BinderInternal.nSetBinderProxyCountWatermarks(1000,900);
+            BinderInternal.nSetBinderProxyCountWatermarks(
+                    /* high= */ 1000, /* low= */ 900, /* warning= */ 950);
             BinderInternal.setBinderProxyCountCallback(
-                    new BinderInternal.BinderProxyLimitListener() {
+                    new BinderInternal.BinderProxyCountEventListener() {
                         @Override
                         public void onLimitReached(int uid) {
                             Slog.w(SystemUIApplication.TAG,
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java
index 1f5a0bf..be75e10 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java
@@ -36,7 +36,6 @@
 import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.internal.accessibility.dialog.AccessibilityTarget;
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.modules.expresslog.Counter;
 import com.android.systemui.Flags;
 import com.android.systemui.util.settings.SecureSettings;
@@ -418,18 +417,11 @@
         onPositionChanged();
     }
 
-    void incrementTexMetricForAllTargets(String metric) {
+    void incrementTexMetric(String metric) {
         if (!Flags.floatingMenuDragToEdit()) {
             return;
         }
-        for (AccessibilityTarget target : mTargetFeatures) {
-            incrementTexMetric(metric, target.getUid());
-        }
-    }
-
-    @VisibleForTesting
-    void incrementTexMetric(String metric, int uid) {
-        Counter.logIncrementWithUid(metric, uid);
+        Counter.logIncrement(metric);
     }
 
     private InstantInsetLayerDrawable getContainerViewInsetLayer() {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
index 85bf784..86279be 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
@@ -105,14 +105,14 @@
      *
      * <p>Defined in frameworks/proto_logging/stats/express/catalog/accessibility.cfg.
      */
-    static final String TEX_METRIC_DISMISS = "accessibility.value_fab_shortcut_action_dismiss";
+    static final String TEX_METRIC_DISMISS = "accessibility.value_fab_shortcut_dismiss";
 
     /**
      * Counter indicating the FAB was dragged to the Edit action button.
      *
      * <p>Defined in frameworks/proto_logging/stats/express/catalog/accessibility.cfg.
      */
-    static final String TEX_METRIC_EDIT = "accessibility.value_fab_shortcut_action_edit";
+    static final String TEX_METRIC_EDIT = "accessibility.value_fab_shortcut_edit";
 
     private final WindowManager mWindowManager;
     private final MenuView mMenuView;
@@ -492,11 +492,11 @@
             } else {
                 hideMenuAndShowMessage();
             }
-            mMenuView.incrementTexMetricForAllTargets(TEX_METRIC_DISMISS);
+            mMenuView.incrementTexMetric(TEX_METRIC_DISMISS);
         } else if (id == R.id.action_edit
                 && Flags.floatingMenuDragToEdit()) {
             gotoEditScreen();
-            mMenuView.incrementTexMetricForAllTargets(TEX_METRIC_EDIT);
+            mMenuView.incrementTexMetric(TEX_METRIC_EDIT);
         }
         mDismissView.hide();
         mDragToInteractView.hide();
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
new file mode 100644
index 0000000..4733d06
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
@@ -0,0 +1,57 @@
+/*
+ * 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.accessibility.hearingaid;
+
+import com.android.systemui.statusbar.phone.SystemUIDialog;
+
+import dagger.assisted.AssistedFactory;
+import dagger.assisted.AssistedInject;
+
+/**
+ * Dialog for showing hearing devices controls.
+ */
+public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate{
+
+    private final SystemUIDialog.Factory mSystemUIDialogFactory;
+
+    private SystemUIDialog mDialog;
+
+    /** Factory to create a {@link HearingDevicesDialogDelegate} dialog instance. */
+    @AssistedFactory
+    public interface Factory {
+        /** Create a {@link HearingDevicesDialogDelegate} instance */
+        HearingDevicesDialogDelegate create();
+    }
+
+    @AssistedInject
+    public HearingDevicesDialogDelegate(
+            SystemUIDialog.Factory systemUIDialogFactory) {
+        mSystemUIDialogFactory = systemUIDialogFactory;
+    }
+
+    @Override
+    public SystemUIDialog createDialog() {
+        SystemUIDialog dialog = mSystemUIDialogFactory.create(this);
+
+        if (mDialog != null) {
+            mDialog.dismiss();
+        }
+        mDialog = dialog;
+
+        return dialog;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogManager.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogManager.java
new file mode 100644
index 0000000..c83043e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogManager.java
@@ -0,0 +1,79 @@
+/*
+ * 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.accessibility.hearingaid;
+
+import android.util.Log;
+import android.view.View;
+
+import com.android.internal.jank.InteractionJankMonitor;
+import com.android.systemui.animation.DialogCuj;
+import com.android.systemui.animation.DialogTransitionAnimator;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
+
+import javax.inject.Inject;
+
+/**
+ * Factory to create {@link HearingDevicesDialogDelegate} objects and manage its lifecycle.
+ */
+@SysUISingleton
+public class HearingDevicesDialogManager {
+
+    private static final boolean DEBUG = true;
+    private static final String TAG = "HearingDevicesDialogManager";
+    private static final String INTERACTION_JANK_TAG = "hearing_devices_tile";
+    private SystemUIDialog mDialog;
+    private final DialogTransitionAnimator mDialogTransitionAnimator;
+    private final HearingDevicesDialogDelegate.Factory mDialogFactory;
+
+    @Inject
+    public HearingDevicesDialogManager(
+            DialogTransitionAnimator dialogTransitionAnimator,
+            HearingDevicesDialogDelegate.Factory dialogFactory) {
+        mDialogTransitionAnimator = dialogTransitionAnimator;
+        mDialogFactory = dialogFactory;
+    }
+
+    /**
+     * Shows the dialog.
+     *
+     * @param view The view from which the dialog is shown.
+     */
+    public void showDialog(View view) {
+        if (mDialog != null) {
+            if (DEBUG) {
+                Log.d(TAG, "HearingDevicesDialog already showing. Destroy it first.");
+            }
+            destroyDialog();
+        }
+        mDialog = mDialogFactory.create().createDialog();
+
+        if (view != null) {
+            mDialogTransitionAnimator.showFromView(mDialog, view,
+                    new DialogCuj(InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN,
+                            INTERACTION_JANK_TAG),
+                    true);
+        } else {
+            mDialog.show();
+        }
+    }
+
+    private void destroyDialog() {
+        mDialog.dismiss();
+        mDialog = null;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
index 86b254b..246d5d9 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
@@ -81,6 +81,7 @@
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.flow.shareIn
+import kotlinx.coroutines.flow.stateIn
 
 /** Encapsulates business-logic related to communal mode. */
 @OptIn(ExperimentalCoroutinesApi::class)
@@ -239,10 +240,14 @@
      * This will not be true while transitioning to the hub and will turn false immediately when a
      * swipe to exit the hub starts.
      */
-    val isIdleOnCommunal: Flow<Boolean> =
-        communalRepository.transitionState.map {
-            it is ObservableTransitionState.Idle && it.scene == CommunalScenes.Communal
-        }
+    val isIdleOnCommunal: StateFlow<Boolean> =
+        communalRepository.transitionState
+            .map { it is ObservableTransitionState.Idle && it.scene == CommunalScenes.Communal }
+            .stateIn(
+                scope = applicationScope,
+                started = SharingStarted.Eagerly,
+                initialValue = false,
+            )
 
     /**
      * Flow that emits a boolean if any portion of the communal UI is visible at all.
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/DeviceEntryModule.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/DeviceEntryModule.kt
index 71b5ab2..b8c03c0 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/DeviceEntryModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/DeviceEntryModule.kt
@@ -1,9 +1,32 @@
+/*
+ * 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.deviceentry
 
+import com.android.keyguard.EmptyLockIconViewController
+import com.android.keyguard.LegacyLockIconViewController
+import com.android.keyguard.LockIconViewController
+import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.deviceentry.data.repository.DeviceEntryRepositoryModule
 import com.android.systemui.deviceentry.data.repository.FaceWakeUpTriggersConfigModule
+import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
 import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
+import dagger.Lazy
 import dagger.Module
+import dagger.Provides
 import dagger.multibindings.Multibinds
 
 @Module(
@@ -18,4 +41,19 @@
      * A set of DeviceEntryIconTransitions. Ensures that this can be injected even if it's empty.
      */
     @Multibinds abstract fun deviceEntryIconTransitionSet(): Set<DeviceEntryIconTransition>
+
+    companion object {
+        @Provides
+        @SysUISingleton
+        fun provideLockIconViewController(
+            legacyLockIconViewController: Lazy<LegacyLockIconViewController>,
+            emptyLockIconViewController: Lazy<EmptyLockIconViewController>,
+        ): LockIconViewController {
+            return if (DeviceEntryUdfpsRefactor.isEnabled) {
+                emptyLockIconViewController.get()
+            } else {
+                legacyLockIconViewController.get()
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
index 7f3b5eb..926f7f1 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
@@ -172,19 +172,18 @@
                     final float screenTravelPercentage = Math.abs(e1.getY() - e2.getY())
                             / mTouchSession.getBounds().height();
                     setPanelExpansion(mBouncerInitiallyShowing
-                            ? screenTravelPercentage : 1 - screenTravelPercentage, dragDownAmount);
+                            ? screenTravelPercentage : 1 - screenTravelPercentage);
                     return true;
                 }
             };
 
-    private void setPanelExpansion(float expansion, float dragDownAmount) {
+    private void setPanelExpansion(float expansion) {
         mCurrentExpansion = expansion;
         ShadeExpansionChangeEvent event =
                 new ShadeExpansionChangeEvent(
                         /* fraction= */ mCurrentExpansion,
                         /* expanded= */ mExpanded,
-                        /* tracking= */ true,
-                        /* dragDownPxAmount= */ dragDownAmount);
+                        /* tracking= */ true);
         mCurrentScrimController.expand(event);
     }
 
@@ -333,7 +332,7 @@
                 animation -> {
                     float expansionFraction = (float) animation.getAnimatedValue();
                     float dragDownAmount = expansionFraction * expansionHeight;
-                    setPanelExpansion(expansionFraction, dragDownAmount);
+                    setPanelExpansion(expansionFraction);
                 });
         if (!mBouncerInitiallyShowing
                 && targetExpansion == KeyguardBouncerConstants.EXPANSION_VISIBLE) {
diff --git a/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffectViewBinder.kt b/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffectViewBinder.kt
index 1705909..f4998a7 100644
--- a/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffectViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/haptics/qs/QSLongPressEffectViewBinder.kt
@@ -18,10 +18,10 @@
 
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
+import com.android.app.tracing.coroutines.launch
 import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.qs.tileimpl.QSTileViewImpl
 import kotlinx.coroutines.DisposableHandle
-import kotlinx.coroutines.launch
 
 class QSLongPressEffectViewBinder {
 
@@ -31,16 +31,18 @@
 
     fun bind(
         tile: QSTileViewImpl,
+        tileSpec: String?,
         effect: QSLongPressEffect?,
     ) {
         if (effect == null) return
 
         handle =
             tile.repeatWhenAttached {
-                repeatOnLifecycle(Lifecycle.State.STARTED) {
+                repeatOnLifecycle(Lifecycle.State.CREATED) {
                     effect.scope = this
+                    val tag = "${tileSpec ?: "unknownTileSpec"}#LongPressEffect"
 
-                    launch {
+                    launch("$tag#progress") {
                         effect.effectProgress.collect { progress ->
                             progress?.let {
                                 if (it == 0f) {
@@ -51,7 +53,7 @@
                         }
                     }
 
-                    launch {
+                    launch("$tag#action") {
                         effect.actionType.collect { action ->
                             action?.let {
                                 when (it) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
index fa845c7..30beca7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewConfigurator.kt
@@ -29,11 +29,14 @@
 import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
 import androidx.constraintlayout.widget.ConstraintSet.START
 import androidx.constraintlayout.widget.ConstraintSet.TOP
+import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.SceneTransitionLayout
+import com.android.compose.animation.scene.transitions
 import com.android.internal.jank.InteractionJankMonitor
 import com.android.keyguard.KeyguardStatusView
 import com.android.keyguard.KeyguardStatusViewController
+import com.android.keyguard.LegacyLockIconViewController
 import com.android.keyguard.LockIconView
-import com.android.keyguard.LockIconViewController
 import com.android.keyguard.dagger.KeyguardStatusViewComponent
 import com.android.systemui.CoreStartable
 import com.android.systemui.common.ui.ConfigurationState
@@ -92,7 +95,7 @@
     private val configuration: ConfigurationState,
     private val context: Context,
     private val keyguardIndicationController: KeyguardIndicationController,
-    private val lockIconViewController: Lazy<LockIconViewController>,
+    private val lockIconViewController: Lazy<LegacyLockIconViewController>,
     private val shadeInteractor: ShadeInteractor,
     private val interactionJankMonitor: InteractionJankMonitor,
     private val deviceEntryHapticsInteractor: DeviceEntryHapticsInteractor,
@@ -109,6 +112,7 @@
 
     private var rootViewHandle: DisposableHandle? = null
     private var indicationAreaHandle: DisposableHandle? = null
+    private val sceneKey = SceneKey("root-view-scene-key")
 
     var keyguardStatusViewController: KeyguardStatusViewController? = null
         get() {
@@ -219,12 +223,25 @@
             blueprints.mapNotNull { it as? ComposableLockscreenSceneBlueprint }.toSet()
         return ComposeView(context).apply {
             setContent {
-                LockscreenContent(
-                        viewModel = viewModel,
-                        blueprints = sceneBlueprints,
-                        clockInteractor = clockInteractor
-                    )
-                    .Content(modifier = Modifier.fillMaxSize())
+                // STL is used solely to provide a SceneScope to enable us to invoke SceneScope
+                // composables.
+                SceneTransitionLayout(
+                    currentScene = sceneKey,
+                    onChangeScene = {},
+                    transitions = transitions {},
+                ) {
+                    scene(sceneKey) {
+                        with(
+                            LockscreenContent(
+                                viewModel = viewModel,
+                                blueprints = sceneBlueprints,
+                                clockInteractor = clockInteractor
+                            )
+                        ) {
+                            Content(modifier = Modifier.fillMaxSize())
+                        }
+                    }
+                }
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
index 88eadd7..b3d9a76 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
@@ -92,7 +92,8 @@
                 walletController.setupWalletChangeObservers(
                     callback,
                     QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE,
-                    QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE
+                    QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE,
+                    QuickAccessWalletController.WalletChangeEvent.DEFAULT_WALLET_APP_CHANGE
                 )
 
                 withContext(backgroundDispatcher) {
@@ -104,7 +105,8 @@
                 awaitClose {
                     walletController.unregisterWalletChangeObservers(
                         QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE,
-                        QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE
+                        QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE,
+                        QuickAccessWalletController.WalletChangeEvent.DEFAULT_WALLET_APP_CHANGE
                     )
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/backup/KeyguardQuickAffordanceBackupHelper.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/backup/KeyguardQuickAffordanceBackupHelper.kt
index fa6efa5..f763e62 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/backup/KeyguardQuickAffordanceBackupHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/backup/KeyguardQuickAffordanceBackupHelper.kt
@@ -17,14 +17,17 @@
 
 package com.android.systemui.keyguard.domain.backup
 
+import android.app.backup.BackupDataInputStream
 import android.app.backup.SharedPreferencesBackupHelper
 import android.content.Context
+import android.util.Log
+import com.android.app.tracing.traceSection
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceSelectionManager
 import com.android.systemui.settings.UserFileManagerImpl
 
 /** Handles backup & restore for keyguard quick affordances. */
 class KeyguardQuickAffordanceBackupHelper(
-    context: Context,
+    private val context: Context,
     userId: Int,
 ) :
     SharedPreferencesBackupHelper(
@@ -34,4 +37,17 @@
                 fileName = KeyguardQuickAffordanceSelectionManager.FILE_NAME,
             )
             .getPath()
-    )
+    ) {
+
+    override fun restoreEntity(data: BackupDataInputStream?) {
+        Log.d(TAG, "Starting restore for ${data?.key} for user ${context.userId}")
+        traceSection("$TAG File restore: ${data?.key}") {
+            super.restoreEntity(data)
+        }
+        Log.d(TAG, "Finished restore for ${data?.key} for user ${context.userId}")
+    }
+
+    companion object {
+        private const val TAG = "KeyguardQuickAffordanceBackupHelper"
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
index 1b91c49..87324a2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
@@ -20,6 +20,7 @@
 import android.content.Context
 import com.android.settingslib.Utils
 import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
+import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import javax.inject.Inject
@@ -34,6 +35,7 @@
 /** Models the UI state for the device entry icon background view. */
 @Suppress("WHEN_ENUM_CAN_BE_NULL_IN_JAVA")
 @ExperimentalCoroutinesApi
+@SysUISingleton
 class DeviceEntryBackgroundViewModel
 @Inject
 constructor(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
index 6281097..0aa6d12 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
@@ -21,6 +21,7 @@
 import com.android.settingslib.Utils
 import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor
 import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
+import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
 import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -39,6 +40,7 @@
 
 /** Models the UI state for the device entry icon foreground view (displayed icon). */
 @ExperimentalCoroutinesApi
+@SysUISingleton
 class DeviceEntryForegroundViewModel
 @Inject
 constructor(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
index bc4fd1c..49fffdd 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
@@ -19,6 +19,7 @@
 import android.animation.FloatEvaluator
 import android.animation.IntEvaluator
 import com.android.keyguard.KeyguardViewController
+import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntrySourceInteractor
@@ -52,6 +53,7 @@
 
 /** Models the UI state for the containing device entry icon & long-press handling view. */
 @ExperimentalCoroutinesApi
+@SysUISingleton
 class DeviceEntryIconViewModel
 @Inject
 constructor(
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseMediaProjectionPermissionDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseMediaProjectionPermissionDialogDelegate.kt
index 1983a67..dba0173 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseMediaProjectionPermissionDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseMediaProjectionPermissionDialogDelegate.kt
@@ -53,19 +53,17 @@
     private lateinit var cancelButton: TextView
     private lateinit var warning: TextView
     private lateinit var screenShareModeSpinner: Spinner
-    private var hasCancelBeenLogged: Boolean = false
     protected lateinit var dialog: AlertDialog
+    private var shouldLogCancel: Boolean = true
     var selectedScreenShareOption: ScreenShareOption = screenShareOptions.first()
 
     @CallSuper
     override fun onStop(dialog: T) {
         // onStop can be called multiple times and we only want to log once.
-        if (hasCancelBeenLogged) {
-            return
+        if (shouldLogCancel) {
+            mediaProjectionMetricsLogger.notifyProjectionRequestCancelled(hostUid)
+            shouldLogCancel = false
         }
-
-        mediaProjectionMetricsLogger.notifyProjectionRequestCancelled(hostUid)
-        hasCancelBeenLogged = true
     }
 
     @CallSuper
@@ -140,7 +138,10 @@
     }
 
     protected fun setStartButtonOnClickListener(listener: View.OnClickListener?) {
-        startButton.setOnClickListener(listener)
+        startButton.setOnClickListener { view ->
+            shouldLogCancel = false
+            listener?.onClick(view)
+        }
     }
 
     protected fun setCancelButtonOnClickListener(listener: View.OnClickListener?) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
index 1aef920..8d3500a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
@@ -29,6 +29,7 @@
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.ReduceBrightColorsController;
 import com.android.systemui.qs.external.QSExternalModule;
+import com.android.systemui.qs.panels.dagger.PanelsModule;
 import com.android.systemui.qs.pipeline.dagger.QSPipelineModule;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.qs.tiles.di.QSTilesModule;
@@ -44,21 +45,22 @@
 import com.android.systemui.statusbar.policy.WalletController;
 import com.android.systemui.util.settings.SecureSettings;
 
-import java.util.Map;
-
-import javax.inject.Named;
-
 import dagger.Binds;
 import dagger.Module;
 import dagger.Provides;
 import dagger.multibindings.Multibinds;
 
+import java.util.Map;
+
+import javax.inject.Named;
+
 /**
  * Module for QS dependencies
  */
 @Module(subcomponents = {QSFragmentComponent.class, QSSceneComponent.class},
         includes = {
                 MediaModule.class,
+                PanelsModule.class,
                 QSExternalModule.class,
                 QSFlagsModule.class,
                 QSHostModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt
new file mode 100644
index 0000000..1307296
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.panels.dagger
+
+import com.android.systemui.qs.panels.data.repository.IconTilesRepository
+import com.android.systemui.qs.panels.data.repository.IconTilesRepositoryImpl
+import dagger.Binds
+import dagger.Module
+
+@Module
+interface PanelsModule {
+    @Binds fun bindIconTilesRepository(impl: IconTilesRepositoryImpl): IconTilesRepository
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/IconTilesRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/IconTilesRepository.kt
new file mode 100644
index 0000000..92f87e7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/IconTilesRepository.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.panels.data.repository
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flowOf
+
+/** Repository for retrieving the list of [TileSpec] to be displayed as icons. */
+interface IconTilesRepository {
+    val iconTilesSpecs: Flow<Set<TileSpec>>
+}
+
+@SysUISingleton
+class IconTilesRepositoryImpl @Inject constructor() : IconTilesRepository {
+
+    /** Set of toggleable tiles that are suitable for being shown as an icon. */
+    override val iconTilesSpecs: Flow<Set<TileSpec>> =
+        flowOf(
+            setOf(
+                TileSpec.create("airplane"),
+                TileSpec.create("battery"),
+                TileSpec.create("cameratoggle"),
+                TileSpec.create("cast"),
+                TileSpec.create("color_correction"),
+                TileSpec.create("inversion"),
+                TileSpec.create("saver"),
+                TileSpec.create("dnd"),
+                TileSpec.create("flashlight"),
+                TileSpec.create("location"),
+                TileSpec.create("mictoggle"),
+                TileSpec.create("nfc"),
+                TileSpec.create("night"),
+                TileSpec.create("rotation")
+            )
+        )
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractor.kt
new file mode 100644
index 0000000..367c670
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractor.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.panels.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.qs.panels.data.repository.IconTilesRepository
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+
+/** Interactor for retrieving the list of [TileSpec] to be displayed as icons. */
+@SysUISingleton
+class IconTilesInteractor @Inject constructor(private val repo: IconTilesRepository) {
+    val iconTilesSpecs: Flow<Set<TileSpec>> = repo.iconTilesSpecs
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
index 2360f27..3004485 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -620,7 +620,7 @@
                 showRippleEffect = false
                 setOnTouchListener(longPressEffect)
                 if (!longPressEffectViewBinder.isBound) {
-                    longPressEffectViewBinder.bind(this, longPressEffect)
+                    longPressEffectViewBinder.bind(this, state.spec, longPressEffect)
                 }
             } else {
                 // Long-press effects might have been enabled before but the new state does not
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HearingDevicesTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HearingDevicesTile.java
index 1fb701e..81a2026 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HearingDevicesTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HearingDevicesTile.java
@@ -26,6 +26,7 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.Flags;
+import com.android.systemui.accessibility.hearingaid.HearingDevicesDialogManager;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
@@ -45,6 +46,8 @@
 
     public static final String TILE_SPEC = "hearing_devices";
 
+    private final HearingDevicesDialogManager mDialogManager;
+
     @Inject
     public HearingDevicesTile(
             QSHost host,
@@ -55,10 +58,12 @@
             MetricsLogger metricsLogger,
             StatusBarStateController statusBarStateController,
             ActivityStarter activityStarter,
-            QSLogger qsLogger
+            QSLogger qsLogger,
+            HearingDevicesDialogManager hearingDevicesDialogManager
     ) {
         super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger,
                 statusBarStateController, activityStarter, qsLogger);
+        mDialogManager = hearingDevicesDialogManager;
     }
 
     @Override
@@ -68,7 +73,7 @@
 
     @Override
     protected void handleClick(@Nullable View view) {
-
+        mUiHandler.post(() -> mDialogManager.showDialog(view));
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
index 1b73225..e1b742e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
@@ -182,12 +182,19 @@
 
     @Override
     public boolean isAvailable() {
+        if (isWalletRoleAvailable()) {
+            return !mPackageManager.hasSystemFeature(FEATURE_CHROME_OS);
+        }
         return mPackageManager.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)
                 && !mPackageManager.hasSystemFeature(FEATURE_CHROME_OS)
                 && mSecureSettings.getStringForUser(NFC_PAYMENT_DEFAULT_COMPONENT,
                     UserHandle.USER_CURRENT) != null;
     }
 
+    private boolean isWalletRoleAvailable() {
+        return mHost.getUserId() == UserHandle.USER_SYSTEM && mController.isWalletRoleAvailable();
+    }
+
     @Nullable
     @Override
     public Intent getLongClickIntent() {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelView.java
index c501d88..6bf5535 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelView.java
@@ -27,6 +27,8 @@
 import android.view.MotionEvent;
 import android.widget.FrameLayout;
 
+import com.android.systemui.scene.shared.flag.SceneContainerFlag;
+
 /** The shade view. */
 public final class NotificationPanelView extends FrameLayout {
     static final boolean DEBUG = false;
@@ -41,14 +43,20 @@
 
     public NotificationPanelView(Context context, AttributeSet attrs) {
         super(context, attrs);
-        setWillNotDraw(!DEBUG);
-        mAlphaPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
+        if (!SceneContainerFlag.isEnabled()) {
+            setWillNotDraw(!DEBUG);
+            mAlphaPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
 
-        setBackgroundColor(Color.TRANSPARENT);
+            setBackgroundColor(Color.TRANSPARENT);
+        }
     }
 
     @Override
     public void onRtlPropertiesChanged(int layoutDirection) {
+        if (SceneContainerFlag.isEnabled()) {
+            super.onRtlPropertiesChanged(layoutDirection);
+            return;
+        }
         if (mRtlChangeListener != null) {
             mRtlChangeListener.onRtlPropertielsChanged(layoutDirection);
         }
@@ -56,14 +64,19 @@
 
     @Override
     public boolean shouldDelayChildPressedState() {
+        if (SceneContainerFlag.isEnabled()) {
+            return super.shouldDelayChildPressedState();
+        }
         return true;
     }
 
     @Override
     protected void dispatchDraw(Canvas canvas) {
         super.dispatchDraw(canvas);
-        if (mCurrentPanelAlpha != 255) {
-            canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), mAlphaPaint);
+        if (!SceneContainerFlag.isEnabled()) {
+            if (mCurrentPanelAlpha != 255) {
+                canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), mAlphaPaint);
+            }
         }
     }
 
@@ -83,6 +96,9 @@
 
     @Override
     public boolean hasOverlappingRendering() {
+        if (SceneContainerFlag.isEnabled()) {
+            return super.hasOverlappingRendering();
+        }
         return !mDozing;
     }
 
@@ -102,6 +118,9 @@
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent event) {
+        if (SceneContainerFlag.isEnabled()) {
+            return super.onInterceptTouchEvent(event);
+        }
         return mTouchHandler.onInterceptTouchEvent(event);
     }
 
@@ -113,7 +132,9 @@
     @Override
     public void dispatchConfigurationChanged(Configuration newConfig) {
         super.dispatchConfigurationChanged(newConfig);
-        mOnConfigurationChangedListener.onConfigurationChanged(newConfig);
+        if (!SceneContainerFlag.isEnabled()) {
+            mOnConfigurationChangedListener.onConfigurationChanged(newConfig);
+        }
     }
 
     /** Callback for right-to-left setting changes. */
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index e4f5aeb..fa5f30f 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -96,12 +96,12 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.util.LatencyTracker;
 import com.android.keyguard.ActiveUnlockConfig;
+import com.android.keyguard.LockIconViewController;
 import com.android.keyguard.KeyguardClockSwitch.ClockSize;
 import com.android.keyguard.KeyguardStatusView;
 import com.android.keyguard.KeyguardStatusViewController;
 import com.android.keyguard.KeyguardUnfoldTransition;
 import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.LockIconViewController;
 import com.android.keyguard.dagger.KeyguardQsUserSwitchComponent;
 import com.android.keyguard.dagger.KeyguardStatusBarViewComponent;
 import com.android.keyguard.dagger.KeyguardStatusViewComponent;
@@ -982,6 +982,7 @@
                 });
         mAlternateBouncerInteractor = alternateBouncerInteractor;
         dumpManager.registerDumpable(this);
+        SceneContainerFlag.assertInLegacyMode();
     }
 
     private void unlockAnimationFinished() {
@@ -3555,9 +3556,9 @@
     }
 
     @Override
-    public ViewPropertyAnimator fadeOut(long startDelayMs, long durationMs, Runnable endAction) {
+    public void fadeOut(long startDelayMs, long durationMs, Runnable endAction) {
         mView.animate().cancel();
-        return mView.animate().alpha(0).setStartDelay(startDelayMs).setDuration(
+        mView.animate().alpha(0).setStartDelay(startDelayMs).setDuration(
                 durationMs).setInterpolator(Interpolators.ALPHA_OUT).withLayer().withEndAction(
                 endAction);
     }
@@ -4121,9 +4122,10 @@
 
     @Override
     public void updateExpansionAndVisibility() {
-        mShadeExpansionStateManager.onPanelExpansionChanged(
-                mExpandedFraction, isExpanded(), isTracking(), mExpansionDragDownAmountPx);
-
+        if (!SceneContainerFlag.isEnabled()) {
+            mShadeExpansionStateManager.onPanelExpansionChanged(
+                    mExpandedFraction, isExpanded(), isTracking());
+        }
         updateVisibility();
     }
 
@@ -4159,7 +4161,8 @@
     }
 
     /** Sends an external (e.g. Status Bar) intercept touch event to the Shade touch handler. */
-    boolean handleExternalInterceptTouch(MotionEvent event) {
+    @Override
+    public boolean handleExternalInterceptTouch(MotionEvent event) {
         try {
             mUseExternalTouch = true;
             return mTouchHandler.onInterceptTouchEvent(event);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index 59da8f1..324dfdf 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -52,6 +52,7 @@
 import com.android.systemui.keyguard.shared.model.TransitionState;
 import com.android.systemui.keyguard.shared.model.TransitionStep;
 import com.android.systemui.res.R;
+import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor;
 import com.android.systemui.shared.animation.DisableSubpixelTextTransitionListener;
 import com.android.systemui.statusbar.DragDownHelper;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
@@ -132,7 +133,8 @@
     private DragDownHelper mDragDownHelper;
     private boolean mExpandingBelowNotch;
     private final DockManager mDockManager;
-    private final NotificationPanelViewController mNotificationPanelViewController;
+    private final ShadeViewController mShadeViewController;
+    private final PanelExpansionInteractor mPanelExpansionInteractor;
     private final ShadeExpansionStateManager mShadeExpansionStateManager;
 
     private boolean mIsTrackingBarGesture = false;
@@ -154,7 +156,8 @@
             DockManager dockManager,
             NotificationShadeDepthController depthController,
             NotificationShadeWindowView notificationShadeWindowView,
-            NotificationPanelViewController notificationPanelViewController,
+            ShadeViewController shadeViewController,
+            PanelExpansionInteractor panelExpansionInteractor,
             ShadeExpansionStateManager shadeExpansionStateManager,
             NotificationStackScrollLayoutController notificationStackScrollLayoutController,
             StatusBarKeyguardViewManager statusBarKeyguardViewManager,
@@ -187,7 +190,8 @@
         mStatusBarStateController = statusBarStateController;
         mView = notificationShadeWindowView;
         mDockManager = dockManager;
-        mNotificationPanelViewController = notificationPanelViewController;
+        mShadeViewController = shadeViewController;
+        mPanelExpansionInteractor = panelExpansionInteractor;
         mShadeExpansionStateManager = shadeExpansionStateManager;
         mDepthController = depthController;
         mNotificationStackScrollLayoutController = notificationStackScrollLayoutController;
@@ -374,7 +378,7 @@
                 }
 
                 if (!mIsTrackingBarGesture && isDown
-                        && mNotificationPanelViewController.isFullyCollapsed()) {
+                        && mPanelExpansionInteractor.isFullyCollapsed()) {
                     float x = ev.getRawX();
                     float y = ev.getRawY();
                     if (mStatusBarViewController.touchIsWithinView(x, y)) {
@@ -447,7 +451,7 @@
                 } else {
                     bouncerShowing = mService.isBouncerShowing();
                 }
-                if (mNotificationPanelViewController.isFullyExpanded()
+                if (mPanelExpansionInteractor.isFullyExpanded()
                         && !bouncerShowing
                         && !mStatusBarStateController.isDozing()) {
                     if (mDragDownHelper.isDragDownEnabled()) {
@@ -503,7 +507,7 @@
                 cancellation.setAction(MotionEvent.ACTION_CANCEL);
                 mStackScrollLayout.onInterceptTouchEvent(cancellation);
                 if (!MigrateClocksToBlueprint.isEnabled()) {
-                    mNotificationPanelViewController.handleExternalInterceptTouch(cancellation);
+                    mShadeViewController.handleExternalInterceptTouch(cancellation);
                 }
                 cancellation.recycle();
             }
@@ -522,7 +526,7 @@
                         // we still want to finish our drag down gesture when locking the screen
                         handled |= mDragDownHelper.onTouchEvent(ev) || handled;
                     }
-                    if (!handled && mNotificationPanelViewController.handleExternalTouch(ev)) {
+                    if (!handled && mShadeViewController.handleExternalTouch(ev)) {
                         return true;
                     }
                 } else {
@@ -611,7 +615,7 @@
             // Since NotificationStackScrollLayout is now a sibling of notification_panel, we need
             // to also ask NotificationPanelViewController directly, in order to process swipe up
             // events originating from notifications
-            if (mNotificationPanelViewController.handleExternalInterceptTouch(ev)) {
+            if (mShadeViewController.handleExternalInterceptTouch(ev)) {
                 mShadeLogger.d("NSWVC: NPVC intercepted");
                 return true;
             }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionChangeEvent.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionChangeEvent.kt
index 71dfafa..d9c1f0a 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionChangeEvent.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionChangeEvent.kt
@@ -23,7 +23,5 @@
     /** Whether the panel should be considered expanded */
     val expanded: Boolean,
     /** Whether the user is actively dragging the panel. */
-    val tracking: Boolean,
-    /** The amount of pixels that the user has dragged during the expansion. */
-    val dragDownPxAmount: Float
+    val tracking: Boolean
 )
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt
index df5ff5a..359ddd8 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt
@@ -18,13 +18,13 @@
 
 import android.annotation.IntDef
 import android.os.Trace
-import android.os.Trace.TRACE_TAG_APP as TRACE_TAG
 import android.util.Log
 import androidx.annotation.FloatRange
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.util.Compile
 import java.util.concurrent.CopyOnWriteArrayList
 import javax.inject.Inject
+import android.os.Trace.TRACE_TAG_APP as TRACE_TAG
 
 /**
  * A class responsible for managing the notification panel's current state.
@@ -42,7 +42,6 @@
     @FloatRange(from = 0.0, to = 1.0) private var fraction: Float = 0f
     private var expanded: Boolean = false
     private var tracking: Boolean = false
-    private var dragDownPxAmount: Float = 0f
 
     /**
      * Adds a listener that will be notified when the panel expansion fraction has changed and
@@ -53,7 +52,7 @@
     @Deprecated("Use ShadeInteractor instead")
     fun addExpansionListener(listener: ShadeExpansionListener): ShadeExpansionChangeEvent {
         expansionListeners.add(listener)
-        return ShadeExpansionChangeEvent(fraction, expanded, tracking, dragDownPxAmount)
+        return ShadeExpansionChangeEvent(fraction, expanded, tracking)
     }
 
     /** Adds a listener that will be notified when the panel state has changed. */
@@ -76,8 +75,7 @@
     fun onPanelExpansionChanged(
         @FloatRange(from = 0.0, to = 1.0) fraction: Float,
         expanded: Boolean,
-        tracking: Boolean,
-        dragDownPxAmount: Float
+        tracking: Boolean
     ) {
         require(!fraction.isNaN()) { "fraction cannot be NaN" }
         val oldState = state
@@ -85,7 +83,6 @@
         this.fraction = fraction
         this.expanded = expanded
         this.tracking = tracking
-        this.dragDownPxAmount = dragDownPxAmount
 
         var fullyClosed = true
         var fullyOpened = false
@@ -111,7 +108,6 @@
                 "f=$fraction " +
                 "expanded=$expanded " +
                 "tracking=$tracking " +
-                "dragDownPxAmount=$dragDownPxAmount " +
                 "${if (fullyOpened) " fullyOpened" else ""} " +
                 if (fullyClosed) " fullyClosed" else ""
         )
@@ -124,8 +120,7 @@
             }
         }
 
-        val expansionChangeEvent =
-            ShadeExpansionChangeEvent(fraction, expanded, tracking, dragDownPxAmount)
+        val expansionChangeEvent = ShadeExpansionChangeEvent(fraction, expanded, tracking)
         expansionListeners.forEach { it.onPanelExpansionChanged(expansionChangeEvent) }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
index 2d3833c..648d4b5 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeModule.kt
@@ -162,9 +162,7 @@
 
     @Binds
     @SysUISingleton
-    abstract fun bindsShadeViewController(
-        notificationPanelViewController: NotificationPanelViewController
-    ): ShadeViewController
+    abstract fun bindsShadeViewController(shadeSurface: ShadeSurface): ShadeViewController
 
     @Binds
     @SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
index d02c215..7346a28 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurface.kt
@@ -15,7 +15,6 @@
  */
 package com.android.systemui.shade
 
-import android.view.ViewPropertyAnimator
 import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor
 import com.android.systemui.shade.domain.interactor.ShadeBackActionInteractor
 import com.android.systemui.shade.domain.interactor.ShadeLockscreenInteractor
@@ -48,7 +47,7 @@
     fun cancelAnimation()
 
     /** Animates the view from its current alpha to zero then runs the runnable. */
-    fun fadeOut(startDelayMs: Long, durationMs: Long, endAction: Runnable): ViewPropertyAnimator
+    fun fadeOut(startDelayMs: Long, durationMs: Long, endAction: Runnable)
 
     /** Set whether the bouncer is showing. */
     fun setBouncerShowing(bouncerShowing: Boolean)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeSurfaceImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurfaceImpl.kt
new file mode 100644
index 0000000..adb2928
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeSurfaceImpl.kt
@@ -0,0 +1,87 @@
+/*
+ * 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.shade
+
+import com.android.systemui.statusbar.GestureRecorder
+import com.android.systemui.statusbar.phone.CentralSurfaces
+import com.android.systemui.statusbar.policy.HeadsUpManager
+import javax.inject.Inject
+
+class ShadeSurfaceImpl @Inject constructor() : ShadeSurface, ShadeViewControllerEmptyImpl() {
+    override fun initDependencies(
+        centralSurfaces: CentralSurfaces,
+        recorder: GestureRecorder,
+        hideExpandedRunnable: Runnable,
+        headsUpManager: HeadsUpManager
+    ) {}
+
+    override fun cancelPendingCollapse() {
+        // Do nothing
+    }
+
+    override fun cancelAnimation() {
+        // Do nothing
+    }
+
+    override fun fadeOut(startDelayMs: Long, durationMs: Long, endAction: Runnable) {
+        // Do nothing
+    }
+
+    override fun setBouncerShowing(bouncerShowing: Boolean) {
+        // Do nothing
+    }
+
+    override fun setTouchAndAnimationDisabled(disabled: Boolean) {
+        // TODO(b/322197941): determine if still needed
+    }
+
+    override fun setWillPlayDelayedDozeAmountAnimation(willPlay: Boolean) {
+        // TODO(b/322494538): determine if still needed
+    }
+
+    override fun setDozing(dozing: Boolean, animate: Boolean) {
+        // Do nothing
+    }
+
+    override fun setImportantForAccessibility(mode: Int) {
+        // Do nothing
+    }
+
+    override fun resetTranslation() {
+        // Do nothing
+    }
+
+    override fun resetAlpha() {
+        // Do nothing
+    }
+
+    override fun onScreenTurningOn() {
+        // Do nothing
+    }
+
+    override fun onThemeChanged() {
+        // Do nothing
+    }
+
+    override fun updateExpansionAndVisibility() {
+        // Do nothing
+    }
+
+    override fun updateResources() {
+        // Do nothing
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
index 5b2377f..4e1edd3 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
@@ -33,14 +33,12 @@
     /** Returns whether the shade's top level view is enabled. */
     @Deprecated("No longer supported. Do not add new calls to this.") val isViewEnabled: Boolean
 
-    /** Returns whether status bar icons should be hidden when the shade is expanded. */
-    fun shouldHideStatusBarIconsWhenExpanded(): Boolean
-
     /** If the latency tracker is enabled, begins tracking expand latency. */
     @Deprecated("No longer supported. Do not add new calls to this.")
     fun startExpandLatencyTracking()
 
     /** Sets the alpha value of the shade to a value between 0 and 255. */
+    @Deprecated("No longer supported. Do not add new calls to this.")
     fun setAlpha(alpha: Int, animate: Boolean)
 
     /**
@@ -48,6 +46,7 @@
      *
      * @see .setAlpha
      */
+    @Deprecated("No longer supported. Do not add new calls to this.")
     fun setAlphaChangeAnimationEndAction(r: Runnable)
 
     /** Sets Qs ScrimEnabled and updates QS state. */
@@ -61,7 +60,7 @@
     @Deprecated("Does nothing when scene container is enabled.") fun updateSystemUiStateFlags()
 
     /** Ensures that the touchable region is updated. */
-    fun updateTouchableRegion()
+    @Deprecated("No longer supported. Do not add new calls to this.") fun updateTouchableRegion()
 
     /**
      * Sends an external (e.g. Status Bar) touch event to the Shade touch handler.
@@ -72,6 +71,8 @@
      */
     fun handleExternalTouch(event: MotionEvent): Boolean
 
+    fun handleExternalInterceptTouch(event: MotionEvent): Boolean
+
     /**
      * Triggered when an input focus transfer gesture has started.
      *
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt
index e037c70..0c41efd 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt
@@ -28,7 +28,7 @@
 import kotlinx.coroutines.flow.flowOf
 
 /** Empty implementation of ShadeViewController for variants with no shade. */
-class ShadeViewControllerEmptyImpl @Inject constructor() :
+open class ShadeViewControllerEmptyImpl @Inject constructor() :
     ShadeViewController,
     ShadeBackActionInteractor,
     ShadeLockscreenInteractor,
@@ -81,6 +81,10 @@
     override fun handleExternalTouch(event: MotionEvent): Boolean {
         return false
     }
+    override fun handleExternalInterceptTouch(event: MotionEvent): Boolean {
+        return false
+    }
+
     override fun startInputFocusTransfer() {}
     override fun cancelInputFocusTransfer() {}
     override fun finishInputFocusTransfer(velocity: Float) {}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractor.kt
index 6611303..dfdf2ad 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractor.kt
@@ -72,4 +72,8 @@
 
     /** Returns the StatusBarState. Note: System UI was formerly known simply as Status Bar. */
     @Deprecated("Use SceneInteractor or ShadeInteractor instead") val barState: Int
+
+    /** Returns whether status bar icons should be hidden when the shade is expanded. */
+    @Deprecated("No longer supported. Do not add new calls to this.")
+    fun shouldHideStatusBarIconsWhenExpanded(): Boolean
 }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImpl.kt
index 561d0bc..58bcd2e 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/PanelExpansionInteractorImpl.kt
@@ -69,27 +69,21 @@
                         state.fromScene == Scenes.Gone ->
                             if (state.toScene.isExpandable()) {
                                 // Moving from Gone to a scene that can animate-expand has a
-                                // panel
-                                // expansion
-                                // that tracks with the transition.
+                                // panel expansion that tracks with the transition.
                                 state.progress
                             } else {
                                 // Moving from Gone to a scene that doesn't animate-expand
-                                // immediately makes
-                                // the panel fully expanded.
+                                // immediately makes the panel fully expanded.
                                 flowOf(1f)
                             }
                         state.toScene == Scenes.Gone ->
                             if (state.fromScene.isExpandable()) {
                                 // Moving to Gone from a scene that can animate-expand has a
-                                // panel
-                                // expansion
-                                // that tracks with the transition.
+                                // panel expansion that tracks with the transition.
                                 state.progress.map { 1 - it }
                             } else {
                                 // Moving to Gone from a scene that doesn't animate-expand
-                                // immediately makes
-                                // the panel fully collapsed.
+                                // immediately makes the panel fully collapsed.
                                 flowOf(0f)
                             }
                         else -> flowOf(1f)
@@ -126,6 +120,15 @@
     override val barState
         get() = statusBarStateController.state
 
+    @Deprecated("No longer supported. Do not add new calls to this.")
+    override fun shouldHideStatusBarIconsWhenExpanded(): Boolean {
+        if (shadeAnimationInteractor.isLaunchingActivity.value) {
+            return false
+        }
+        // TODO(b/325936094) if a HUN is showing, return false
+        return sceneInteractor.currentScene.value == Scenes.Lockscreen
+    }
+
     private fun SceneKey.isExpandable(): Boolean {
         return this == Scenes.Shade || this == Scenes.QuickSettings
     }
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 d8216dc..f3802da 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
@@ -23,13 +23,20 @@
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.dagger.ShadeTouchLog
+import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.shade.ShadeExpansionStateManager
 import com.android.systemui.shade.TouchLogger.Companion.logTouchesTo
 import com.android.systemui.shade.data.repository.ShadeRepository
+import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor
 import com.android.systemui.shade.shared.model.ShadeMode
 import com.android.systemui.shade.transition.ScrimShadeTransitionController
 import com.android.systemui.statusbar.policy.SplitShadeStateController
 import javax.inject.Inject
+import javax.inject.Provider
 import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onStart
 import kotlinx.coroutines.launch
@@ -43,23 +50,44 @@
     @ShadeTouchLog private val touchLog: LogBuffer,
     private val configurationRepository: ConfigurationRepository,
     private val shadeRepository: ShadeRepository,
-    private val controller: SplitShadeStateController,
+    private val splitShadeStateController: SplitShadeStateController,
     private val scrimShadeTransitionController: ScrimShadeTransitionController,
+    private val sceneInteractorProvider: Provider<SceneInteractor>,
+    private val panelExpansionInteractorProvider: Provider<PanelExpansionInteractor>,
+    private val shadeExpansionStateManager: ShadeExpansionStateManager,
 ) : CoreStartable {
 
     override fun start() {
         hydrateShadeMode()
+        hydrateShadeExpansionStateManager()
         logTouchesTo(touchLog)
         scrimShadeTransitionController.init()
     }
 
+    private fun hydrateShadeExpansionStateManager() {
+        if (SceneContainerFlag.isEnabled) {
+            combine(
+                panelExpansionInteractorProvider.get().legacyPanelExpansion,
+                sceneInteractorProvider.get().isTransitionUserInputOngoing,
+            ) { panelExpansion, tracking ->
+                shadeExpansionStateManager.onPanelExpansionChanged(
+                    fraction = panelExpansion,
+                    expanded = panelExpansion > 0f,
+                    tracking = tracking,
+                )
+            }.launchIn(applicationScope)
+        }
+    }
+
     private fun hydrateShadeMode() {
         applicationScope.launch {
             configurationRepository.onAnyConfigurationChange
                 // Force initial collection.
                 .onStart { emit(Unit) }
                 .map { applicationContext.resources }
-                .map { resources -> controller.shouldUseSplitNotificationShade(resources) }
+                .map { resources ->
+                    splitShadeStateController.shouldUseSplitNotificationShade(resources)
+                }
                 .collect { isSplitShade ->
                     shadeRepository.setShadeMode(
                         if (isSplitShade) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt
index 151e289..e38e53d 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt
@@ -17,28 +17,20 @@
 package com.android.systemui.shade.transition
 
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dump.DumpManager
-import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.shade.PanelState
 import com.android.systemui.shade.ShadeExpansionChangeEvent
 import com.android.systemui.shade.ShadeExpansionStateManager
-import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor
 import com.android.systemui.statusbar.phone.ScrimController
-import dagger.Lazy
 import java.io.PrintWriter
 import javax.inject.Inject
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.launch
 
 /** Controls the scrim properties during the shade expansion transition on non-lockscreen. */
 @SysUISingleton
 class ScrimShadeTransitionController
 @Inject
 constructor(
-    @Application private val applicationScope: CoroutineScope,
     private val shadeExpansionStateManager: ShadeExpansionStateManager,
-    private val panelExpansionInteractor: Lazy<PanelExpansionInteractor>,
     private val dumpManager: DumpManager,
     private val scrimController: ScrimController,
 ) {
@@ -47,32 +39,17 @@
     private var currentPanelState: Int? = null
 
     fun init() {
-        if (SceneContainerFlag.isEnabled) {
-            applicationScope.launch {
-                panelExpansionInteractor.get().legacyPanelExpansion.collect { panelExpansion ->
-                    onPanelExpansionChanged(
-                        ShadeExpansionChangeEvent(
-                            fraction = panelExpansion,
-                            expanded = panelExpansion > 0f,
-                            tracking = true,
-                            dragDownPxAmount = 0f,
-                        )
-                    )
-                }
-            }
-        } else {
-            val currentState =
-                shadeExpansionStateManager.addExpansionListener(this::onPanelExpansionChanged)
-            onPanelExpansionChanged(currentState)
-            shadeExpansionStateManager.addStateListener(this::onPanelStateChanged)
-        }
+        val currentState =
+            shadeExpansionStateManager.addExpansionListener(this::onPanelExpansionChanged)
+        onPanelExpansionChanged(currentState)
+        shadeExpansionStateManager.addStateListener(this::onPanelStateChanged)
         dumpManager.registerDumpable(
             ScrimShadeTransitionController::class.java.simpleName,
             this::dump
         )
     }
 
-    fun onPanelStateChanged(@PanelState state: Int) {
+    private fun onPanelStateChanged(@PanelState state: Int) {
         currentPanelState = state
         onStateChanged()
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java
index 8d7fc98..acb5339 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java
@@ -19,8 +19,6 @@
 import android.util.AttributeSet;
 import android.widget.TextView;
 
-import com.android.settingslib.WirelessUtils;
-
 /** Shows the operator name */
 public class OperatorNameView extends TextView {
     private boolean mDemoMode;
@@ -41,13 +39,14 @@
         mDemoMode = demoMode;
     }
 
-    void update(boolean showOperatorName,
+    void update(
+            boolean showOperatorName,
             boolean hasMobile,
+            boolean airplaneMode,
             OperatorNameViewController.SubInfo sub
     ) {
         setVisibility(showOperatorName ? VISIBLE : GONE);
 
-        boolean airplaneMode = WirelessUtils.isAirplaneModeOn(mContext);
         if (!hasMobile || airplaneMode) {
             setText(null);
             setVisibility(GONE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameViewController.java
index 8afc72f..6e7d8f4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameViewController.java
@@ -16,11 +16,9 @@
 
 package com.android.systemui.statusbar;
 
-import android.annotation.NonNull;
 import android.os.Bundle;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionInfo;
-import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.view.View;
 
@@ -28,47 +26,60 @@
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.demomode.DemoModeCommandReceiver;
 import com.android.systemui.plugins.DarkIconDispatcher;
-import com.android.systemui.statusbar.connectivity.IconState;
-import com.android.systemui.statusbar.connectivity.NetworkController;
-import com.android.systemui.statusbar.connectivity.SignalCallback;
 import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
+import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor;
+import com.android.systemui.statusbar.pipeline.mobile.util.SubscriptionManagerProxy;
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.util.CarrierConfigTracker;
 import com.android.systemui.util.ViewController;
+import com.android.systemui.util.kotlin.JavaAdapter;
 
 import javax.inject.Inject;
 
+import kotlinx.coroutines.Job;
+
 /** Controller for {@link OperatorNameView}. */
 public class OperatorNameViewController extends ViewController<OperatorNameView> {
     private static final String KEY_SHOW_OPERATOR_NAME = "show_operator_name";
 
     private final DarkIconDispatcher mDarkIconDispatcher;
-    private final NetworkController mNetworkController;
     private final TunerService mTunerService;
     private final TelephonyManager mTelephonyManager;
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     private final CarrierConfigTracker mCarrierConfigTracker;
+    private final AirplaneModeInteractor mAirplaneModeInteractor;
+    private final SubscriptionManagerProxy mSubscriptionManagerProxy;
+    private final JavaAdapter mJavaAdapter;
+
+    private Job mAirplaneModeJob;
 
     private OperatorNameViewController(OperatorNameView view,
             DarkIconDispatcher darkIconDispatcher,
-            NetworkController networkController,
             TunerService tunerService,
             TelephonyManager telephonyManager,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
-            CarrierConfigTracker carrierConfigTracker) {
+            CarrierConfigTracker carrierConfigTracker,
+            AirplaneModeInteractor airplaneModeInteractor,
+            SubscriptionManagerProxy subscriptionManagerProxy,
+            JavaAdapter javaAdapter) {
         super(view);
         mDarkIconDispatcher = darkIconDispatcher;
-        mNetworkController = networkController;
         mTunerService = tunerService;
         mTelephonyManager = telephonyManager;
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mCarrierConfigTracker = carrierConfigTracker;
+        mAirplaneModeInteractor = airplaneModeInteractor;
+        mSubscriptionManagerProxy = subscriptionManagerProxy;
+        mJavaAdapter = javaAdapter;
     }
 
     @Override
     protected void onViewAttached() {
         mDarkIconDispatcher.addDarkReceiver(mDarkReceiver);
-        mNetworkController.addCallback(mSignalCallback);
+        mAirplaneModeJob =
+                mJavaAdapter.alwaysCollectFlow(
+                        mAirplaneModeInteractor.isAirplaneMode(),
+                        (isAirplaneMode) -> update());
         mTunerService.addTunable(mTunable, KEY_SHOW_OPERATOR_NAME);
         mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
     }
@@ -76,7 +87,7 @@
     @Override
     protected void onViewDetached() {
         mDarkIconDispatcher.removeDarkReceiver(mDarkReceiver);
-        mNetworkController.removeCallback(mSignalCallback);
+        mAirplaneModeJob.cancel(null);
         mTunerService.removeTunable(mTunable);
         mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback);
     }
@@ -87,11 +98,17 @@
                 mCarrierConfigTracker
                         .getShowOperatorNameInStatusBarConfig(defaultSubInfo.getSubId())
                         && (mTunerService.getValue(KEY_SHOW_OPERATOR_NAME, 1) != 0);
-        mView.update(showOperatorName, mTelephonyManager.isDataCapable(), getDefaultSubInfo());
+        mView.update(
+                showOperatorName,
+                mTelephonyManager.isDataCapable(),
+                mAirplaneModeInteractor.isAirplaneMode().getValue(),
+                getDefaultSubInfo()
+        );
     }
 
     private SubInfo getDefaultSubInfo() {
-        int defaultSubId = SubscriptionManager.getDefaultDataSubscriptionId();
+        int defaultSubId = mSubscriptionManagerProxy.getDefaultDataSubscriptionId();
+
         SubscriptionInfo sI = mKeyguardUpdateMonitor.getSubscriptionInfoForSubId(defaultSubId);
         return new SubInfo(
                 sI.getSubscriptionId(),
@@ -103,36 +120,44 @@
     /** Factory for constructing an {@link OperatorNameViewController}. */
     public static class Factory {
         private final DarkIconDispatcher mDarkIconDispatcher;
-        private final NetworkController mNetworkController;
         private final TunerService mTunerService;
         private final TelephonyManager mTelephonyManager;
         private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
         private final CarrierConfigTracker mCarrierConfigTracker;
+        private final AirplaneModeInteractor mAirplaneModeInteractor;
+        private final SubscriptionManagerProxy mSubscriptionManagerProxy;
+        private final JavaAdapter mJavaAdapter;
 
         @Inject
         public Factory(DarkIconDispatcher darkIconDispatcher,
-                NetworkController networkController,
                 TunerService tunerService,
                 TelephonyManager telephonyManager,
                 KeyguardUpdateMonitor keyguardUpdateMonitor,
-                CarrierConfigTracker carrierConfigTracker) {
+                CarrierConfigTracker carrierConfigTracker,
+                AirplaneModeInteractor airplaneModeInteractor,
+                SubscriptionManagerProxy subscriptionManagerProxy,
+                JavaAdapter javaAdapter) {
             mDarkIconDispatcher = darkIconDispatcher;
-            mNetworkController = networkController;
             mTunerService = tunerService;
             mTelephonyManager = telephonyManager;
             mKeyguardUpdateMonitor = keyguardUpdateMonitor;
             mCarrierConfigTracker = carrierConfigTracker;
+            mAirplaneModeInteractor = airplaneModeInteractor;
+            mSubscriptionManagerProxy = subscriptionManagerProxy;
+            mJavaAdapter = javaAdapter;
         }
 
         /** Create an {@link OperatorNameViewController}. */
         public OperatorNameViewController create(OperatorNameView view) {
             return new OperatorNameViewController(view,
                     mDarkIconDispatcher,
-                    mNetworkController,
                     mTunerService,
                     mTelephonyManager,
                     mKeyguardUpdateMonitor,
-                    mCarrierConfigTracker);
+                    mCarrierConfigTracker,
+                    mAirplaneModeInteractor,
+                    mSubscriptionManagerProxy,
+                    mJavaAdapter);
         }
     }
 
@@ -149,13 +174,6 @@
             (area, darkIntensity, tint) ->
                     mView.setTextColor(DarkIconDispatcher.getTint(area, mView, tint));
 
-    private final SignalCallback mSignalCallback = new SignalCallback() {
-        @Override
-        public void setIsAirplaneMode(@NonNull IconState icon) {
-            update();
-        }
-    };
-
     private final TunerService.Tunable mTunable = (key, newValue) -> update();
 
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
index f960fca..e5b6497 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
@@ -35,9 +35,11 @@
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.media.controls.domain.pipeline.MediaDataManager;
 import com.android.systemui.power.domain.interactor.PowerInteractor;
+import com.android.systemui.scene.shared.flag.SceneContainerFlags;
 import com.android.systemui.settings.DisplayTracker;
 import com.android.systemui.shade.NotificationPanelViewController;
 import com.android.systemui.shade.ShadeSurface;
+import com.android.systemui.shade.ShadeSurfaceImpl;
 import com.android.systemui.shade.carrier.ShadeCarrierGroupController;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NotificationClickNotifier;
@@ -59,6 +61,8 @@
 import com.android.systemui.statusbar.phone.StatusBarRemoteInputCallback;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
+import javax.inject.Provider;
+
 import dagger.Binds;
 import dagger.Lazy;
 import dagger.Module;
@@ -178,9 +182,20 @@
      * The {@link com.android.systemui.shade.ShadeViewController} interface is bound in
      * {@link com.android.systemui.shade.ShadeModule} so others can access it.
      */
-    @Binds
+    @Provides
     @SysUISingleton
-    ShadeSurface provideShadeSurface(NotificationPanelViewController impl);
+    static ShadeSurface provideShadeSurface(
+            SceneContainerFlags sceneContainerFlags,
+            Provider<ShadeSurfaceImpl> sceneContainerOn,
+            Provider<NotificationPanelViewController> sceneContainerOff) {
+        if (sceneContainerFlags.isEnabled()) {
+            return sceneContainerOn.get();
+        } else {
+            return sceneContainerOff.get();
+        }
+
+    }
+
 
     /** */
     @Binds
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index 7c71864..4c66f66 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -23,7 +23,9 @@
 import com.android.app.animation.Interpolators
 import com.android.app.animation.InterpolatorsAndroidX
 import com.android.systemui.Dumpable
+import com.android.systemui.communal.domain.interactor.CommunalInteractor
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.shade.ShadeExpansionChangeEvent
@@ -47,11 +49,14 @@
 import javax.inject.Inject
 import kotlin.math.max
 import kotlin.math.min
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
 
 @SysUISingleton
 class NotificationWakeUpCoordinator
 @Inject
 constructor(
+    @Application applicationScope: CoroutineScope,
     dumpManager: DumpManager,
     private val mHeadsUpManager: HeadsUpManager,
     private val statusBarStateController: StatusBarStateController,
@@ -60,6 +65,7 @@
     private val screenOffAnimationController: ScreenOffAnimationController,
     private val logger: NotificationWakeUpCoordinatorLogger,
     private val notifsKeyguardInteractor: NotificationsKeyguardInteractor,
+    private val communalInteractor: CommunalInteractor,
 ) :
     OnHeadsUpChangedListener,
     StatusBarStateController.StateListener,
@@ -201,6 +207,13 @@
                 }
             }
         )
+        applicationScope.launch {
+            communalInteractor.isIdleOnCommunal.collect {
+                if (!overrideDozeAmountIfCommunalShowing()) {
+                    maybeClearHardDozeAmountOverrideHidingNotifs()
+                }
+            }
+        }
     }
 
     fun setStackScroller(stackScrollerController: NotificationStackScrollLayoutController) {
@@ -302,6 +315,10 @@
             return
         }
 
+        if (overrideDozeAmountIfCommunalShowing()) {
+            return
+        }
+
         if (clearHardDozeAmountOverride()) {
             return
         }
@@ -311,9 +328,12 @@
 
     private fun setHardDozeAmountOverride(dozing: Boolean, source: String) {
         logger.logSetDozeAmountOverride(dozing = dozing, source = source)
+        val previousOverride = hardDozeAmountOverride
         hardDozeAmountOverride = if (dozing) 1f else 0f
         hardDozeAmountOverrideSource = source
-        updateDozeAmount()
+        if (previousOverride != hardDozeAmountOverride) {
+            updateDozeAmount()
+        }
     }
 
     private fun clearHardDozeAmountOverride(): Boolean {
@@ -434,6 +454,11 @@
             return
         }
 
+        if (overrideDozeAmountIfCommunalShowing()) {
+            this.state = newState
+            return
+        }
+
         maybeClearHardDozeAmountOverrideHidingNotifs()
 
         this.state = newState
@@ -471,6 +496,18 @@
         return false
     }
 
+    private fun overrideDozeAmountIfCommunalShowing(): Boolean {
+        if (communalInteractor.isIdleOnCommunal.value) {
+            if (statusBarStateController.state == StatusBarState.KEYGUARD) {
+                setHardDozeAmountOverride(dozing = true, source = "Override: communal (keyguard)")
+            } else {
+                setHardDozeAmountOverride(dozing = false, source = "Override: communal (shade)")
+            }
+            return true
+        }
+        return false
+    }
+
     /**
      * If the last [setDozeAmount] call was an override to hide notifications, then this call will
      * check for the set of states that may have caused that override, and if none of them still
@@ -483,20 +520,23 @@
             val onKeyguard = statusBarStateController.state == StatusBarState.KEYGUARD
             val dozing = statusBarStateController.isDozing
             val bypass = bypassController.bypassEnabled
+            val idleOnCommunal = communalInteractor.isIdleOnCommunal.value
             val animating =
                 screenOffAnimationController.overrideNotificationsFullyDozingOnKeyguard()
-            // Overrides are set by [overrideDozeAmountIfAnimatingScreenOff] and
-            // [overrideDozeAmountIfBypass] based on 'animating' and 'bypass' respectively, so only
-            // clear the override if both those conditions are cleared.  But also require either
+            // Overrides are set by [overrideDozeAmountIfAnimatingScreenOff],
+            // [overrideDozeAmountIfBypass] and [overrideDozeAmountIfCommunalShowing] based on
+            // 'animating', 'bypass' and 'idleOnCommunal' respectively, so only clear the override
+            // if all of those conditions are cleared.  But also require either
             // !dozing or !onKeyguard because those conditions should indicate that we intend
             // notifications to be visible, and thus it is safe to unhide them.
-            val willRemove = (!onKeyguard || !dozing) && !bypass && !animating
+            val willRemove = (!onKeyguard || !dozing) && !bypass && !animating && !idleOnCommunal
             logger.logMaybeClearHardDozeAmountOverrideHidingNotifs(
                 willRemove = willRemove,
                 onKeyguard = onKeyguard,
                 dozing = dozing,
                 bypass = bypass,
                 animating = animating,
+                idleOnCommunal = idleOnCommunal,
             )
             if (willRemove) {
                 clearHardDozeAmountOverride()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt
index 502e1d9..9619bea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt
@@ -95,6 +95,7 @@
         onKeyguard: Boolean,
         dozing: Boolean,
         bypass: Boolean,
+        idleOnCommunal: Boolean,
         animating: Boolean,
     ) {
         buffer.log(
@@ -103,7 +104,7 @@
             {
                 str1 =
                     "willRemove=$willRemove onKeyguard=$onKeyguard dozing=$dozing" +
-                        " bypass=$bypass animating=$animating"
+                        " bypass=$bypass animating=$animating idleOnCommunal=$idleOnCommunal"
             },
             { "maybeClearHardDozeAmountOverrideHidingNotifs() $str1" }
         )
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 b6f653f..2798dbf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -164,6 +164,7 @@
 import com.android.systemui.qs.QSPanelController;
 import com.android.systemui.res.R;
 import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor;
+import com.android.systemui.scene.shared.flag.SceneContainerFlag;
 import com.android.systemui.scene.shared.flag.SceneContainerFlags;
 import com.android.systemui.scrim.ScrimView;
 import com.android.systemui.settings.UserTracker;
@@ -1256,11 +1257,13 @@
         mScreenOffAnimationController.initialize(this, mShadeSurface, mLightRevealScrim);
         updateLightRevealScrimVisibility();
 
-        mShadeSurface.initDependencies(
-                this,
-                mGestureRec,
-                mShadeController::makeExpandedInvisible,
-                mHeadsUpManager);
+        if (!SceneContainerFlag.isEnabled()) {
+            mShadeSurface.initDependencies(
+                    this,
+                    mGestureRec,
+                    mShadeController::makeExpandedInvisible,
+                    mHeadsUpManager);
+        }
 
         // Set up the quick settings tile panel
         final View container = getNotificationShadeWindowView().findViewById(R.id.qs_frame);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt
index 82b10bc..eadb7f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt
@@ -23,12 +23,12 @@
 import android.widget.FrameLayout
 import androidx.annotation.StringRes
 import com.android.keyguard.LockIconViewController
-import com.android.systemui.res.R
 import com.android.systemui.keyguard.ui.binder.KeyguardBottomAreaViewBinder
 import com.android.systemui.keyguard.ui.binder.KeyguardBottomAreaViewBinder.bind
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.res.R
 import com.android.systemui.statusbar.VibratorHelper
 
 /**
@@ -155,13 +155,13 @@
                 // make top of ambient indication view the bottom of the lock icon
                 it.layout(
                     ambientLeft,
-                    lockIconViewController?.bottom?.toInt() ?: 0,
+                    lockIconViewController?.getBottom()?.toInt() ?: 0,
                     right - ambientLeft,
                     ambientTop + it.measuredHeight
                 )
             } else {
                 // make bottom of ambient indication view the top of the lock icon
-                val lockLocationTop = lockIconViewController?.top ?: 0
+                val lockLocationTop = lockIconViewController?.getTop() ?: 0
                 it.layout(
                     ambientLeft,
                     lockLocationTop.toInt() - it.measuredHeight,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index febe5a2..afd2415 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -579,7 +579,7 @@
             ViewRootImpl viewRoot = getViewRootImpl();
             if (viewRoot != null) {
                 viewRoot.getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
-                        OnBackInvokedDispatcher.PRIORITY_OVERLAY, mOnBackInvokedCallback);
+                        OnBackInvokedDispatcher.PRIORITY_DEFAULT, mOnBackInvokedCallback);
                 mIsBackCallbackRegistered = true;
             } else {
                 if (DEBUG) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index 617e107..c52132f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -46,7 +46,7 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.res.R;
 import com.android.systemui.shade.ShadeExpansionStateManager;
-import com.android.systemui.shade.ShadeViewController;
+import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.OperatorNameView;
 import com.android.systemui.statusbar.OperatorNameViewController;
@@ -79,6 +79,8 @@
 import com.android.systemui.util.CarrierConfigTracker.DefaultDataSubscriptionChangedListener;
 import com.android.systemui.util.settings.SecureSettings;
 
+import kotlin.Unit;
+
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -89,8 +91,6 @@
 
 import javax.inject.Inject;
 
-import kotlin.Unit;
-
 import kotlinx.coroutines.DisposableHandle;
 
 /**
@@ -115,7 +115,7 @@
     private PhoneStatusBarView mStatusBar;
     private final StatusBarStateController mStatusBarStateController;
     private final KeyguardStateController mKeyguardStateController;
-    private final ShadeViewController mShadeViewController;
+    private final PanelExpansionInteractor mPanelExpansionInteractor;
     private MultiSourceMinAlphaController mEndSideAlphaController;
     private LinearLayout mEndSideContent;
     private View mClockView;
@@ -227,7 +227,7 @@
             CollapsedStatusBarViewBinder collapsedStatusBarViewBinder,
             StatusBarHideIconsForBouncerManager statusBarHideIconsForBouncerManager,
             KeyguardStateController keyguardStateController,
-            ShadeViewController shadeViewController,
+            PanelExpansionInteractor panelExpansionInteractor,
             StatusBarStateController statusBarStateController,
             NotificationIconContainerStatusBarViewBinder nicViewBinder,
             CommandQueue commandQueue,
@@ -252,7 +252,7 @@
         mStatusBarHideIconsForBouncerManager = statusBarHideIconsForBouncerManager;
         mDarkIconManagerFactory = darkIconManagerFactory;
         mKeyguardStateController = keyguardStateController;
-        mShadeViewController = shadeViewController;
+        mPanelExpansionInteractor = panelExpansionInteractor;
         mStatusBarStateController = statusBarStateController;
         mNicViewBinder = nicViewBinder;
         mCommandQueue = commandQueue;
@@ -603,7 +603,7 @@
 
     private boolean shouldHideStatusBar() {
         if (!mShadeExpansionStateManager.isClosed()
-                && mShadeViewController.shouldHideStatusBarIconsWhenExpanded()) {
+                && mPanelExpansionInteractor.shouldHideStatusBarIconsWhenExpanded()) {
             return true;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractor.kt
index c6c8823..684e38e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractor.kt
@@ -23,6 +23,7 @@
 import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
 import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.map
 
 /**
@@ -40,7 +41,7 @@
     private val mobileConnectionsRepository: MobileConnectionsRepository,
 ) {
     /** True if the device is currently in airplane mode. */
-    val isAirplaneMode: Flow<Boolean> = airplaneModeRepository.isAirplaneMode
+    val isAirplaneMode: StateFlow<Boolean> = airplaneModeRepository.isAirplaneMode
 
     /** True if we're configured to force-hide the airplane mode icon and false otherwise. */
     val isForceHidden: Flow<Boolean> =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java
index 068e0a6..860068c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java
@@ -94,7 +94,8 @@
 
                         int packageUid;
                         try {
-                            packageUid = mPackageManager.getPackageUid(info.getPackageName(), 0);
+                            packageUid = mPackageManager.getPackageUidAsUser(info.getPackageName(),
+                                    info.getUserHandle().getIdentifier());
                         } catch (PackageManager.NameNotFoundException e) {
                             Log.w(LOG_TAG, "Package " + info.getPackageName() + " not found");
                             packageUid = -1;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModel.kt
index 0207d6e..04d7b1f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModel.kt
@@ -36,10 +36,15 @@
     }
 
     fun onSettingsClicked() {
-        activityStarter.startActivity(
-            Intent(Settings.ACTION_SOUND_SETTINGS)
-                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_REORDER_TO_FRONT),
-            true,
-        ) { volumePanelViewModel.dismissPanel() }
+        activityStarter.startActivityDismissingKeyguard(
+            /* intent = */ Intent(Settings.ACTION_SOUND_SETTINGS),
+            /* onlyProvisioned = */ false,
+            /* dismissShade = */ true,
+            /* disallowEnterPictureInPictureWhileLaunching = */ false,
+            /* callback = */ { volumePanelViewModel.dismissPanel() },
+            /* flags = */ Intent.FLAG_ACTIVITY_REORDER_TO_FRONT,
+            /* animationController = */ null,
+            /* userHandle = */ null,
+        )
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java b/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
index 1d9b90a..ff18418 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
@@ -91,17 +91,22 @@
             @Background Executor bgExecutor,
             SecureSettings secureSettings,
             QuickAccessWalletClient quickAccessWalletClient,
-            SystemClock clock) {
+            SystemClock clock,
+            RoleManager roleManager) {
         mContext = context;
         mExecutor = executor;
         mBgExecutor = bgExecutor;
         mSecureSettings = secureSettings;
-        mRoleManager = mContext.getSystemService(RoleManager.class);
+        mRoleManager = roleManager;
         mQuickAccessWalletClient = quickAccessWalletClient;
         mClock = clock;
         mQawClientCreatedTimeMillis = mClock.elapsedRealtime();
     }
 
+    public boolean isWalletRoleAvailable() {
+        return mRoleManager.isRoleAvailable(RoleManager.ROLE_WALLET);
+    }
+
     /**
      * Returns true if the Quick Access Wallet service & feature is available.
      */
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LegacyLockIconViewControllerBaseTest.java
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
rename to packages/SystemUI/tests/src/com/android/keyguard/LegacyLockIconViewControllerBaseTest.java
index 1c77351..f924ab4 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LegacyLockIconViewControllerBaseTest.java
@@ -68,7 +68,7 @@
 import org.mockito.MockitoSession;
 import org.mockito.quality.Strictness;
 
-public class LockIconViewControllerBaseTest extends SysuiTestCase {
+public class LegacyLockIconViewControllerBaseTest extends SysuiTestCase {
     protected static final String UNLOCKED_LABEL = "unlocked";
     protected static final String LOCKED_LABEL = "locked";
     protected static final int PADDING = 10;
@@ -98,7 +98,7 @@
 
     protected @Mock PrimaryBouncerInteractor mPrimaryBouncerInteractor;
 
-    protected LockIconViewController mUnderTest;
+    protected LegacyLockIconViewController mUnderTest;
 
     // Capture listeners so that they can be used to send events
     @Captor protected ArgumentCaptor<View.OnAttachStateChangeListener> mAttachCaptor =
@@ -153,7 +153,7 @@
         mFeatureFlags.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false);
         mFeatureFlags.set(LOCKSCREEN_ENABLE_LANDSCAPE, false);
 
-        mUnderTest = new LockIconViewController(
+        mUnderTest = new LegacyLockIconViewController(
                 mStatusBarStateController,
                 mKeyguardUpdateMonitor,
                 mKeyguardViewController,
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/LegacyLockIconViewControllerTest.java
similarity index 99%
rename from packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java
rename to packages/SystemUI/tests/src/com/android/keyguard/LegacyLockIconViewControllerTest.java
index b0887ef..8689842 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LegacyLockIconViewControllerTest.java
@@ -51,7 +51,7 @@
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
-public class LockIconViewControllerTest extends LockIconViewControllerBaseTest {
+public class LegacyLockIconViewControllerTest extends LegacyLockIconViewControllerBaseTest {
 
     @Override
     public void setUp() throws Exception {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/LegacyLockIconViewControllerWithCoroutinesTest.kt
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerWithCoroutinesTest.kt
rename to packages/SystemUI/tests/src/com/android/keyguard/LegacyLockIconViewControllerWithCoroutinesTest.kt
index 1213518..25a87b8 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/LockIconViewControllerWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/LegacyLockIconViewControllerWithCoroutinesTest.kt
@@ -39,7 +39,7 @@
 
 @RunWith(AndroidTestingRunner::class)
 @SmallTest
-class LockIconViewControllerWithCoroutinesTest : LockIconViewControllerBaseTest() {
+class LegacyLockIconViewControllerWithCoroutinesTest : LegacyLockIconViewControllerBaseTest() {
 
     /** After migration, replaces LockIconViewControllerTest version */
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
index de696f4..71f6081 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
@@ -165,7 +165,7 @@
         mMenuView = spy(
                 new MenuView(mSpyContext, mMenuViewModel, menuViewAppearance, mSecureSettings));
         // Ensure tests don't actually update metrics.
-        doNothing().when(mMenuView).incrementTexMetric(any(), anyInt());
+        doNothing().when(mMenuView).incrementTexMetric(any());
 
         mMenuViewLayer = spy(new MenuViewLayer(mSpyContext, mStubWindowManager,
                 mStubAccessibilityManager, mMenuViewModel, menuViewAppearance, mMenuView,
@@ -414,33 +414,25 @@
     @Test
     @EnableFlags(Flags.FLAG_FLOATING_MENU_DRAG_TO_EDIT)
     public void onDismissAction_incrementsTexMetricDismiss() {
-        int uid1 = 1234, uid2 = 5678;
         mMenuViewModel.onTargetFeaturesChanged(
-                List.of(new TestAccessibilityTarget(mSpyContext, uid1),
-                        new TestAccessibilityTarget(mSpyContext, uid2)));
+                List.of(new TestAccessibilityTarget(mSpyContext, 1234),
+                        new TestAccessibilityTarget(mSpyContext, 5678)));
 
         mMenuViewLayer.dispatchAccessibilityAction(R.id.action_remove_menu);
 
-        ArgumentCaptor<Integer> uidCaptor = ArgumentCaptor.forClass(Integer.class);
-        verify(mMenuView, times(2)).incrementTexMetric(eq(MenuViewLayer.TEX_METRIC_DISMISS),
-                uidCaptor.capture());
-        assertThat(uidCaptor.getAllValues()).containsExactly(uid1, uid2);
+        verify(mMenuView, times(1)).incrementTexMetric(eq(MenuViewLayer.TEX_METRIC_DISMISS));
     }
 
     @Test
     @EnableFlags(Flags.FLAG_FLOATING_MENU_DRAG_TO_EDIT)
     public void onEditAction_incrementsTexMetricEdit() {
-        int uid1 = 1234, uid2 = 5678;
         mMenuViewModel.onTargetFeaturesChanged(
-                List.of(new TestAccessibilityTarget(mSpyContext, uid1),
-                        new TestAccessibilityTarget(mSpyContext, uid2)));
+                List.of(new TestAccessibilityTarget(mSpyContext, 1234),
+                        new TestAccessibilityTarget(mSpyContext, 5678)));
 
         mMenuViewLayer.dispatchAccessibilityAction(R.id.action_edit);
 
-        ArgumentCaptor<Integer> uidCaptor = ArgumentCaptor.forClass(Integer.class);
-        verify(mMenuView, times(2)).incrementTexMetric(eq(MenuViewLayer.TEX_METRIC_EDIT),
-                uidCaptor.capture());
-        assertThat(uidCaptor.getAllValues()).containsExactly(uid1, uid2);
+        verify(mMenuView, times(1)).incrementTexMetric(eq(MenuViewLayer.TEX_METRIC_EDIT));
     }
 
     /** Simplified AccessibilityTarget for testing MenuViewLayer. */
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java
new file mode 100644
index 0000000..38e3171
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.hearingaid;
+
+import static com.android.systemui.statusbar.phone.SystemUIDialog.DEFAULT_DISMISS_ON_DEVICE_LOCK;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.animation.DialogTransitionAnimator;
+import com.android.systemui.model.SysUiState;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
+import com.android.systemui.statusbar.phone.SystemUIDialogManager;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+/** Tests for {@link HearingDevicesDialogDelegate}. */
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@SmallTest
+public class HearingDevicesDialogDelegateTest extends SysuiTestCase {
+    @Rule
+    public MockitoRule mockito = MockitoJUnit.rule();
+
+    @Mock
+    private SystemUIDialog.Factory mSystemUIDialogFactory;
+    @Mock
+    private SystemUIDialogManager mSystemUIDialogManager;
+    @Mock
+    private SysUiState mSysUiState;
+    @Mock
+    private DialogTransitionAnimator mDialogTransitionAnimator;
+    private SystemUIDialog mDialog;
+    private HearingDevicesDialogDelegate mDialogDelegate;
+
+    @Before
+    public void setUp() {
+        mDialogDelegate = new HearingDevicesDialogDelegate(mSystemUIDialogFactory);
+        mDialog = new SystemUIDialog(
+                mContext,
+                0,
+                DEFAULT_DISMISS_ON_DEVICE_LOCK,
+                mSystemUIDialogManager,
+                mSysUiState,
+                getFakeBroadcastDispatcher(),
+                mDialogTransitionAnimator,
+                mDialogDelegate
+        );
+
+        when(mSystemUIDialogFactory.create(any(SystemUIDialog.Delegate.class)))
+                .thenReturn(mDialog);
+    }
+
+    @Test
+    public void createDialog_dialogShown() {
+        assertThat(mDialogDelegate.createDialog()).isEqualTo(mDialog);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt
index 58273d6..4f2b690 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySectionTest.kt
@@ -22,7 +22,7 @@
 import androidx.constraintlayout.widget.ConstraintLayout
 import androidx.constraintlayout.widget.ConstraintSet
 import androidx.test.filters.SmallTest
-import com.android.keyguard.LockIconViewController
+import com.android.keyguard.LegacyLockIconViewController
 import com.android.systemui.Flags as AConfigFlags
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.biometrics.AuthController
@@ -58,7 +58,7 @@
     @Mock(answer = Answers.RETURNS_DEEP_STUBS) private lateinit var windowManager: WindowManager
     @Mock private lateinit var notificationPanelView: NotificationPanelView
     private lateinit var featureFlags: FakeFeatureFlags
-    @Mock private lateinit var lockIconViewController: LockIconViewController
+    @Mock private lateinit var lockIconViewController: LegacyLockIconViewController
     @Mock private lateinit var falsingManager: FalsingManager
     @Mock private lateinit var deviceEntryIconViewModel: DeviceEntryIconViewModel
     private lateinit var underTest: DefaultDeviceEntrySection
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/domain/repository/IconTilesRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/domain/repository/IconTilesRepositoryImplTest.kt
new file mode 100644
index 0000000..8cc3a85
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/domain/repository/IconTilesRepositoryImplTest.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.panels.domain.repository
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.qs.panels.data.repository.IconTilesRepositoryImpl
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class IconTilesRepositoryImplTest : SysuiTestCase() {
+
+    private val underTest = IconTilesRepositoryImpl()
+
+    @Test
+    fun iconTilesSpecsIsValid() = runTest {
+        val tilesSpecs by collectLastValue(underTest.iconTilesSpecs)
+        assertThat(tilesSpecs).isEqualTo(ICON_ONLY_TILES_SPECS)
+    }
+
+    companion object {
+        private val ICON_ONLY_TILES_SPECS =
+            setOf(
+                TileSpec.create("airplane"),
+                TileSpec.create("battery"),
+                TileSpec.create("cameratoggle"),
+                TileSpec.create("cast"),
+                TileSpec.create("color_correction"),
+                TileSpec.create("inversion"),
+                TileSpec.create("saver"),
+                TileSpec.create("dnd"),
+                TileSpec.create("flashlight"),
+                TileSpec.create("location"),
+                TileSpec.create("mictoggle"),
+                TileSpec.create("nfc"),
+                TileSpec.create("night"),
+                TileSpec.create("rotation")
+            )
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HearingDevicesTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HearingDevicesTileTest.java
index 326df5c..73aa54c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HearingDevicesTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HearingDevicesTileTest.java
@@ -21,6 +21,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.content.Intent;
 import android.os.Handler;
@@ -29,12 +30,14 @@
 import android.provider.Settings;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
+import android.view.View;
 
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.Flags;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.accessibility.hearingaid.HearingDevicesDialogManager;
 import com.android.systemui.classifier.FalsingManagerFake;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -73,6 +76,8 @@
     private ActivityStarter mActivityStarter;
     @Mock
     private QSLogger mQSLogger;
+    @Mock
+    HearingDevicesDialogManager mHearingDevicesDialogManager;
 
     private TestableLooper mTestableLooper;
     private HearingDevicesTile mTile;
@@ -80,6 +85,7 @@
     @Before
     public void setUp() throws Exception {
         mTestableLooper = TestableLooper.get(this);
+        when(mHost.getContext()).thenReturn(mContext);
 
         mTile = new HearingDevicesTile(
                 mHost,
@@ -90,7 +96,8 @@
                 mMetricsLogger,
                 mStatusBarStateController,
                 mActivityStarter,
-                mQSLogger);
+                mQSLogger,
+                mHearingDevicesDialogManager);
 
         mTile.initialize();
         mTestableLooper.processAllMessages();
@@ -125,4 +132,13 @@
         assertThat(IntentCaptor.getValue().getAction()).isEqualTo(
                 Settings.ACTION_HEARING_DEVICES_SETTINGS);
     }
+
+    @Test
+    public void handleClick_dialogShown() {
+        View view = new View(mContext);
+        mTile.handleClick(view);
+        mTestableLooper.processAllMessages();
+
+        verify(mHearingDevicesDialogManager).showDialog(view);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
index 2d18f92..122d9e4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
@@ -58,7 +58,6 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.res.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.classifier.FalsingManagerFake;
 import com.android.systemui.plugins.ActivityStarter;
@@ -68,6 +67,7 @@
 import com.android.systemui.qs.QsEventLogger;
 import com.android.systemui.qs.logging.QSLogger;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.res.R;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.settings.SecureSettings;
 import com.android.systemui.wallet.controller.QuickAccessWalletController;
@@ -198,7 +198,8 @@
     }
 
     @Test
-    public void testIsAvailable_qawFeatureAvailable() {
+    public void testIsAvailable_qawFeatureAvailableWalletUnavailable() {
+        when(mController.isWalletRoleAvailable()).thenReturn(false);
         when(mPackageManager.hasSystemFeature(FEATURE_NFC_HOST_CARD_EMULATION)).thenReturn(true);
         when(mPackageManager.hasSystemFeature("org.chromium.arc")).thenReturn(false);
         when(mSecureSettings.getStringForUser(NFC_PAYMENT_DEFAULT_COMPONENT,
@@ -208,6 +209,16 @@
     }
 
     @Test
+    public void testIsAvailable_nfcUnavailableWalletAvailable() {
+        when(mController.isWalletRoleAvailable()).thenReturn(true);
+        when(mHost.getUserId()).thenReturn(PRIMARY_USER_ID);
+        when(mPackageManager.hasSystemFeature(FEATURE_NFC_HOST_CARD_EMULATION)).thenReturn(false);
+        when(mPackageManager.hasSystemFeature("org.chromium.arc")).thenReturn(false);
+
+        assertTrue(mTile.isAvailable());
+    }
+
+    @Test
     public void testHandleClick_startQuickAccessUiIntent_noCard() {
         setUpWalletCard(/* hasCard= */ false);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegateTest.kt
index 6e48074..598a0f2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegateTest.kt
@@ -39,7 +39,6 @@
 import com.android.systemui.settings.UserContextProvider
 import com.android.systemui.statusbar.phone.SystemUIDialog
 import com.android.systemui.statusbar.phone.SystemUIDialogManager
-import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.argumentCaptor
 import com.android.systemui.util.mockito.mock
 import com.google.common.truth.Truth.assertThat
@@ -50,6 +49,7 @@
 import org.junit.runner.RunWith
 import org.mockito.Mock
 import org.mockito.Mockito.eq
+import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when` as whenever
 import org.mockito.MockitoAnnotations
@@ -59,7 +59,6 @@
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
 class ScreenRecordPermissionDialogDelegateTest : SysuiTestCase() {
 
-    //@Mock private lateinit var dialogFactory: SystemUIDialog.Factory
     @Mock private lateinit var starter: ActivityStarter
     @Mock private lateinit var controller: RecordingController
     @Mock private lateinit var userContextProvider: UserContextProvider
@@ -76,13 +75,13 @@
         whenever(flags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING)).thenReturn(true)
 
         val systemUIDialogFactory =
-                SystemUIDialog.Factory(
-                        context,
-                        Dependency.get(SystemUIDialogManager::class.java),
-                        Dependency.get(SysUiState::class.java),
-                        Dependency.get(BroadcastDispatcher::class.java),
-                        Dependency.get(DialogTransitionAnimator::class.java),
-                )
+            SystemUIDialog.Factory(
+                context,
+                Dependency.get(SystemUIDialogManager::class.java),
+                Dependency.get(SysUiState::class.java),
+                Dependency.get(BroadcastDispatcher::class.java),
+                Dependency.get(DialogTransitionAnimator::class.java),
+            )
 
         val delegate =
             ScreenRecordPermissionDialogDelegate(
@@ -189,6 +188,17 @@
         verify(mediaProjectionMetricsLogger).notifyProjectionRequestCancelled(TEST_HOST_UID)
     }
 
+    @Test
+    fun showDialog_singleAppSelected_clickOnStart_projectionRequestCancelledIsNotLoggedOnce() {
+        showDialog()
+        onSpinnerItemSelected(SINGLE_APP)
+
+        clickOnStart()
+
+        verify(mediaProjectionMetricsLogger, never())
+            .notifyProjectionRequestCancelled(TEST_HOST_UID)
+    }
+
     private fun showDialog() {
         dialog.show()
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index e957ca2..dfe72cf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -73,7 +73,7 @@
 import com.android.keyguard.KeyguardStatusView;
 import com.android.keyguard.KeyguardStatusViewController;
 import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.LockIconViewController;
+import com.android.keyguard.LegacyLockIconViewController;
 import com.android.keyguard.dagger.KeyguardQsUserSwitchComponent;
 import com.android.keyguard.dagger.KeyguardStatusBarViewComponent;
 import com.android.keyguard.dagger.KeyguardStatusViewComponent;
@@ -278,7 +278,7 @@
     @Mock protected AmbientState mAmbientState;
     @Mock protected UserManager mUserManager;
     @Mock protected UiEventLogger mUiEventLogger;
-    @Mock protected LockIconViewController mLockIconViewController;
+    @Mock protected LegacyLockIconViewController mLockIconViewController;
     @Mock protected KeyguardViewConfigurator mKeyguardViewConfigurator;
     @Mock protected KeyguardRootView mKeyguardRootView;
     @Mock protected View mKeyguardRootViewChild;
@@ -604,6 +604,7 @@
                 new NotificationsKeyguardInteractor(notifsKeyguardViewStateRepository);
         NotificationWakeUpCoordinator coordinator =
                 new NotificationWakeUpCoordinator(
+                        mKosmos.getTestScope().getBackgroundScope(),
                         mDumpManager,
                         mock(HeadsUpManager.class),
                         new StatusBarStateControllerImpl(
@@ -618,7 +619,8 @@
                         mDozeParameters,
                         mScreenOffAnimationController,
                         new NotificationWakeUpCoordinatorLogger(logcatLogBuffer()),
-                        notifsKeyguardInteractor);
+                        notifsKeyguardInteractor,
+                        mKosmos.getCommunalInteractor());
         mConfigurationController = new ConfigurationControllerImpl(mContext);
         PulseExpansionHandler expansionHandler = new PulseExpansionHandler(
                 mContext,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
index 29a92d9..650c45b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -1061,7 +1061,7 @@
     @Test
     public void testPanelClosedWhenClosingQsInSplitShade() {
         mShadeExpansionStateManager.onPanelExpansionChanged(/* fraction= */ 1,
-                /* expanded= */ true, /* tracking= */ false, /* dragDownPxAmount= */ 0);
+                /* expanded= */ true, /* tracking= */ false);
         enableSplitShade(/* enabled= */ true);
         mNotificationPanelViewController.setExpandedFraction(1f);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index b699613..dfbb699 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -25,7 +25,7 @@
 import android.view.ViewGroup
 import androidx.test.filters.SmallTest
 import com.android.keyguard.KeyguardSecurityContainerController
-import com.android.keyguard.LockIconViewController
+import com.android.keyguard.LegacyLockIconViewController
 import com.android.keyguard.dagger.KeyguardBouncerComponent
 import com.android.systemui.Flags
 import com.android.systemui.SysuiTestCase
@@ -46,6 +46,7 @@
 import com.android.systemui.keyguard.shared.model.TransitionStep
 import com.android.systemui.res.R
 import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler
+import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor
 import com.android.systemui.statusbar.DragDownHelper
 import com.android.systemui.statusbar.LockscreenShadeTransitionController
 import com.android.systemui.statusbar.NotificationInsetsController
@@ -68,6 +69,7 @@
 import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
+import java.util.Optional
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.emptyFlow
@@ -85,7 +87,6 @@
 import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
-import java.util.Optional
 import org.mockito.Mockito.`when` as whenever
 
 @OptIn(ExperimentalCoroutinesApi::class)
@@ -100,7 +101,8 @@
     @Mock private lateinit var dozeServiceHost: DozeServiceHost
     @Mock private lateinit var dozeScrimController: DozeScrimController
     @Mock private lateinit var dockManager: DockManager
-    @Mock private lateinit var notificationPanelViewController: NotificationPanelViewController
+    @Mock private lateinit var shadeViewController: ShadeViewController
+    @Mock private lateinit var panelExpansionInteractor: PanelExpansionInteractor
     @Mock private lateinit var notificationShadeDepthController: NotificationShadeDepthController
     @Mock private lateinit var notificationShadeWindowController: NotificationShadeWindowController
     @Mock private lateinit var keyguardUnlockAnimationController: KeyguardUnlockAnimationController
@@ -113,7 +115,7 @@
     @Mock private lateinit var quickSettingsController: QuickSettingsControllerImpl
     @Mock
     private lateinit var lockscreenShadeTransitionController: LockscreenShadeTransitionController
-    @Mock private lateinit var lockIconViewController: LockIconViewController
+    @Mock private lateinit var lockIconViewController: LegacyLockIconViewController
     @Mock private lateinit var phoneStatusBarViewController: PhoneStatusBarViewController
     @Mock private lateinit var pulsingGestureListener: PulsingGestureListener
     @Mock
@@ -177,7 +179,8 @@
                 dockManager,
                 notificationShadeDepthController,
                 view,
-                notificationPanelViewController,
+                shadeViewController,
+                panelExpansionInteractor,
                 ShadeExpansionStateManager(),
                 stackScrollLayoutController,
                 statusBarKeyguardViewManager,
@@ -263,7 +266,7 @@
         testScope.runTest {
             underTest.setStatusBarViewController(phoneStatusBarViewController)
             whenever(statusBarWindowStateController.windowIsShowing()).thenReturn(true)
-            whenever(notificationPanelViewController.isFullyCollapsed).thenReturn(true)
+            whenever(panelExpansionInteractor.isFullyCollapsed).thenReturn(true)
             whenever(phoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
                 .thenReturn(true)
             whenever(phoneStatusBarViewController.sendTouchToView(DOWN_EVENT)).thenReturn(true)
@@ -282,7 +285,7 @@
             whenever(phoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
                 .thenReturn(true)
             // Item we're testing
-            whenever(notificationPanelViewController.isFullyCollapsed).thenReturn(false)
+            whenever(panelExpansionInteractor.isFullyCollapsed).thenReturn(false)
 
             val returnVal = interactionEventHandler.handleDispatchTouchEvent(DOWN_EVENT)
 
@@ -295,7 +298,7 @@
         testScope.runTest {
             underTest.setStatusBarViewController(phoneStatusBarViewController)
             whenever(statusBarWindowStateController.windowIsShowing()).thenReturn(true)
-            whenever(notificationPanelViewController.isFullyCollapsed).thenReturn(true)
+            whenever(panelExpansionInteractor.isFullyCollapsed).thenReturn(true)
             // Item we're testing
             whenever(phoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
                 .thenReturn(false)
@@ -310,7 +313,7 @@
     fun handleDispatchTouchEvent_sbWindowNotShowing_noSendTouchToSbAndReturnsTrue() =
         testScope.runTest {
             underTest.setStatusBarViewController(phoneStatusBarViewController)
-            whenever(notificationPanelViewController.isFullyCollapsed).thenReturn(true)
+            whenever(panelExpansionInteractor.isFullyCollapsed).thenReturn(true)
             whenever(phoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
                 .thenReturn(true)
             // Item we're testing
@@ -327,7 +330,7 @@
         testScope.runTest {
             underTest.setStatusBarViewController(phoneStatusBarViewController)
             whenever(statusBarWindowStateController.windowIsShowing()).thenReturn(true)
-            whenever(notificationPanelViewController.isFullyCollapsed).thenReturn(true)
+            whenever(panelExpansionInteractor.isFullyCollapsed).thenReturn(true)
             whenever(phoneStatusBarViewController.touchIsWithinView(anyFloat(), anyFloat()))
                 .thenReturn(true)
 
@@ -486,7 +489,7 @@
         // AND bouncer is not showing
         whenever(centralSurfaces.isBouncerShowing()).thenReturn(false)
         // AND panel view controller wants it
-        whenever(notificationPanelViewController.handleExternalInterceptTouch(DOWN_EVENT))
+        whenever(shadeViewController.handleExternalInterceptTouch(DOWN_EVENT))
             .thenReturn(true)
 
         mSetFlagsRule.enableFlags(Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
index 2ecca2e..98a815c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
@@ -22,7 +22,7 @@
 import android.widget.FrameLayout
 import androidx.test.filters.SmallTest
 import com.android.keyguard.KeyguardSecurityContainerController
-import com.android.keyguard.LockIconViewController
+import com.android.keyguard.LegacyLockIconViewController
 import com.android.keyguard.dagger.KeyguardBouncerComponent
 import com.android.systemui.Flags as AConfigFlags
 import com.android.systemui.SysuiTestCase
@@ -38,6 +38,7 @@
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
 import com.android.systemui.res.R
 import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler
+import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor
 import com.android.systemui.statusbar.DragDownHelper
 import com.android.systemui.statusbar.LockscreenShadeTransitionController
 import com.android.systemui.statusbar.NotificationInsetsController
@@ -89,7 +90,8 @@
     @Mock private lateinit var dozeServiceHost: DozeServiceHost
     @Mock private lateinit var dozeScrimController: DozeScrimController
     @Mock private lateinit var dockManager: DockManager
-    @Mock private lateinit var notificationPanelViewController: NotificationPanelViewController
+    @Mock private lateinit var shadeViewController: ShadeViewController
+    @Mock private lateinit var panelExpansionInteractor: PanelExpansionInteractor
     @Mock private lateinit var notificationStackScrollLayout: NotificationStackScrollLayout
     @Mock private lateinit var notificationShadeDepthController: NotificationShadeDepthController
     @Mock private lateinit var notificationShadeWindowController: NotificationShadeWindowController
@@ -101,7 +103,7 @@
     @Mock private lateinit var statusBarWindowStateController: StatusBarWindowStateController
     @Mock
     private lateinit var lockscreenShadeTransitionController: LockscreenShadeTransitionController
-    @Mock private lateinit var lockIconViewController: LockIconViewController
+    @Mock private lateinit var lockIconViewController: LegacyLockIconViewController
     @Mock private lateinit var keyguardUnlockAnimationController: KeyguardUnlockAnimationController
     @Mock private lateinit var ambientState: AmbientState
     @Mock private lateinit var shadeLogger: ShadeLogger
@@ -166,7 +168,8 @@
                 dockManager,
                 notificationShadeDepthController,
                 underTest,
-                notificationPanelViewController,
+                shadeViewController,
+                panelExpansionInteractor,
                 ShadeExpansionStateManager(),
                 notificationStackScrollLayoutController,
                 statusBarKeyguardViewManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeExpansionStateManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeExpansionStateManagerTest.kt
index 15c04eb..89ae42f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeExpansionStateManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeExpansionStateManagerTest.kt
@@ -42,17 +42,11 @@
         val tracking = true
         val dragDownAmount = 1234f
 
-        shadeExpansionStateManager.onPanelExpansionChanged(
-            fraction,
-            expanded,
-            tracking,
-            dragDownAmount
-        )
+        shadeExpansionStateManager.onPanelExpansionChanged(fraction, expanded, tracking)
 
         assertThat(listener.fraction).isEqualTo(fraction)
         assertThat(listener.expanded).isEqualTo(expanded)
         assertThat(listener.tracking).isEqualTo(tracking)
-        assertThat(listener.dragDownAmountPx).isEqualTo(dragDownAmount)
     }
 
     @Test
@@ -61,12 +55,7 @@
         val expanded = true
         val tracking = true
         val dragDownAmount = 1234f
-        shadeExpansionStateManager.onPanelExpansionChanged(
-            fraction,
-            expanded,
-            tracking,
-            dragDownAmount
-        )
+        shadeExpansionStateManager.onPanelExpansionChanged(fraction, expanded, tracking)
         val listener = TestShadeExpansionListener()
 
         val currentState = shadeExpansionStateManager.addExpansionListener(listener)
@@ -75,7 +64,6 @@
         assertThat(listener.fraction).isEqualTo(fraction)
         assertThat(listener.expanded).isEqualTo(expanded)
         assertThat(listener.tracking).isEqualTo(tracking)
-        assertThat(listener.dragDownAmountPx).isEqualTo(dragDownAmount)
     }
 
     @Test
@@ -100,8 +88,7 @@
         shadeExpansionStateManager.onPanelExpansionChanged(
             fraction = 0.5f,
             expanded = true,
-            tracking = false,
-            dragDownPxAmount = 0f
+            tracking = false
         )
 
         assertThat(listener.state).isEqualTo(STATE_OPENING)
@@ -115,8 +102,7 @@
         shadeExpansionStateManager.onPanelExpansionChanged(
             fraction = 0.5f,
             expanded = true,
-            tracking = true,
-            dragDownPxAmount = 0f
+            tracking = true
         )
 
         assertThat(listener.state).isEqualTo(STATE_OPENING)
@@ -132,8 +118,7 @@
         shadeExpansionStateManager.onPanelExpansionChanged(
             fraction = 0.5f,
             expanded = false,
-            tracking = false,
-            dragDownPxAmount = 0f
+            tracking = false
         )
 
         assertThat(listener.state).isEqualTo(STATE_CLOSED)
@@ -149,8 +134,7 @@
         shadeExpansionStateManager.onPanelExpansionChanged(
             fraction = 0.5f,
             expanded = false,
-            tracking = true,
-            dragDownPxAmount = 0f
+            tracking = true
         )
 
         assertThat(listener.state).isEqualTo(STATE_OPEN)
@@ -166,8 +150,7 @@
         shadeExpansionStateManager.onPanelExpansionChanged(
             fraction = 1f,
             expanded = true,
-            tracking = false,
-            dragDownPxAmount = 0f
+            tracking = false
         )
 
         assertThat(listener.previousState).isEqualTo(STATE_OPENING)
@@ -182,8 +165,7 @@
         shadeExpansionStateManager.onPanelExpansionChanged(
             fraction = 1f,
             expanded = true,
-            tracking = true,
-            dragDownPxAmount = 0f
+            tracking = true
         )
 
         assertThat(listener.state).isEqualTo(STATE_OPENING)
@@ -199,8 +181,7 @@
         shadeExpansionStateManager.onPanelExpansionChanged(
             fraction = 1f,
             expanded = false,
-            tracking = false,
-            dragDownPxAmount = 0f
+            tracking = false
         )
 
         assertThat(listener.state).isEqualTo(STATE_CLOSED)
@@ -216,8 +197,7 @@
         shadeExpansionStateManager.onPanelExpansionChanged(
             fraction = 1f,
             expanded = false,
-            tracking = true,
-            dragDownPxAmount = 0f
+            tracking = true
         )
 
         assertThat(listener.state).isEqualTo(STATE_OPEN)
@@ -229,13 +209,11 @@
         var fraction: Float = 0f
         var expanded: Boolean = false
         var tracking: Boolean = false
-        var dragDownAmountPx: Float = 0f
 
         override fun onPanelExpansionChanged(event: ShadeExpansionChangeEvent) {
             this.fraction = event.fraction
             this.expanded = event.expanded
             this.tracking = event.tracking
-            this.dragDownAmountPx = event.dragDownPxAmount
         }
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt
index dea905a..f2abb90 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt
@@ -3,23 +3,18 @@
 import android.platform.test.annotations.DisableFlags
 import android.testing.AndroidTestingRunner
 import androidx.test.filters.SmallTest
-import com.android.compose.animation.scene.ObservableTransitionState
-import com.android.compose.animation.scene.SceneKey
 import com.android.systemui.Flags
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository
 import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
 import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor
 import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
 import com.android.systemui.dump.DumpManager
-import com.android.systemui.flags.EnableSceneContainer
 import com.android.systemui.kosmos.applicationCoroutineScope
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.scene.domain.interactor.SceneInteractor
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.scene.shared.model.FakeSceneDataSource
-import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.scene.shared.model.fakeSceneDataSource
 import com.android.systemui.shade.ShadeExpansionChangeEvent
 import com.android.systemui.shade.ShadeExpansionStateManager
@@ -27,15 +22,8 @@
 import com.android.systemui.shade.domain.interactor.panelExpansionInteractor
 import com.android.systemui.statusbar.phone.ScrimController
 import com.android.systemui.testKosmos
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.whenever
-import com.google.common.truth.Truth
 import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.runCurrent
-import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -74,9 +62,7 @@
         sceneInteractor = kosmos.sceneInteractor
         fakeSceneDataSource = kosmos.fakeSceneDataSource
         underTest = ScrimShadeTransitionController(
-            applicationScope,
             shadeExpansionStateManager,
-            { panelExpansionInteractor },
             dumpManager,
             scrimController,
             )
@@ -99,96 +85,20 @@
         verify(scrimController).setRawPanelExpansionFraction(DEFAULT_EXPANSION_EVENT.fraction)
     }
 
-    @Test
-    @EnableSceneContainer
-    fun sceneChanges_forwardsToScrimTransitionController() =
-        testScope.runTest {
-            var rawExpansion: Float? = null
-            whenever(scrimController.setRawPanelExpansionFraction(any())).then {
-                (it.arguments[0] as Float?).also { rawExp -> rawExpansion = rawExp }
-            }
-            setUnlocked(true)
-            val transitionState =
-                MutableStateFlow<ObservableTransitionState>(
-                    ObservableTransitionState.Idle(Scenes.Gone)
-                )
-            sceneInteractor.setTransitionState(transitionState)
-
-            changeScene(Scenes.Gone, transitionState)
-            val currentScene by collectLastValue(sceneInteractor.currentScene)
-            Truth.assertThat(currentScene).isEqualTo(Scenes.Gone)
-
-            Truth.assertThat(rawExpansion)
-                    .isEqualTo(0f)
-
-            changeScene(Scenes.Shade, transitionState) { progress ->
-                Truth.assertThat(rawExpansion)
-                        .isEqualTo(progress)
-            }
-        }
-
     private fun startLegacyPanelExpansion() {
         shadeExpansionStateManager.onPanelExpansionChanged(
             DEFAULT_EXPANSION_EVENT.fraction,
             DEFAULT_EXPANSION_EVENT.expanded,
             DEFAULT_EXPANSION_EVENT.tracking,
-            DEFAULT_EXPANSION_EVENT.dragDownPxAmount,
         )
     }
 
-    private fun TestScope.setUnlocked(isUnlocked: Boolean) {
-        val isDeviceUnlocked by collectLastValue(deviceUnlockedInteractor.isDeviceUnlocked)
-        deviceEntryRepository.setUnlocked(isUnlocked)
-        runCurrent()
-
-        Truth.assertThat(isDeviceUnlocked).isEqualTo(isUnlocked)
-    }
-
-    private fun TestScope.changeScene(
-        toScene: SceneKey,
-        transitionState: MutableStateFlow<ObservableTransitionState>,
-        assertDuringProgress: ((progress: Float) -> Unit) = {},
-    ) {
-        val currentScene by collectLastValue(sceneInteractor.currentScene)
-        val progressFlow = MutableStateFlow(0f)
-        transitionState.value =
-            ObservableTransitionState.Transition(
-                fromScene = checkNotNull(currentScene),
-                toScene = toScene,
-                progress = progressFlow,
-                isInitiatedByUserInput = true,
-                isUserInputOngoing = flowOf(true),
-            )
-        runCurrent()
-        assertDuringProgress(progressFlow.value)
-
-        progressFlow.value = 0.2f
-        runCurrent()
-        assertDuringProgress(progressFlow.value)
-
-        progressFlow.value = 0.6f
-        runCurrent()
-        assertDuringProgress(progressFlow.value)
-
-        progressFlow.value = 1f
-        runCurrent()
-        assertDuringProgress(progressFlow.value)
-
-        transitionState.value = ObservableTransitionState.Idle(toScene)
-        fakeSceneDataSource.changeScene(toScene)
-        runCurrent()
-        assertDuringProgress(progressFlow.value)
-
-        Truth.assertThat(currentScene).isEqualTo(toScene)
-    }
-
     companion object {
         val DEFAULT_EXPANSION_EVENT =
             ShadeExpansionChangeEvent(
                 fraction = 0.5f,
                 expanded = true,
-                tracking = true,
-                dragDownPxAmount = 10f
+                tracking = true
             )
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
index 68bc72b..fc0c85e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
@@ -23,18 +23,18 @@
 import android.view.View
 import android.view.ViewRootImpl
 import androidx.test.filters.SmallTest
-import com.android.systemui.res.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.ShadeInterpolation
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.res.R
 import com.android.systemui.shade.ShadeExpansionChangeEvent
 import com.android.systemui.statusbar.phone.BiometricUnlockController
 import com.android.systemui.statusbar.phone.DozeParameters
 import com.android.systemui.statusbar.phone.ScrimController
 import com.android.systemui.statusbar.policy.FakeConfigurationController
-import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController
 import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController
 import com.android.systemui.util.WallpaperController
 import com.android.systemui.util.mockito.eq
 import com.google.common.truth.Truth.assertThat
@@ -142,7 +142,7 @@
     fun onPanelExpansionChanged_apliesBlur_ifShade() {
         notificationShadeDepthController.onPanelExpansionChanged(
             ShadeExpansionChangeEvent(
-                fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f))
+                fraction = 1f, expanded = true, tracking = false))
         verify(shadeAnimation).animateTo(eq(maxBlur))
     }
 
@@ -150,7 +150,7 @@
     fun onPanelExpansionChanged_animatesBlurIn_ifShade() {
         notificationShadeDepthController.onPanelExpansionChanged(
             ShadeExpansionChangeEvent(
-                fraction = 0.01f, expanded = false, tracking = false, dragDownPxAmount = 0f))
+                fraction = 0.01f, expanded = false, tracking = false))
         verify(shadeAnimation).animateTo(eq(maxBlur))
     }
 
@@ -160,7 +160,7 @@
         clearInvocations(shadeAnimation)
         notificationShadeDepthController.onPanelExpansionChanged(
             ShadeExpansionChangeEvent(
-                fraction = 0f, expanded = false, tracking = false, dragDownPxAmount = 0f))
+                fraction = 0f, expanded = false, tracking = false))
         verify(shadeAnimation).animateTo(eq(0))
     }
 
@@ -168,7 +168,7 @@
     fun onPanelExpansionChanged_animatesBlurOut_ifFlick() {
         val event =
             ShadeExpansionChangeEvent(
-                fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f)
+                fraction = 1f, expanded = true, tracking = false)
         onPanelExpansionChanged_apliesBlur_ifShade()
         clearInvocations(shadeAnimation)
         notificationShadeDepthController.onPanelExpansionChanged(event)
@@ -189,7 +189,7 @@
         clearInvocations(shadeAnimation)
         notificationShadeDepthController.onPanelExpansionChanged(
             ShadeExpansionChangeEvent(
-                fraction = 0.6f, expanded = true, tracking = true, dragDownPxAmount = 0f))
+                fraction = 0.6f, expanded = true, tracking = true))
         verify(shadeAnimation).animateTo(eq(maxBlur))
     }
 
@@ -197,7 +197,7 @@
     fun onPanelExpansionChanged_respectsMinPanelPullDownFraction() {
         val event =
             ShadeExpansionChangeEvent(
-                fraction = 0.5f, expanded = true, tracking = true, dragDownPxAmount = 0f)
+                fraction = 0.5f, expanded = true, tracking = true)
         notificationShadeDepthController.panelPullDownMinFraction = 0.5f
         notificationShadeDepthController.onPanelExpansionChanged(event)
         assertThat(notificationShadeDepthController.shadeExpansion).isEqualTo(0f)
@@ -225,7 +225,7 @@
         notificationShadeDepthController.qsPanelExpansion = 1f
         notificationShadeDepthController.onPanelExpansionChanged(
             ShadeExpansionChangeEvent(
-                fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f))
+                fraction = 1f, expanded = true, tracking = false))
         notificationShadeDepthController.updateBlurCallback.doFrame(0)
         verify(blurUtils).applyBlur(any(), eq(maxBlur), eq(false))
     }
@@ -236,7 +236,7 @@
         notificationShadeDepthController.qsPanelExpansion = 0.25f
         notificationShadeDepthController.onPanelExpansionChanged(
             ShadeExpansionChangeEvent(
-                fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f))
+                fraction = 1f, expanded = true, tracking = false))
         notificationShadeDepthController.updateBlurCallback.doFrame(0)
         verify(wallpaperController)
             .setNotificationShadeZoom(eq(ShadeInterpolation.getNotificationScrimAlpha(0.25f)))
@@ -248,7 +248,7 @@
 
         notificationShadeDepthController.onPanelExpansionChanged(
             ShadeExpansionChangeEvent(
-                fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f))
+                fraction = 1f, expanded = true, tracking = false))
         notificationShadeDepthController.updateBlurCallback.doFrame(0)
 
         verify(wallpaperController).setNotificationShadeZoom(0f)
@@ -260,7 +260,7 @@
 
         notificationShadeDepthController.onPanelExpansionChanged(
             ShadeExpansionChangeEvent(
-                fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f))
+                fraction = 1f, expanded = true, tracking = false))
         notificationShadeDepthController.updateBlurCallback.doFrame(0)
 
         verify(wallpaperController).setNotificationShadeZoom(floatThat { it > 0 })
@@ -273,7 +273,7 @@
         val expanded = true
         val tracking = false
         val dragDownPxAmount = 0f
-        val event = ShadeExpansionChangeEvent(rawFraction, expanded, tracking, dragDownPxAmount)
+        val event = ShadeExpansionChangeEvent(rawFraction, expanded, tracking)
         val inOrder = Mockito.inOrder(wallpaperController)
 
         notificationShadeDepthController.onPanelExpansionChanged(event)
@@ -338,7 +338,7 @@
     fun updateBlurCallback_setsBlur_whenExpanded() {
         notificationShadeDepthController.onPanelExpansionChanged(
             ShadeExpansionChangeEvent(
-                fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f))
+                fraction = 1f, expanded = true, tracking = false))
         `when`(shadeAnimation.radius).thenReturn(maxBlur.toFloat())
         notificationShadeDepthController.updateBlurCallback.doFrame(0)
         verify(blurUtils).applyBlur(any(), eq(maxBlur), eq(false))
@@ -348,7 +348,7 @@
     fun updateBlurCallback_ignoreShadeBlurUntilHidden_overridesZoom() {
         notificationShadeDepthController.onPanelExpansionChanged(
             ShadeExpansionChangeEvent(
-                fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f))
+                fraction = 1f, expanded = true, tracking = false))
         `when`(shadeAnimation.radius).thenReturn(maxBlur.toFloat())
         notificationShadeDepthController.blursDisabledForAppLaunch = true
         notificationShadeDepthController.updateBlurCallback.doFrame(0)
@@ -367,7 +367,7 @@
     fun ignoreBlurForUnlock_ignores() {
         notificationShadeDepthController.onPanelExpansionChanged(
             ShadeExpansionChangeEvent(
-                fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f))
+                fraction = 1f, expanded = true, tracking = false))
         `when`(shadeAnimation.radius).thenReturn(maxBlur.toFloat())
 
         notificationShadeDepthController.blursDisabledForAppLaunch = false
@@ -384,7 +384,7 @@
     fun ignoreBlurForUnlock_doesNotIgnore() {
         notificationShadeDepthController.onPanelExpansionChanged(
             ShadeExpansionChangeEvent(
-                fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f))
+                fraction = 1f, expanded = true, tracking = false))
         `when`(shadeAnimation.radius).thenReturn(maxBlur.toFloat())
 
         notificationShadeDepthController.blursDisabledForAppLaunch = false
@@ -416,7 +416,7 @@
         // And shade is blurred
         notificationShadeDepthController.onPanelExpansionChanged(
             ShadeExpansionChangeEvent(
-                fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f))
+                fraction = 1f, expanded = true, tracking = false))
         `when`(shadeAnimation.radius).thenReturn(maxBlur.toFloat())
 
         notificationShadeDepthController.updateBlurCallback.doFrame(0)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/OperatorNameViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/OperatorNameViewControllerTest.kt
new file mode 100644
index 0000000..9c59f9b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/OperatorNameViewControllerTest.kt
@@ -0,0 +1,202 @@
+/*
+ * 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
+
+import android.telephony.ServiceState
+import android.telephony.SubscriptionInfo
+import android.telephony.TelephonyManager
+import android.telephony.telephonyManager
+import androidx.test.filters.SmallTest
+import com.android.keyguard.keyguardUpdateMonitor
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.plugins.DarkIconDispatcher
+import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
+import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.util.FakeSubscriptionManagerProxy
+import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
+import com.android.systemui.tuner.TunerService
+import com.android.systemui.util.CarrierConfigTracker
+import com.android.systemui.util.kotlin.JavaAdapter
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import junit.framework.Assert.assertTrue
+import kotlin.test.Test
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+class OperatorNameViewControllerTest : SysuiTestCase() {
+    private lateinit var underTest: OperatorNameViewController
+    private lateinit var airplaneModeInteractor: AirplaneModeInteractor
+
+    private val kosmos = Kosmos()
+    private val testScope = TestScope()
+
+    private val view = OperatorNameView(mContext)
+    private val javaAdapter = JavaAdapter(testScope.backgroundScope)
+
+    @Mock private lateinit var darkIconDispatcher: DarkIconDispatcher
+    @Mock private lateinit var tunerService: TunerService
+    private var telephonyManager = kosmos.telephonyManager
+    private val keyguardUpdateMonitor = kosmos.keyguardUpdateMonitor
+    @Mock private lateinit var carrierConfigTracker: CarrierConfigTracker
+    private val subscriptionManagerProxy = FakeSubscriptionManagerProxy()
+
+    private val airplaneModeRepository = FakeAirplaneModeRepository()
+    private val connectivityRepository = FakeConnectivityRepository()
+    private val mobileConnectionsRepository = FakeMobileConnectionsRepository()
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+
+        airplaneModeInteractor =
+            AirplaneModeInteractor(
+                airplaneModeRepository,
+                connectivityRepository,
+                mobileConnectionsRepository,
+            )
+
+        underTest =
+            OperatorNameViewController.Factory(
+                    darkIconDispatcher,
+                    tunerService,
+                    telephonyManager,
+                    keyguardUpdateMonitor,
+                    carrierConfigTracker,
+                    airplaneModeInteractor,
+                    subscriptionManagerProxy,
+                    javaAdapter,
+                )
+                .create(view)
+    }
+
+    @Test
+    fun updateFromSubInfo_showsCarrieName() =
+        testScope.runTest {
+            whenever(telephonyManager.isDataCapable).thenReturn(true)
+
+            val mockSubInfo =
+                mock<SubscriptionInfo>().also {
+                    whenever(it.subscriptionId).thenReturn(1)
+                    whenever(it.carrierName).thenReturn("test_carrier")
+                }
+            whenever(keyguardUpdateMonitor.getSubscriptionInfoForSubId(any()))
+                .thenReturn(mockSubInfo)
+            whenever(keyguardUpdateMonitor.getSimState(any()))
+                .thenReturn(TelephonyManager.SIM_STATE_READY)
+            whenever(keyguardUpdateMonitor.getServiceState(any()))
+                .thenReturn(ServiceState().also { it.state = ServiceState.STATE_IN_SERVICE })
+            subscriptionManagerProxy.defaultDataSubId = 1
+            airplaneModeRepository.setIsAirplaneMode(false)
+
+            underTest.onViewAttached()
+            runCurrent()
+
+            assertThat(view.text).isEqualTo("test_carrier")
+        }
+
+    @Test
+    fun notDataCapable_doesNotShowOperatorName() =
+        testScope.runTest {
+            whenever(telephonyManager.isDataCapable).thenReturn(false)
+
+            val mockSubInfo =
+                mock<SubscriptionInfo>().also {
+                    whenever(it.subscriptionId).thenReturn(1)
+                    whenever(it.carrierName).thenReturn("test_carrier")
+                }
+            whenever(keyguardUpdateMonitor.getSubscriptionInfoForSubId(any()))
+                .thenReturn(mockSubInfo)
+            whenever(keyguardUpdateMonitor.getSimState(any()))
+                .thenReturn(TelephonyManager.SIM_STATE_READY)
+            whenever(keyguardUpdateMonitor.getServiceState(any()))
+                .thenReturn(ServiceState().also { it.state = ServiceState.STATE_IN_SERVICE })
+            subscriptionManagerProxy.defaultDataSubId = 1
+            airplaneModeRepository.setIsAirplaneMode(false)
+
+            underTest.onViewAttached()
+            runCurrent()
+
+            assertTrue(view.text.isNullOrEmpty())
+        }
+
+    @Test
+    fun airplaneMode_doesNotShowOperatorName() =
+        testScope.runTest {
+            whenever(telephonyManager.isDataCapable).thenReturn(false)
+            val mockSubInfo =
+                mock<SubscriptionInfo>().also {
+                    whenever(it.subscriptionId).thenReturn(1)
+                    whenever(it.carrierName).thenReturn("test_carrier")
+                }
+            whenever(keyguardUpdateMonitor.getSubscriptionInfoForSubId(any()))
+                .thenReturn(mockSubInfo)
+            whenever(keyguardUpdateMonitor.getSimState(any()))
+                .thenReturn(TelephonyManager.SIM_STATE_READY)
+            whenever(keyguardUpdateMonitor.getServiceState(any()))
+                .thenReturn(ServiceState().also { it.state = ServiceState.STATE_IN_SERVICE })
+            subscriptionManagerProxy.defaultDataSubId = 1
+            airplaneModeRepository.setIsAirplaneMode(true)
+
+            underTest.onViewAttached()
+            runCurrent()
+
+            assertTrue(view.text.isNullOrEmpty())
+        }
+
+    @Test
+    fun notInService_doesNotShowOperatorName() =
+        testScope.runTest {
+            // Data capable
+            whenever(telephonyManager.isDataCapable).thenReturn(true)
+
+            // Valid subscription
+            val mockSubInfo =
+                mock<SubscriptionInfo>().also {
+                    whenever(it.subscriptionId).thenReturn(1)
+                    whenever(it.carrierName).thenReturn("test_carrier")
+                }
+            whenever(keyguardUpdateMonitor.getSubscriptionInfoForSubId(any()))
+                .thenReturn(mockSubInfo)
+            whenever(keyguardUpdateMonitor.getSimState(any()))
+                .thenReturn(TelephonyManager.SIM_STATE_READY)
+
+            // Not in service
+            whenever(keyguardUpdateMonitor.getServiceState(any()))
+                .thenReturn(ServiceState().also { it.state = ServiceState.STATE_OUT_OF_SERVICE })
+            // Subscription is default for data
+            subscriptionManagerProxy.defaultDataSubId = 1
+            // Not airplane mode
+            airplaneModeRepository.setIsAirplaneMode(false)
+
+            underTest.onViewAttached()
+            runCurrent()
+
+            assertTrue(view.text.isNullOrEmpty())
+        }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt
index 82093ad..67b540c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorTest.kt
@@ -19,10 +19,15 @@
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import androidx.test.filters.SmallTest
+import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.AnimatorTestRule
+import com.android.systemui.communal.data.repository.communalRepository
+import com.android.systemui.communal.domain.interactor.communalInteractor
+import com.android.systemui.communal.shared.model.CommunalScenes
 import com.android.systemui.dump.DumpManager
-import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testScope
 import com.android.systemui.log.logcatLogBuffer
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.shade.ShadeViewController.Companion.WAKEUP_ANIMATION_DELAY_MS
@@ -34,11 +39,16 @@
 import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.statusbar.phone.ScreenOffAnimationController
 import com.android.systemui.statusbar.policy.HeadsUpManager
+import com.android.systemui.testKosmos
 import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
 import com.android.systemui.util.mockito.withArgCaptor
 import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
@@ -49,6 +59,7 @@
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.verifyNoMoreInteractions
 
+@OptIn(ExperimentalCoroutinesApi::class)
 @RunWith(AndroidTestingRunner::class)
 @SmallTest
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
@@ -56,7 +67,8 @@
 
     @get:Rule val animatorTestRule = AnimatorTestRule(this)
 
-    private val kosmos = Kosmos()
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
 
     private val dumpManager: DumpManager = mock()
     private val headsUpManager: HeadsUpManager = mock()
@@ -97,6 +109,7 @@
         whenever(statusBarStateController.state).then { statusBarState }
         notificationWakeUpCoordinator =
             NotificationWakeUpCoordinator(
+                kosmos.applicationCoroutineScope,
                 dumpManager,
                 headsUpManager,
                 statusBarStateController,
@@ -105,6 +118,7 @@
                 screenOffAnimationController,
                 logger,
                 kosmos.notificationsKeyguardInteractor,
+                kosmos.communalInteractor,
             )
         statusBarStateCallback = withArgCaptor {
             verify(statusBarStateController).addCallback(capture())
@@ -161,6 +175,39 @@
     }
 
     @Test
+    fun setDozeToZeroWhenCommunalShowingWillFullyHideNotifications() =
+        testScope.runTest {
+            val transitionState =
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Idle(CommunalScenes.Communal)
+                )
+            kosmos.communalRepository.setTransitionState(transitionState)
+            runCurrent()
+            setDozeAmount(0f)
+            verifyStackScrollerDozeAndHideAmount(dozeAmount = 1f, hideAmount = 1f)
+            assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isTrue()
+        }
+
+    @Test
+    fun closingCommunalWillShowNotifications() =
+        testScope.runTest {
+            val transitionState =
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Idle(CommunalScenes.Communal)
+                )
+            kosmos.communalRepository.setTransitionState(transitionState)
+            runCurrent()
+            setDozeAmount(0f)
+            verifyStackScrollerDozeAndHideAmount(dozeAmount = 1f, hideAmount = 1f)
+            assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isTrue()
+
+            transitionState.value = ObservableTransitionState.Idle(CommunalScenes.Blank)
+            runCurrent()
+            verifyStackScrollerDozeAndHideAmount(dozeAmount = 0f, hideAmount = 0f)
+            assertThat(notificationWakeUpCoordinator.notificationsFullyHidden).isFalse()
+        }
+
+    @Test
     fun switchingToShadeWithBypassEnabledWillShowNotifications() {
         setDozeToZeroWithBypassWillFullyHideNotifications()
         clearInvocations(stackScrollerController)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 054680d..34605fe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -597,8 +597,7 @@
 
     private static ShadeExpansionChangeEvent expansionEvent(
             float fraction, boolean expanded, boolean tracking) {
-        return new ShadeExpansionChangeEvent(
-                fraction, expanded, tracking, /* dragDownPxAmount= */ 0f);
+        return new ShadeExpansionChangeEvent(fraction, expanded, tracking);
     }
 
     @Test
@@ -607,7 +606,7 @@
         /* verify that a predictive back callback is registered when the bouncer becomes visible */
         mBouncerExpansionCallback.onVisibilityChanged(true);
         verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
-                eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY),
+                eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT),
                 mBackCallbackCaptor.capture());
 
         /* verify that the same callback is unregistered when the bouncer becomes invisible */
@@ -622,7 +621,7 @@
         mBouncerExpansionCallback.onVisibilityChanged(true);
         /* capture the predictive back callback during registration */
         verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
-                eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY),
+                eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT),
                 mBackCallbackCaptor.capture());
 
         when(mPrimaryBouncerInteractor.isFullyShowing()).thenReturn(true);
@@ -642,7 +641,7 @@
         mBouncerExpansionCallback.onVisibilityChanged(true);
         /* capture the predictive back callback during registration */
         verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
-                eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY),
+                eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT),
                 mBackCallbackCaptor.capture());
         assertTrue(mBackCallbackCaptor.getValue() instanceof OnBackAnimationCallback);
 
@@ -660,7 +659,7 @@
         mBouncerExpansionCallback.onVisibilityChanged(true);
         /* capture the predictive back callback during registration */
         verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
-                eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY),
+                eq(OnBackInvokedDispatcher.PRIORITY_DEFAULT),
                 mBackCallbackCaptor.capture());
         assertTrue(mBackCallbackCaptor.getValue() instanceof OnBackAnimationCallback);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index 3da5ab9..9c3d9c6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -52,7 +52,7 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.res.R;
 import com.android.systemui.shade.ShadeExpansionStateManager;
-import com.android.systemui.shade.ShadeViewController;
+import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.OperatorNameViewController;
 import com.android.systemui.statusbar.disableflags.DisableFlagsLogger;
@@ -115,7 +115,7 @@
     @Mock
     private HeadsUpAppearanceController mHeadsUpAppearanceController;
     @Mock
-    private ShadeViewController mShadeViewController;
+    private PanelExpansionInteractor mPanelExpansionInteractor;
     @Mock
     private StatusBarIconController.DarkIconManager.Factory mIconManagerFactory;
     @Mock
@@ -304,7 +304,7 @@
 
         // WHEN the shade is open and configured to hide the status bar icons
         mShadeExpansionStateManager.updateState(STATE_OPEN);
-        when(mShadeViewController.shouldHideStatusBarIconsWhenExpanded()).thenReturn(true);
+        when(mPanelExpansionInteractor.shouldHideStatusBarIconsWhenExpanded()).thenReturn(true);
 
         fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
 
@@ -320,7 +320,7 @@
 
         // WHEN the shade is open but *not* configured to hide the status bar icons
         mShadeExpansionStateManager.updateState(STATE_OPEN);
-        when(mShadeViewController.shouldHideStatusBarIconsWhenExpanded()).thenReturn(false);
+        when(mPanelExpansionInteractor.shouldHideStatusBarIconsWhenExpanded()).thenReturn(false);
 
         fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
 
@@ -337,7 +337,7 @@
 
         // WHEN the shade is open and configured to hide the status bar icons
         mShadeExpansionStateManager.updateState(STATE_OPEN);
-        when(mShadeViewController.shouldHideStatusBarIconsWhenExpanded()).thenReturn(true);
+        when(mPanelExpansionInteractor.shouldHideStatusBarIconsWhenExpanded()).thenReturn(true);
 
         fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
 
@@ -696,7 +696,7 @@
                 mCollapsedStatusBarViewBinder,
                 mStatusBarHideIconsForBouncerManager,
                 mKeyguardStateController,
-                mShadeViewController,
+                mPanelExpansionInteractor,
                 mStatusBarStateController,
                 mock(NotificationIconContainerStatusBarViewBinder.class),
                 mCommandQueue,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt
index 867476f..581ca3b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt
@@ -28,6 +28,7 @@
 import android.content.pm.PackageManager
 import android.media.projection.MediaProjectionInfo
 import android.media.projection.MediaProjectionManager
+import android.os.UserHandle
 import android.permission.flags.Flags.FLAG_SENSITIVE_NOTIFICATION_APP_PROTECTION
 import android.platform.test.annotations.EnableFlags
 import android.platform.test.annotations.RequiresFlagsDisabled
@@ -85,7 +86,6 @@
     @Mock private lateinit var activityManager: IActivityManager
     @Mock private lateinit var mediaProjectionManager: MediaProjectionManager
     @Mock private lateinit var packageManager: PackageManager
-    @Mock private lateinit var mediaProjectionInfo: MediaProjectionInfo
     @Mock private lateinit var listener1: Runnable
     @Mock private lateinit var listener2: Runnable
     @Mock private lateinit var listener3: Runnable
@@ -95,6 +95,7 @@
     private lateinit var globalSettings: FakeGlobalSettings
     private lateinit var mediaProjectionCallback: MediaProjectionManager.Callback
     private lateinit var controller: SensitiveNotificationProtectionControllerImpl
+    private lateinit var mediaProjectionInfo: MediaProjectionInfo
 
     @Before
     fun setUp() {
@@ -109,14 +110,29 @@
         setShareFullScreen()
         whenever(activityManager.bugreportWhitelistedPackages)
             .thenReturn(listOf(BUGREPORT_PACKAGE_NAME))
-        whenever(packageManager.getPackageUid(TEST_PROJECTION_PACKAGE_NAME, 0))
+        whenever(
+                packageManager.getPackageUidAsUser(
+                    TEST_PROJECTION_PACKAGE_NAME,
+                    UserHandle.CURRENT.identifier
+                )
+            )
             .thenReturn(TEST_PROJECTION_PACKAGE_UID)
-        whenever(packageManager.getPackageUid(BUGREPORT_PACKAGE_NAME, 0))
+        whenever(
+                packageManager.getPackageUidAsUser(
+                    BUGREPORT_PACKAGE_NAME,
+                    UserHandle.CURRENT.identifier
+                )
+            )
             .thenReturn(BUGREPORT_PACKAGE_UID)
         // SystemUi context package name is exempt, but in test scenarios its
         // com.android.systemui.tests so use that instead of hardcoding. Setup packagemanager to
         // return the correct uid in this scenario
-        whenever(packageManager.getPackageUid(mContext.packageName, 0))
+        whenever(
+                packageManager.getPackageUidAsUser(
+                    mContext.packageName,
+                    UserHandle.CURRENT.identifier
+                )
+            )
             .thenReturn(mContext.applicationInfo.uid)
 
         whenever(packageManager.checkPermission(anyString(), anyString()))
@@ -271,7 +287,7 @@
     fun isSensitiveStateActive_projectionActive_sysuiExempt_false() {
         // SystemUi context package name is exempt, but in test scenarios its
         // com.android.systemui.tests so use that instead of hardcoding
-        whenever(mediaProjectionInfo.packageName).thenReturn(mContext.packageName)
+        setShareFullScreenViaSystemUi()
         mediaProjectionCallback.onStart(mediaProjectionInfo)
 
         assertFalse(controller.isSensitiveStateActive)
@@ -309,7 +325,7 @@
 
     @Test
     fun isSensitiveStateActive_projectionActive_bugReportHandlerExempt_false() {
-        whenever(mediaProjectionInfo.packageName).thenReturn(BUGREPORT_PACKAGE_NAME)
+        setShareFullScreenViaBugReportHandler()
         mediaProjectionCallback.onStart(mediaProjectionInfo)
 
         assertFalse(controller.isSensitiveStateActive)
@@ -371,7 +387,7 @@
     fun shouldProtectNotification_projectionActive_sysuiExempt_false() {
         // SystemUi context package name is exempt, but in test scenarios its
         // com.android.systemui.tests so use that instead of hardcoding
-        whenever(mediaProjectionInfo.packageName).thenReturn(mContext.packageName)
+        setShareFullScreenViaSystemUi()
         mediaProjectionCallback.onStart(mediaProjectionInfo)
 
         val notificationEntry = setupNotificationEntry(TEST_PACKAGE_NAME, false)
@@ -415,7 +431,7 @@
 
     @Test
     fun shouldProtectNotification_projectionActive_bugReportHandlerExempt_false() {
-        whenever(mediaProjectionInfo.packageName).thenReturn(BUGREPORT_PACKAGE_NAME)
+        setShareFullScreenViaBugReportHandler()
         mediaProjectionCallback.onStart(mediaProjectionInfo)
 
         val notificationEntry = setupNotificationEntry(TEST_PACKAGE_NAME, false)
@@ -548,9 +564,7 @@
     fun logSensitiveContentProtectionSession_exemptViaSystemUi() {
         // SystemUi context package name is exempt, but in test scenarios its
         // com.android.systemui.tests so use that instead of hardcoding
-        val testPackageName = mContext.packageName
-        val testUid = mContext.applicationInfo.uid
-        whenever(mediaProjectionInfo.packageName).thenReturn(testPackageName)
+        setShareFullScreenViaSystemUi()
 
         mediaProjectionCallback.onStart(mediaProjectionInfo)
 
@@ -558,7 +572,7 @@
             FrameworkStatsLog.write(
                 eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION),
                 anyLong(),
-                eq(testUid),
+                eq(mContext.applicationInfo.uid),
                 eq(true),
                 eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__START),
                 eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI)
@@ -571,7 +585,7 @@
             FrameworkStatsLog.write(
                 eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION),
                 anyLong(),
-                eq(testUid),
+                eq(mContext.applicationInfo.uid),
                 eq(true),
                 eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__STOP),
                 eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI)
@@ -582,8 +596,7 @@
     @Test
     fun logSensitiveContentProtectionSession_exemptViaBugReportHandler() {
         // Setup exempt via bugreport handler
-        whenever(mediaProjectionInfo.packageName).thenReturn(BUGREPORT_PACKAGE_NAME)
-
+        setShareFullScreenViaBugReportHandler()
         mediaProjectionCallback.onStart(mediaProjectionInfo)
 
         verify {
@@ -619,13 +632,26 @@
     }
 
     private fun setShareFullScreen() {
-        whenever(mediaProjectionInfo.packageName).thenReturn(TEST_PROJECTION_PACKAGE_NAME)
-        whenever(mediaProjectionInfo.launchCookie).thenReturn(null)
+        setShareScreen(TEST_PROJECTION_PACKAGE_NAME, true)
+    }
+
+    private fun setShareFullScreenViaBugReportHandler() {
+        setShareScreen(BUGREPORT_PACKAGE_NAME, true)
+    }
+
+    private fun setShareFullScreenViaSystemUi() {
+        // SystemUi context package name is exempt, but in test scenarios its
+        // com.android.systemui.tests so use that instead of hardcoding
+        setShareScreen(mContext.packageName, true)
     }
 
     private fun setShareSingleApp() {
-        whenever(mediaProjectionInfo.packageName).thenReturn(TEST_PROJECTION_PACKAGE_NAME)
-        whenever(mediaProjectionInfo.launchCookie).thenReturn(ActivityOptions.LaunchCookie())
+        setShareScreen(TEST_PROJECTION_PACKAGE_NAME, false)
+    }
+
+    private fun setShareScreen(packageName: String, fullScreen: Boolean) {
+        val launchCookie = if (fullScreen) null else ActivityOptions.LaunchCookie()
+        mediaProjectionInfo = MediaProjectionInfo(packageName, UserHandle.CURRENT, launchCookie)
     }
 
     private fun setupNotificationEntry(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java
index fccb936..dc5597a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallet/controller/QuickAccessWalletControllerTest.java
@@ -29,6 +29,7 @@
 import static org.mockito.Mockito.when;
 
 import android.app.PendingIntent;
+import android.app.role.RoleManager;
 import android.content.Intent;
 import android.service.quickaccesswallet.GetWalletCardsRequest;
 import android.service.quickaccesswallet.QuickAccessWalletClient;
@@ -54,11 +55,14 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.List;
+
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
 @SmallTest
 public class QuickAccessWalletControllerTest extends SysuiTestCase {
 
+    private static final String WALLET_ROLE_HOLDER = "wallet.role.holder";
     @Mock
     private QuickAccessWalletClient mQuickAccessWalletClient;
     @Mock
@@ -69,6 +73,8 @@
     private ActivityStarter mActivityStarter;
     @Mock
     private ActivityTransitionAnimator.Controller mAnimationController;
+    @Mock
+    private RoleManager mRoleManager;
     @Captor
     private ArgumentCaptor<GetWalletCardsRequest> mRequestCaptor;
     @Captor
@@ -102,7 +108,8 @@
                 MoreExecutors.directExecutor(),
                 mSecureSettings,
                 mQuickAccessWalletClient,
-                mClock);
+                mClock,
+                mRoleManager);
     }
 
     @Test
@@ -113,6 +120,24 @@
     }
 
     @Test
+    public void walletRoleAvailable_isAvailable() {
+        when(mRoleManager.isRoleAvailable(eq(RoleManager.ROLE_WALLET))).thenReturn(true);
+        when(mRoleManager.getRoleHolders(eq(RoleManager.ROLE_WALLET)))
+                .thenReturn(List.of(WALLET_ROLE_HOLDER));
+
+        assertTrue(mController.isWalletRoleAvailable());
+    }
+
+    @Test
+    public void walletRoleAvailable_isNotAvailable() {
+        when(mRoleManager.isRoleAvailable(eq(RoleManager.ROLE_WALLET))).thenReturn(false);
+        when(mRoleManager.getRoleHolders(eq(RoleManager.ROLE_WALLET)))
+                .thenReturn(List.of(WALLET_ROLE_HOLDER));
+
+        assertFalse(mController.isWalletRoleAvailable());
+    }
+
+    @Test
     public void walletServiceUnavailable_walletNotEnabled() {
         when(mQuickAccessWalletClient.isWalletServiceAvailable()).thenReturn(false);
 
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt
index 513c6ab..4a2eaf0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ShadeControllerKosmos.kt
@@ -27,6 +27,7 @@
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.plugins.statusbar.statusBarStateController
 import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.shade.domain.interactor.shadeInteractor
 import com.android.systemui.statusbar.CommandQueue
 import com.android.systemui.statusbar.NotificationShadeWindowController
@@ -78,4 +79,11 @@
             { mock<NotificationGutsManager>() },
         )
     }
-var Kosmos.shadeController: ShadeController by Kosmos.Fixture { shadeControllerImpl }
+var Kosmos.shadeController: ShadeController by
+    Kosmos.Fixture {
+        if (SceneContainerFlag.isEnabled) {
+            shadeControllerSceneImpl
+        } else {
+            shadeControllerImpl
+        }
+    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/startable/ShadeStartableKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/startable/ShadeStartableKosmos.kt
index 7dfa686..b85858d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/startable/ShadeStartableKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/startable/ShadeStartableKosmos.kt
@@ -22,11 +22,17 @@
 import com.android.systemui.kosmos.Kosmos.Fixture
 import com.android.systemui.kosmos.applicationCoroutineScope
 import com.android.systemui.log.LogBuffer
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.shade.ShadeExpansionStateManager
 import com.android.systemui.shade.data.repository.shadeRepository
+import com.android.systemui.shade.domain.interactor.panelExpansionInteractor
 import com.android.systemui.shade.transition.ScrimShadeTransitionController
 import com.android.systemui.statusbar.policy.splitShadeStateController
 import com.android.systemui.util.mockito.mock
 
+@Deprecated("ShadeExpansionStateManager is deprecated. Remove your dependency on it instead.")
+val Kosmos.shadeExpansionStateManager by Fixture { ShadeExpansionStateManager() }
+
 val Kosmos.shadeStartable by Fixture {
     ShadeStartable(
         applicationScope = applicationCoroutineScope,
@@ -34,7 +40,10 @@
         touchLog = mock<LogBuffer>(),
         configurationRepository = configurationRepository,
         shadeRepository = shadeRepository,
-        controller = splitShadeStateController,
+        splitShadeStateController = splitShadeStateController,
         scrimShadeTransitionController = mock<ScrimShadeTransitionController>(),
+        sceneInteractorProvider = { sceneInteractor },
+        panelExpansionInteractorProvider = { panelExpansionInteractor },
+        shadeExpansionStateManager = shadeExpansionStateManager,
     )
 }
diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp
index f4337d4..8905ad3 100644
--- a/ravenwood/Android.bp
+++ b/ravenwood/Android.bp
@@ -151,7 +151,7 @@
 
 filegroup {
     name: "ravenwood-services-jarjar-rules",
-    srcs: ["ravenwood-services-jarjar-rules.txt"],
+    srcs: ["texts/ravenwood-services-jarjar-rules.txt"],
     visibility: ["//frameworks/base"],
 }
 
@@ -159,7 +159,7 @@
 // The "test" just shows the available stats filenames.
 sh_test_host {
     name: "ravenwood-stats-checker",
-    src: "ravenwood-stats-checker.sh",
+    src: "scripts/ravenwood-stats-checker.sh",
     test_suites: ["general-tests"],
     data: [
         ":framework-minus-apex.ravenwood.stats",
diff --git a/ravenwood/ravenwood-stats-checker.sh b/ravenwood/ravenwood-stats-checker.sh
deleted file mode 100755
index fb58e72..0000000
--- a/ravenwood/ravenwood-stats-checker.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/bash
-
-# Just print the available *.csv filenames.
-echo '#Stats files:'
-ls *.csv
\ No newline at end of file
diff --git a/ravenwood/bulk_enable.py b/ravenwood/scripts/bulk_enable.py
similarity index 100%
rename from ravenwood/bulk_enable.py
rename to ravenwood/scripts/bulk_enable.py
diff --git a/ravenwood/fix_test_runner.py b/ravenwood/scripts/fix_test_runner.py
similarity index 100%
rename from ravenwood/fix_test_runner.py
rename to ravenwood/scripts/fix_test_runner.py
diff --git a/ravenwood/list-ravenwood-tests.sh b/ravenwood/scripts/list-ravenwood-tests.sh
similarity index 100%
rename from ravenwood/list-ravenwood-tests.sh
rename to ravenwood/scripts/list-ravenwood-tests.sh
diff --git a/ravenwood/run-ravenwood-tests.sh b/ravenwood/scripts/ravenwood-stats-checker.sh
similarity index 65%
copy from ravenwood/run-ravenwood-tests.sh
copy to ravenwood/scripts/ravenwood-stats-checker.sh
index a303626..93f4a3f 100755
--- a/ravenwood/run-ravenwood-tests.sh
+++ b/ravenwood/scripts/ravenwood-stats-checker.sh
@@ -13,16 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Run all the ravenwood tests + hoststubgen unit tests.
-
-all_tests="hoststubgentest tiny-framework-dump-test hoststubgen-invoke-test"
-
-# "echo" is to remove the newlines
-all_tests="$all_tests $(echo $(${0%/*}/list-ravenwood-tests.sh) )"
-
-run() {
-    echo "Running: $*"
-    "${@}"
-}
-
-run ${ATEST:-atest} $all_tests
+# Just print the available *.csv filenames.
+echo '#Stats files:'
+ls *.csv
\ No newline at end of file
diff --git a/ravenwood/scripts/ravenwood-stats-collector.sh b/ravenwood/scripts/ravenwood-stats-collector.sh
new file mode 100755
index 0000000..4dcaa2b
--- /dev/null
+++ b/ravenwood/scripts/ravenwood-stats-collector.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+# 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.
+
+# Script to collect the ravenwood "stats" CVS files and create a single file.
+
+set -e
+
+# Output file
+out=/tmp/ravenwood-stats-all.csv
+
+# Where the input files are.
+path=$ANDROID_BUILD_TOP/out/host/linux-x86/testcases/ravenwood-stats-checker/x86_64/
+
+m() {
+    ${ANDROID_BUILD_TOP}/build/soong/soong_ui.bash --make-mode "$@"
+}
+
+# Building this will generate the files we need.
+m ravenwood-stats-checker
+
+# Start...
+
+cd $path
+
+dump() {
+    local jar=$1
+    local file=$2
+
+    sed -e '1d' -e "s/^/$jar,/"  $file
+}
+
+collect() {
+    echo 'Jar,PackageName,ClassName,SupportedMethods,TotalMethods'
+    dump "framework-minus-apex"  hoststubgen_framework-minus-apex_stats.csv
+    dump "service.core"  hoststubgen_services.core_stats.csv
+}
+
+collect >$out
+
+echo "Full dump CVS created at $out"
diff --git a/ravenwood/run-ravenwood-tests.sh b/ravenwood/scripts/run-ravenwood-tests.sh
similarity index 95%
rename from ravenwood/run-ravenwood-tests.sh
rename to ravenwood/scripts/run-ravenwood-tests.sh
index a303626..926c08f 100755
--- a/ravenwood/run-ravenwood-tests.sh
+++ b/ravenwood/scripts/run-ravenwood-tests.sh
@@ -15,7 +15,7 @@
 
 # Run all the ravenwood tests + hoststubgen unit tests.
 
-all_tests="hoststubgentest tiny-framework-dump-test hoststubgen-invoke-test"
+all_tests="hoststubgentest tiny-framework-dump-test hoststubgen-invoke-test ravenwood-stats-checker"
 
 # "echo" is to remove the newlines
 all_tests="$all_tests $(echo $(${0%/*}/list-ravenwood-tests.sh) )"
diff --git a/ravenwood/framework-minus-apex-ravenwood-policies.txt b/ravenwood/texts/framework-minus-apex-ravenwood-policies.txt
similarity index 100%
rename from ravenwood/framework-minus-apex-ravenwood-policies.txt
rename to ravenwood/texts/framework-minus-apex-ravenwood-policies.txt
diff --git a/ravenwood/ravenwood-annotation-allowed-classes.txt b/ravenwood/texts/ravenwood-annotation-allowed-classes.txt
similarity index 100%
rename from ravenwood/ravenwood-annotation-allowed-classes.txt
rename to ravenwood/texts/ravenwood-annotation-allowed-classes.txt
diff --git a/ravenwood/ravenwood-services-jarjar-rules.txt b/ravenwood/texts/ravenwood-services-jarjar-rules.txt
similarity index 100%
rename from ravenwood/ravenwood-services-jarjar-rules.txt
rename to ravenwood/texts/ravenwood-services-jarjar-rules.txt
diff --git a/ravenwood/ravenwood-standard-options.txt b/ravenwood/texts/ravenwood-standard-options.txt
similarity index 100%
rename from ravenwood/ravenwood-standard-options.txt
rename to ravenwood/texts/ravenwood-standard-options.txt
diff --git a/ravenwood/services.core-ravenwood-policies.txt b/ravenwood/texts/services.core-ravenwood-policies.txt
similarity index 100%
rename from ravenwood/services.core-ravenwood-policies.txt
rename to ravenwood/texts/services.core-ravenwood-policies.txt
diff --git a/services/Android.bp b/services/Android.bp
index 7bbb42e..29d1acf 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -254,6 +254,7 @@
     required: [
         "libukey2_jni_shared",
         "protolog.conf.json.gz",
+        "core.protolog.pb",
     ],
     lint: {
         baseline_filename: "lint-baseline.xml",
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5941fd7..47f03f3 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -414,6 +414,7 @@
 import com.android.internal.os.BinderCallHeavyHitterWatcher.BinderCallHeavyHitterListener;
 import com.android.internal.os.BinderCallHeavyHitterWatcher.HeavyHitterContainer;
 import com.android.internal.os.BinderInternal;
+import com.android.internal.os.BinderInternal.BinderProxyCountEventListener;
 import com.android.internal.os.BinderTransactionNameResolver;
 import com.android.internal.os.ByteTransferPipe;
 import com.android.internal.os.IResultReceiver;
@@ -614,8 +615,8 @@
     private static final int MINIMUM_MEMORY_GROWTH_THRESHOLD = 10 * 1000; // 10 MB
 
     /**
-     * The number of binder proxies we need to have before we start warning and
-     * dumping debug info.
+     * The number of binder proxies we need to have before we start dumping debug info
+     * and kill the offenders.
      */
     private static final int BINDER_PROXY_HIGH_WATERMARK = 6000;
 
@@ -625,6 +626,11 @@
      */
     private static final int BINDER_PROXY_LOW_WATERMARK = 5500;
 
+    /**
+     * The number of binder proxies we need to have before we start warning.
+     */
+    private static final int BINDER_PROXY_WARNING_WATERMARK = 5750;
+
     // Max character limit for a notification title. If the notification title is larger than this
     // the notification will not be legible to the user.
     private static final int MAX_BUGREPORT_TITLE_SIZE = 100;
@@ -9063,34 +9069,10 @@
 
             t.traceBegin("setBinderProxies");
             BinderInternal.nSetBinderProxyCountWatermarks(BINDER_PROXY_HIGH_WATERMARK,
-                    BINDER_PROXY_LOW_WATERMARK);
+                    BINDER_PROXY_LOW_WATERMARK, BINDER_PROXY_WARNING_WATERMARK);
             BinderInternal.nSetBinderProxyCountEnabled(true);
-            BinderInternal.setBinderProxyCountCallback(
-                    (uid) -> {
-                        Slog.wtf(TAG, "Uid " + uid + " sent too many Binders to uid "
-                                + Process.myUid());
-                        BinderProxy.dumpProxyDebugInfo();
-                        CriticalEventLog.getInstance().logExcessiveBinderCalls(uid);
-                        if (uid == Process.SYSTEM_UID) {
-                            Slog.i(TAG, "Skipping kill (uid is SYSTEM)");
-                        } else {
-                            killUid(UserHandle.getAppId(uid), UserHandle.getUserId(uid),
-                                    ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE,
-                                    ApplicationExitInfo.SUBREASON_EXCESSIVE_BINDER_OBJECTS,
-                                    "Too many Binders sent to SYSTEM");
-                            // We need to run a GC here, because killing the processes involved
-                            // actually isn't guaranteed to free up the proxies; in fact, if the
-                            // GC doesn't run for a long time, we may even exceed the global
-                            // proxy limit for a process (20000), resulting in system_server itself
-                            // being killed.
-                            // Note that the GC here might not actually clean up all the proxies,
-                            // because the binder reference decrements will come in asynchronously;
-                            // but if new processes belonging to the UID keep adding proxies, we
-                            // will get another callback here, and run the GC again - this time
-                            // cleaning up the old proxies.
-                            VMRuntime.getRuntime().requestConcurrentGC();
-                        }
-                    }, mHandler);
+            BinderInternal.setBinderProxyCountCallback(new MyBinderProxyCountEventListener(),
+                    mHandler);
             t.traceEnd(); // setBinderProxies
 
             t.traceEnd(); // ActivityManagerStartApps
@@ -9105,6 +9087,46 @@
         }
     }
 
+    private class MyBinderProxyCountEventListener implements BinderProxyCountEventListener {
+        @Override
+        public void onLimitReached(int uid) {
+            Slog.wtf(TAG, "Uid " + uid + " sent too many Binders to uid "
+                    + Process.myUid());
+            BinderProxy.dumpProxyDebugInfo();
+            CriticalEventLog.getInstance().logExcessiveBinderCalls(uid);
+            if (uid == Process.SYSTEM_UID) {
+                Slog.i(TAG, "Skipping kill (uid is SYSTEM)");
+            } else {
+                killUid(UserHandle.getAppId(uid), UserHandle.getUserId(uid),
+                        ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE,
+                        ApplicationExitInfo.SUBREASON_EXCESSIVE_BINDER_OBJECTS,
+                        "Too many Binders sent to SYSTEM");
+                // We need to run a GC here, because killing the processes involved
+                // actually isn't guaranteed to free up the proxies; in fact, if the
+                // GC doesn't run for a long time, we may even exceed the global
+                // proxy limit for a process (20000), resulting in system_server itself
+                // being killed.
+                // Note that the GC here might not actually clean up all the proxies,
+                // because the binder reference decrements will come in asynchronously;
+                // but if new processes belonging to the UID keep adding proxies, we
+                // will get another callback here, and run the GC again - this time
+                // cleaning up the old proxies.
+                VMRuntime.getRuntime().requestConcurrentGC();
+            }
+        }
+
+        @Override
+        public void onWarningThresholdReached(int uid) {
+            if (Flags.logExcessiveBinderProxies()) {
+                Slog.w(TAG, "Uid " + uid + " sent too many ("
+                        + BINDER_PROXY_WARNING_WATERMARK + ") Binders to uid " + Process.myUid());
+                FrameworkStatsLog.write(
+                        FrameworkStatsLog.EXCESSIVE_BINDER_PROXY_COUNT_REPORTED,
+                        uid);
+            }
+        }
+    }
+
     private void watchDeviceProvisioning(Context context) {
         // setting system property based on whether device is provisioned
 
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 9c1ce66..5a750c2 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -71,7 +71,7 @@
 import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK;
 import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE;
 import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL;
-import static android.media.audio.Flags.foregroundAudioControl;
+import static android.media.audio.Flags.roForegroundAudioControl;
 import static android.os.Process.SCHED_OTHER;
 import static android.os.Process.THREAD_GROUP_BACKGROUND;
 import static android.os.Process.THREAD_GROUP_DEFAULT;
@@ -2212,7 +2212,7 @@
                             (fgsType & FOREGROUND_SERVICE_TYPE_LOCATION)
                                     != 0 ? PROCESS_CAPABILITY_FOREGROUND_LOCATION : 0;
 
-                    if (foregroundAudioControl()) { // flag check
+                    if (roForegroundAudioControl()) { // flag check
                         final int fgsAudioType = FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
                                 | FOREGROUND_SERVICE_TYPE_CAMERA
                                 | FOREGROUND_SERVICE_TYPE_MICROPHONE
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index be47f85..ed58c40 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -34,7 +34,7 @@
 import static android.media.audio.Flags.automaticBtDeviceType;
 import static android.media.audio.Flags.featureSpatialAudioHeadtrackingLowLatency;
 import static android.media.audio.Flags.focusFreezeTestApi;
-import static android.media.audio.Flags.foregroundAudioControl;
+import static android.media.audio.Flags.roForegroundAudioControl;
 import static android.media.audiopolicy.Flags.enableFadeManagerConfiguration;
 import static android.os.Process.FIRST_APPLICATION_UID;
 import static android.os.Process.INVALID_UID;
@@ -4539,10 +4539,11 @@
                 + focusFreezeTestApi());
         pw.println("\tcom.android.media.audio.disablePrescaleAbsoluteVolume:"
                 + disablePrescaleAbsoluteVolume());
+
         pw.println("\tcom.android.media.audio.setStreamVolumeOrder:"
                 + setStreamVolumeOrder());
-        pw.println("\tandroid.media.audio.foregroundAudioControl:"
-                + foregroundAudioControl());
+        pw.println("\tandroid.media.audio.roForegroundAudioControl:"
+                + roForegroundAudioControl());
     }
 
     private void dumpAudioMode(PrintWriter pw) {
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index 14f3120..7df63b1 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -869,9 +869,7 @@
             }
 
             if (faceAidlInstances != null && faceAidlInstances.length > 0) {
-                mFaceSensorConfigurations.addAidlConfigs(faceAidlInstances,
-                        name -> IFace.Stub.asInterface(Binder.allowBlocking(
-                                ServiceManager.waitForDeclaredService(name))));
+                mFaceSensorConfigurations.addAidlConfigs(faceAidlInstances);
             }
 
             if (faceService != null) {
@@ -909,9 +907,7 @@
             }
 
             if (fingerprintAidlInstances != null && fingerprintAidlInstances.length > 0) {
-                mFingerprintSensorConfigurations.addAidlSensors(fingerprintAidlInstances,
-                        name -> IFingerprint.Stub.asInterface(Binder.allowBlocking(
-                                ServiceManager.waitForDeclaredService(name))));
+                mFingerprintSensorConfigurations.addAidlSensors(fingerprintAidlInstances);
             }
 
             if (fingerprintService != null) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
index 7ee2a7a..1037124 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
@@ -729,8 +729,8 @@
         private List<ServiceProvider> getProviders(
                 FaceSensorConfigurations faceSensorConfigurations) {
             final List<ServiceProvider> providers = new ArrayList<>();
-            final Pair<String, SensorProps[]> filteredSensorProps =
-                    filterAvailableHalInstances(faceSensorConfigurations);
+            final Pair<String, SensorProps[]> filteredSensorProps = filterAvailableHalInstances(
+                            faceSensorConfigurations);
             providers.add(mFaceProviderFunction.getFaceProvider(filteredSensorProps,
                     faceSensorConfigurations.getResetLockoutRequiresChallenge()));
             return providers;
@@ -739,28 +739,36 @@
         @NonNull
         private Pair<String, SensorProps[]> filterAvailableHalInstances(
                 FaceSensorConfigurations faceSensorConfigurations) {
-            Pair<String, SensorProps[]> finalSensorPair = faceSensorConfigurations.getSensorPair();
+            String finalSensorInstance = faceSensorConfigurations.getSensorInstance();
 
             if (faceSensorConfigurations.isSingleSensorConfigurationPresent()) {
-                return finalSensorPair;
+                return new Pair<>(finalSensorInstance,
+                        faceSensorConfigurations.getSensorPropForInstance(finalSensorInstance));
             }
-
-            final Pair<String, SensorProps[]> virtualSensorProps = faceSensorConfigurations
-                    .getSensorPairForInstance("virtual");
-
-            if (Utils.isVirtualEnabled(getContext())) {
-                if (virtualSensorProps != null) {
-                    return virtualSensorProps;
+            final String virtualInstance = "virtual";
+            final boolean isVirtualHalPresent =
+                    faceSensorConfigurations.doesInstanceExist(virtualInstance);
+            if (Flags.faceVhalFeature() && Utils.isVirtualEnabled(getContext())) {
+                if (isVirtualHalPresent) {
+                    return new Pair<>(virtualInstance,
+                            faceSensorConfigurations.getSensorPropForInstance(virtualInstance));
                 } else {
                     Slog.e(TAG, "Could not find virtual interface while it is enabled");
-                    return finalSensorPair;
+                    return new Pair<>(finalSensorInstance,
+                            faceSensorConfigurations.getSensorPropForInstance(finalSensorInstance));
                 }
             } else {
-                if (virtualSensorProps != null) {
-                    return faceSensorConfigurations.getSensorPairNotForInstance("virtual");
+                if (isVirtualHalPresent) {
+                    final String notAVirtualInstance =
+                            faceSensorConfigurations.getSensorNameNotForInstance(virtualInstance);
+                    if (notAVirtualInstance != null) {
+                        return new Pair<>(notAVirtualInstance, faceSensorConfigurations
+                                .getSensorPropForInstance(notAVirtualInstance));
+                    }
                 }
             }
-            return finalSensorPair;
+            return new Pair<>(finalSensorInstance, faceSensorConfigurations
+                    .getSensorPropForInstance(finalSensorInstance));
         }
 
         private Pair<List<FaceSensorPropertiesInternal>, List<String>>
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index 1ba1213..2dc03ed 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -1128,27 +1128,36 @@
     @NonNull
     private Pair<String, SensorProps[]> filterAvailableHalInstances(
             FingerprintSensorConfigurations fingerprintSensorConfigurations) {
-        Pair<String, SensorProps[]> finalSensorPair =
-                fingerprintSensorConfigurations.getSensorPair();
+        final String finalSensorInstance = fingerprintSensorConfigurations.getSensorInstance();
         if (fingerprintSensorConfigurations.isSingleSensorConfigurationPresent()) {
-            return finalSensorPair;
+            return new Pair<>(finalSensorInstance,
+                    fingerprintSensorConfigurations.getSensorPropForInstance(finalSensorInstance));
         }
-
-        final Pair<String, SensorProps[]> virtualSensorPropsPair = fingerprintSensorConfigurations
-                .getSensorPairForInstance("virtual");
+        final String virtualInstance = "virtual";
+        final boolean isVirtualHalPresent =
+                fingerprintSensorConfigurations.doesInstanceExist(virtualInstance);
         if (Utils.isVirtualEnabled(getContext())) {
-            if (virtualSensorPropsPair != null) {
-                return virtualSensorPropsPair;
+            if (isVirtualHalPresent) {
+                return new Pair<>(virtualInstance,
+                        fingerprintSensorConfigurations.getSensorPropForInstance(virtualInstance));
             } else {
                 Slog.e(TAG, "Could not find virtual interface while it is enabled");
-                return finalSensorPair;
+                return new Pair<>(finalSensorInstance,
+                        fingerprintSensorConfigurations.getSensorPropForInstance(
+                                finalSensorInstance));
             }
         } else {
-            if (virtualSensorPropsPair != null) {
-                return fingerprintSensorConfigurations.getSensorPairNotForInstance("virtual");
+            if (isVirtualHalPresent) {
+                final String notAVirtualInstance = fingerprintSensorConfigurations
+                        .getSensorNameNotForInstance(virtualInstance);
+                if (notAVirtualInstance != null) {
+                    return new Pair<>(notAVirtualInstance, fingerprintSensorConfigurations
+                            .getSensorPropForInstance(notAVirtualInstance));
+                }
             }
         }
-        return finalSensorPair;
+        return new Pair<>(finalSensorInstance, fingerprintSensorConfigurations
+                .getSensorPropForInstance(finalSensorInstance));
     }
 
     private Pair<List<FingerprintSensorPropertiesInternal>, List<String>>
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index f5ed8d4..9f2c36a 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -93,6 +93,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.BackgroundThread;
+import com.android.internal.pm.parsing.pkg.AndroidPackageInternal;
 import com.android.internal.pm.pkg.component.ParsedComponent;
 import com.android.internal.pm.pkg.component.ParsedIntentInfo;
 import com.android.internal.pm.pkg.component.ParsedPermission;
@@ -911,8 +912,10 @@
             sharedUserSetting.mDisabledPackages.remove(p);
         }
         p.getPkgState().setUpdatedSystemApp(false);
+        final AndroidPackageInternal pkg = p.getPkg();
         PackageSetting ret = addPackageLPw(name, p.getRealName(), p.getPath(), p.getAppId(),
-                p.getFlags(), p.getPrivateFlags(), mDomainVerificationManager.generateNewId());
+                p.getFlags(), p.getPrivateFlags(), mDomainVerificationManager.generateNewId(),
+                pkg == null ? false : pkg.isSdkLibrary());
         if (ret != null) {
             ret.setLegacyNativeLibraryPath(p.getLegacyNativeLibraryPath());
             ret.setPrimaryCpuAbi(p.getPrimaryCpuAbiLegacy());
@@ -951,8 +954,8 @@
         }
     }
 
-    PackageSetting addPackageLPw(String name, String realName, File codePath, int uid, int pkgFlags,
-                                 int pkgPrivateFlags, @NonNull UUID domainSetId) {
+    PackageSetting addPackageLPw(String name, String realName, File codePath, int uid,
+            int pkgFlags, int pkgPrivateFlags, @NonNull UUID domainSetId, boolean isSdkLibrary) {
         PackageSetting p = mPackages.get(name);
         if (p != null) {
             if (p.getAppId() == uid) {
@@ -964,7 +967,8 @@
         }
         p = new PackageSetting(name, realName, codePath, pkgFlags, pkgPrivateFlags, domainSetId)
                 .setAppId(uid);
-        if (mAppIds.registerExistingAppId(uid, p, name)) {
+        if ((uid == Process.INVALID_UID && isSdkLibrary && Flags.disallowSdkLibsToBeApps())
+                || mAppIds.registerExistingAppId(uid, p, name)) {
             mPackages.put(name, p);
             return p;
         }
@@ -4176,7 +4180,7 @@
             } else if (appId > 0 || (appId == Process.INVALID_UID && isSdkLibrary
                     && Flags.disallowSdkLibsToBeApps())) {
                 packageSetting = addPackageLPw(name.intern(), realName, new File(codePathStr),
-                        appId, pkgFlags, pkgPrivateFlags, domainSetId);
+                        appId, pkgFlags, pkgPrivateFlags, domainSetId, isSdkLibrary);
                 if (PackageManagerService.DEBUG_SETTINGS)
                     Log.i(PackageManagerService.TAG, "Reading package " + name + ": appId="
                             + appId + " pkg=" + packageSetting);
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index f5ac830..63386a9 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -567,7 +567,7 @@
                     int autoLockPreference =
                             Settings.Secure.getIntForUser(mContext.getContentResolver(),
                                     Settings.Secure.PRIVATE_SPACE_AUTO_LOCK,
-                                    Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_NEVER,
+                                    Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_AFTER_DEVICE_RESTART,
                                     getMainUserIdUnchecked());
                     Slog.i(LOG_TAG, "Auto-lock settings changed to " + autoLockPreference);
                     setOrUpdateAutoLockPreferenceForPrivateProfile(autoLockPreference);
@@ -615,7 +615,7 @@
         int privateSpaceAutoLockPreference =
                 Settings.Secure.getIntForUser(mContext.getContentResolver(),
                         Settings.Secure.PRIVATE_SPACE_AUTO_LOCK,
-                        Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_NEVER,
+                        Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_AFTER_DEVICE_RESTART,
                         getMainUserIdUnchecked());
         if (privateSpaceAutoLockPreference
                 != Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_AFTER_INACTIVITY) {
@@ -714,7 +714,7 @@
         if (isAutoLockForPrivateSpaceEnabled()) {
             int autoLockPreference = Settings.Secure.getIntForUser(mContext.getContentResolver(),
                     Settings.Secure.PRIVATE_SPACE_AUTO_LOCK,
-                    Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_NEVER,
+                    Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_AFTER_DEVICE_RESTART,
                     getMainUserIdUnchecked());
             boolean isAutoLockOnDeviceLockSelected =
                     autoLockPreference == Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_ON_DEVICE_LOCK;
@@ -1052,7 +1052,8 @@
                 setOrUpdateAutoLockPreferenceForPrivateProfile(
                         Settings.Secure.getIntForUser(mContext.getContentResolver(),
                                 Settings.Secure.PRIVATE_SPACE_AUTO_LOCK,
-                                Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_NEVER, mainUserId));
+                                Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_AFTER_DEVICE_RESTART,
+                                mainUserId));
             }
         }
 
diff --git a/services/core/java/com/android/server/stats/pull/AggregatedMobileDataStatsPuller.java b/services/core/java/com/android/server/stats/pull/AggregatedMobileDataStatsPuller.java
index 881583a..f28a91c 100644
--- a/services/core/java/com/android/server/stats/pull/AggregatedMobileDataStatsPuller.java
+++ b/services/core/java/com/android/server/stats/pull/AggregatedMobileDataStatsPuller.java
@@ -125,6 +125,11 @@
     @GuardedBy("mLock")
     private final Map<UidProcState, MobileDataStats> mUidStats;
 
+    // No reason to keep more dimensions than 3000. The 3000 is the hard top for the statsd metrics
+    // dimensions guardrail. It also will keep the result binder transaction size capped to
+    // approximately 220kB for 3000 atoms
+    private static final int UID_STATS_MAX_SIZE = 3000;
+
     private final SparseIntArray mUidPreviousState;
 
     private NetworkStats mLastMobileUidStats = new NetworkStats(0, -1);
@@ -188,14 +193,18 @@
         }
 
         final UidProcState statsKey = new UidProcState(uid, previousState);
-        MobileDataStats stats;
         if (mUidStats.containsKey(statsKey)) {
-            stats = mUidStats.get(statsKey);
-        } else {
-            stats = new MobileDataStats();
-            mUidStats.put(statsKey, stats);
+            return mUidStats.get(statsKey);
         }
-        return stats;
+        if (mUidStats.size() < UID_STATS_MAX_SIZE) {
+            MobileDataStats stats = new MobileDataStats();
+            mUidStats.put(statsKey, stats);
+            return stats;
+        }
+        if (DEBUG) {
+            Slog.w(TAG, "getUidStatsForPreviousStateLocked() UID_STATS_MAX_SIZE reached");
+        }
+        return null;
     }
 
     private void noteUidProcessStateImpl(int uid, int state) {
@@ -252,10 +261,12 @@
                     continue;
                 }
                 MobileDataStats stats = getUidStatsForPreviousStateLocked(entry.getUid());
-                stats.addTxBytes(entry.getTxBytes());
-                stats.addRxBytes(entry.getRxBytes());
-                stats.addTxPackets(entry.getTxPackets());
-                stats.addRxPackets(entry.getRxPackets());
+                if (stats != null) {
+                    stats.addTxBytes(entry.getTxBytes());
+                    stats.addRxBytes(entry.getRxBytes());
+                    stats.addTxPackets(entry.getTxPackets());
+                    stats.addRxPackets(entry.getRxPackets());
+                }
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index baf274d..2ec26ca 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -819,12 +819,6 @@
     @Nullable
     private Rect mLetterboxBoundsForFixedOrientationAndAspectRatio;
 
-    // Bounds populated in resolveAspectRatioRestriction when this activity is letterboxed for
-    // aspect ratio. If not null, they are used as parent container in
-    // resolveSizeCompatModeConfiguration and in a constructor of CompatDisplayInsets.
-    @Nullable
-    private Rect mLetterboxBoundsForAspectRatio;
-
     // Whether the activity is eligible to be letterboxed for fixed orientation with respect to its
     // requested orientation, even when it's letterbox for another reason (e.g., size compat mode)
     // and therefore #isLetterboxedForFixedOrientationAndAspectRatio returns false.
@@ -8427,14 +8421,10 @@
                     fullConfig.windowConfiguration.getRotation());
         }
 
-        final Rect letterboxedContainerBounds =
-                mLetterboxBoundsForFixedOrientationAndAspectRatio != null
-                ? mLetterboxBoundsForFixedOrientationAndAspectRatio
-                : mLetterboxBoundsForAspectRatio;
-
         // The role of CompatDisplayInsets is like the override bounds.
         mCompatDisplayInsets =
-                new CompatDisplayInsets(mDisplayContent, this, letterboxedContainerBounds);
+                new CompatDisplayInsets(
+                        mDisplayContent, this, mLetterboxBoundsForFixedOrientationAndAspectRatio);
     }
 
     private void clearSizeCompatModeAttributes() {
@@ -8506,7 +8496,6 @@
         mIsAspectRatioApplied = false;
         mIsEligibleForFixedOrientationLetterbox = false;
         mLetterboxBoundsForFixedOrientationAndAspectRatio = null;
-        mLetterboxBoundsForAspectRatio = null;
 
         // Can't use resolvedConfig.windowConfiguration.getWindowingMode() because it can be
         // different from windowing mode of the task (PiP) during transition from fullscreen to PiP
@@ -8545,11 +8534,9 @@
                 getTaskFragment().computeConfigResourceOverrides(resolvedConfig,
                         newParentConfiguration);
             }
-        }
         // If activity in fullscreen mode is letterboxed because of fixed orientation then bounds
-        // are already calculated in resolveFixedOrientationConfiguration, or if in size compat
-        // mode, it should already be calculated in resolveSizeCompatModeConfiguration
-        if (!isLetterboxedForFixedOrientationAndAspectRatio() && !mInSizeCompatModeForBounds) {
+        // are already calculated in resolveFixedOrientationConfiguration.
+        } else if (!isLetterboxedForFixedOrientationAndAspectRatio()) {
             resolveAspectRatioRestriction(newParentConfiguration);
         }
 
@@ -9043,8 +9030,7 @@
         }
         final CompatDisplayInsets compatDisplayInsets = getCompatDisplayInsets();
 
-        if (compatDisplayInsets != null
-                && !compatDisplayInsets.mIsInFixedOrientationOrAspectRatioLetterbox) {
+        if (compatDisplayInsets != null && !compatDisplayInsets.mIsInFixedOrientationLetterbox) {
             // App prefers to keep its original size.
             // If the size compat is from previous fixed orientation letterboxing, we may want to
             // have fixed orientation letterbox again, otherwise it will show the size compat
@@ -9176,7 +9162,6 @@
             // restrict, the bounds should be the requested override bounds.
             getTaskFragment().computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
                     getFixedRotationTransformDisplayInfo());
-            mLetterboxBoundsForAspectRatio = new Rect(resolvedBounds);
         }
     }
 
@@ -10741,10 +10726,10 @@
         /** Whether the {@link Task} windowingMode represents a floating window*/
         final boolean mIsFloating;
         /**
-         * Whether is letterboxed because of fixed orientation or aspect ratio when the
-         * unresizable activity is first shown.
+         * Whether is letterboxed because of fixed orientation when the unresizable activity is
+         * first shown.
          */
-        final boolean mIsInFixedOrientationOrAspectRatioLetterbox;
+        final boolean mIsInFixedOrientationLetterbox;
         /**
          * The nonDecorInsets for each rotation. Includes the navigation bar and cutout insets. It
          * is used to compute the appBounds.
@@ -10759,7 +10744,7 @@
 
         /** Constructs the environment to simulate the bounds behavior of the given container. */
         CompatDisplayInsets(DisplayContent display, ActivityRecord container,
-                @Nullable Rect letterboxedContainerBounds) {
+                @Nullable Rect fixedOrientationBounds) {
             mOriginalRotation = display.getRotation();
             mIsFloating = container.getWindowConfiguration().tasksAreFloating();
             mOriginalRequestedOrientation = container.getRequestedConfigurationOrientation();
@@ -10774,21 +10759,22 @@
                     mNonDecorInsets[rotation] = emptyRect;
                     mStableInsets[rotation] = emptyRect;
                 }
-                mIsInFixedOrientationOrAspectRatioLetterbox = false;
+                mIsInFixedOrientationLetterbox = false;
                 return;
             }
 
             final Task task = container.getTask();
 
-            mIsInFixedOrientationOrAspectRatioLetterbox = letterboxedContainerBounds != null;
+            mIsInFixedOrientationLetterbox = fixedOrientationBounds != null;
+
             // Store the bounds of the Task for the non-resizable activity to use in size compat
             // mode so that the activity will not be resized regardless the windowing mode it is
             // currently in.
-            // When an activity needs to be letterboxed because of fixed orientation or aspect
-            // ratio, use resolved bounds instead of task bounds since the activity will be
-            // displayed within these even if it is in size compat mode.
-            final Rect filledContainerBounds = mIsInFixedOrientationOrAspectRatioLetterbox
-                    ? letterboxedContainerBounds
+            // When an activity needs to be letterboxed because of fixed orientation, use fixed
+            // orientation bounds instead of task bounds since the activity will be displayed
+            // within these even if it is in size compat mode.
+            final Rect filledContainerBounds = mIsInFixedOrientationLetterbox
+                    ? fixedOrientationBounds
                     : task != null ? task.getBounds() : display.getBounds();
             final int filledContainerRotation = task != null
                     ? task.getConfiguration().windowConfiguration.getRotation()
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 38f0587a..354cab3 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -2160,19 +2160,6 @@
         return rect;
     }
 
-    @Override
-    public ActivityManager.TaskDescription getTaskDescription(int id) {
-        synchronized (mGlobalLock) {
-            enforceTaskPermission("getTaskDescription()");
-            final Task tr = mRootWindowContainer.anyTaskForId(id,
-                    MATCH_ATTACHED_TASK_OR_RECENT_TASKS);
-            if (tr != null) {
-                return tr.getTaskDescription();
-            }
-        }
-        return null;
-    }
-
     /**
      * Sets the locusId for a particular activity.
      *
@@ -3072,8 +3059,33 @@
 
     @Override
     public Bitmap getTaskDescriptionIcon(String filePath, int userId) {
-        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
-                userId, "getTaskDescriptionIcon");
+        final int callingUid = Binder.getCallingUid();
+        // Verify that the caller can make the request for the given userId
+        userId = handleIncomingUser(Binder.getCallingPid(), callingUid, userId,
+                "getTaskDescriptionIcon");
+        synchronized (mGlobalLock) {
+            // Verify that the caller can make the request for given icon file path
+            final ActivityRecord matchingActivity = mRootWindowContainer.getActivity(
+                    r -> {
+                        if (r.taskDescription == null
+                                || r.taskDescription.getIconFilename() == null) {
+                            return false;
+                        }
+                        return r.taskDescription.getIconFilename().equals(filePath);
+                    });
+            if (matchingActivity == null || (matchingActivity.getUid() != callingUid)) {
+                // Caller UID doesn't match the requested Activity's UID, check if caller is
+                // privileged
+                try {
+                    enforceActivityTaskPermission("getTaskDescriptionIcon");
+                } catch (SecurityException e) {
+                    Slog.w(TAG, "getTaskDescriptionIcon(): request (callingUid=" + callingUid
+                            + ", filePath=" + filePath + ", user=" + userId + ") doesn't match any "
+                            + "activity");
+                    throw e;
+                }
+            }
+        }
 
         final File passedIconFile = new File(filePath);
         final File legitIconFile = new File(TaskPersister.getUserImagesDir(userId),
@@ -3303,6 +3315,13 @@
         return false;
     }
 
+    /**
+     * An instance method that's easier for mocking in tests.
+     */
+    void enforceActivityTaskPermission(String func) {
+        enforceTaskPermission(func);
+    }
+
     static void enforceTaskPermission(String func) {
         if (checkCallingPermission(MANAGE_ACTIVITY_TASKS) == PackageManager.PERMISSION_GRANTED) {
             return;
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 6f1c834..1ce2cd8 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -1277,8 +1277,9 @@
             final ActivityRecord top = topRunningActivity();
             final ActivityRecord resumedActivity = getResumedActivity();
             if (resumedActivity != null
-                    && (top.getTaskFragment() != this || !canBeResumed(resuming))) {
-                // Pausing the resumed activity because it is occluded by other task fragment.
+                    && (top == null || top.getTaskFragment() != this || !canBeResumed(resuming))) {
+                // Pausing the resumed activity because it is occluded by other task fragment, or
+                // should not be remained in resumed state.
                 if (startPausing(false /* uiSleeping*/, resuming, reason)) {
                     someActivityPaused[0]++;
                 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index 538c0ee..c9aab53 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -166,7 +166,7 @@
             null
         }
         whenever(mocks.settings.addPackageLPw(nullable(), nullable(), nullable(), nullable(),
-                nullable(), nullable(), nullable())) {
+                nullable(), nullable(), nullable(), nullable())) {
             val name: String = getArgument(0)
             val pendingAdd = mPendingPackageAdds.firstOrNull { it.first == name }
                     ?: return@whenever null
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
index 6aa1825..759a974 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
@@ -736,9 +736,10 @@
         Mockito.clearInvocations(mKeyguardManager);
         Mockito.clearInvocations(mSpiedContext);
 
-        // Finally, set the preference to don't auto-lock
+        // Finally, set the preference to auto-lock only after device restart, which is the default
+        // behaviour
         mUms.setOrUpdateAutoLockPreferenceForPrivateProfile(
-                Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_NEVER);
+                Settings.Secure.PRIVATE_SPACE_AUTO_LOCK_AFTER_DEVICE_RESTART);
 
         // Verify that inactivity broadcasts are unregistered and keyguard listener was removed
         Mockito.verify(mSpiedContext).unregisterReceiver(any());
diff --git a/services/tests/servicestests/src/com/android/server/audio/VolumeHelperTest.java b/services/tests/servicestests/src/com/android/server/audio/VolumeHelperTest.java
index 83bbd0e..23728db 100644
--- a/services/tests/servicestests/src/com/android/server/audio/VolumeHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/VolumeHelperTest.java
@@ -35,6 +35,7 @@
 import static android.media.AudioManager.STREAM_RING;
 import static android.media.AudioManager.STREAM_SYSTEM;
 import static android.media.AudioManager.STREAM_VOICE_CALL;
+import static android.media.audio.Flags.autoPublicVolumeApiHardening;
 import static android.view.KeyEvent.ACTION_DOWN;
 import static android.view.KeyEvent.KEYCODE_VOLUME_UP;
 
@@ -47,6 +48,7 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeNotNull;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -66,6 +68,8 @@
 import android.annotation.Nullable;
 import android.app.AppOpsManager;
 import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
 import android.media.AudioDeviceAttributes;
 import android.media.AudioDeviceInfo;
 import android.media.AudioManager;
@@ -214,6 +218,19 @@
 
         reset(mSpyAudioSystem);
 
+        final boolean useFixedVolume = mContext.getResources().getBoolean(
+                Resources.getSystem().getIdentifier("config_useFixedVolume", "bool", "android"));
+        final PackageManager packageManager = mContext.getPackageManager();
+        final boolean isTelevision = packageManager != null
+                && (packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)
+                || packageManager.hasSystemFeature(PackageManager.FEATURE_TELEVISION));
+        final boolean isSingleVolume = mContext.getResources().getBoolean(
+                Resources.getSystem().getIdentifier("config_single_volume", "bool", "android"));
+        final boolean automotiveHardened = mContext.getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_AUTOMOTIVE) && autoPublicVolumeApiHardening();
+        assumeFalse("Skipping test for fixed, TV, single volume and auto devices",
+                useFixedVolume || isTelevision || isSingleVolume || automotiveHardened);
+
         InstrumentationRegistry.getInstrumentation().getUiAutomation()
                 .adoptShellPermissionIdentity(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED,
                         Manifest.permission.MODIFY_AUDIO_ROUTING,
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
index f0dc5f0..7e04277 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
@@ -269,7 +269,7 @@
                 mFingerprintSensorConfigurationsCaptor.capture());
 
         final SensorProps[] fingerprintProp = mFingerprintSensorConfigurationsCaptor.getValue()
-                .getSensorPairForInstance("defaultHIDL").second;
+                .getSensorPropForInstance("defaultHIDL");
 
         assertEquals(fingerprintProp[0].commonProps.sensorId, fingerprintId);
         assertEquals(fingerprintProp[0].commonProps.sensorStrength,
@@ -280,7 +280,7 @@
 
         final android.hardware.biometrics.face.SensorProps[] faceProp =
                 mFaceSensorConfigurationsCaptor.getValue()
-                        .getSensorPairForInstance("defaultHIDL").second;
+                        .getSensorPropForInstance("defaultHIDL");
 
         assertEquals(faceProp[0].commonProps.sensorId, faceId);
         assertEquals(faceProp[0].commonProps.sensorStrength,
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/FaceServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/FaceServiceTest.java
index 3aaac2e..e015e97 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/FaceServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/FaceServiceTest.java
@@ -32,8 +32,6 @@
 import android.content.pm.PackageManager;
 import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.biometrics.IBiometricService;
-import android.hardware.biometrics.face.IFace;
-import android.hardware.biometrics.face.SensorProps;
 import android.hardware.face.FaceAuthenticateOptions;
 import android.hardware.face.FaceSensorConfigurations;
 import android.hardware.face.FaceSensorPropertiesInternal;
@@ -93,18 +91,12 @@
     @Mock
     private FaceProvider mFaceProviderVirtual;
     @Mock
-    private IFace mDefaultFaceDaemon;
-    @Mock
-    private IFace mVirtualFaceDaemon;
-    @Mock
     private IBiometricService mIBiometricService;
     @Mock
     private IBinder mToken;
     @Mock
     private IFaceServiceReceiver mFaceServiceReceiver;
 
-    private final SensorProps mDefaultSensorProps = new SensorProps();
-    private final SensorProps mVirtualSensorProps = new SensorProps();
     private FaceService mFaceService;
     private final FaceSensorPropertiesInternal mSensorPropsDefault =
             new FaceSensorPropertiesInternal(ID_DEFAULT, STRENGTH_STRONG,
@@ -126,10 +118,6 @@
 
     @Before
     public void setUp() throws RemoteException {
-        when(mDefaultFaceDaemon.getSensorProps()).thenReturn(
-                new SensorProps[]{mDefaultSensorProps});
-        when(mVirtualFaceDaemon.getSensorProps()).thenReturn(
-                new SensorProps[]{mVirtualSensorProps});
         when(mFaceProviderDefault.getSensorProperties()).thenReturn(List.of(mSensorPropsDefault));
         when(mFaceProviderVirtual.getSensorProperties()).thenReturn(List.of(mSensorPropsVirtual));
         when(mFaceProviderDefault.containsSensor(anyInt()))
@@ -140,15 +128,7 @@
         mContext.getTestablePermissions().setPermission(
                 USE_BIOMETRIC_INTERNAL, PackageManager.PERMISSION_GRANTED);
         mFaceSensorConfigurations = new FaceSensorConfigurations(false);
-        mFaceSensorConfigurations.addAidlConfigs(new String[]{NAME_DEFAULT, NAME_VIRTUAL},
-                (name) -> {
-                    if (name.equals(IFace.DESCRIPTOR + "/" + NAME_DEFAULT)) {
-                        return mDefaultFaceDaemon;
-                    } else if (name.equals(IFace.DESCRIPTOR + "/" + NAME_VIRTUAL)) {
-                        return mVirtualFaceDaemon;
-                    }
-                    return null;
-                });
+        mFaceSensorConfigurations.addAidlConfigs(new String[]{NAME_DEFAULT, NAME_VIRTUAL});
     }
 
     private void initService() {
@@ -199,15 +179,7 @@
     @RequiresFlagsEnabled(Flags.FLAG_DE_HIDL)
     public void registerAuthenticatorsLegacy_virtualAlwaysWhenNoOther() throws Exception {
         mFaceSensorConfigurations = new FaceSensorConfigurations(false);
-        mFaceSensorConfigurations.addAidlConfigs(new String[]{NAME_VIRTUAL},
-                (name) -> {
-                    if (name.equals(IFace.DESCRIPTOR + "/" + NAME_DEFAULT)) {
-                        return mDefaultFaceDaemon;
-                    } else if (name.equals(IFace.DESCRIPTOR + "/" + NAME_VIRTUAL)) {
-                        return mVirtualFaceDaemon;
-                    }
-                    return null;
-                });
+        mFaceSensorConfigurations.addAidlConfigs(new String[]{NAME_VIRTUAL});
         initService();
 
         mFaceService.mServiceWrapper.registerAuthenticatorsLegacy(mFaceSensorConfigurations);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceTest.java
index 88956b6..20961a9 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintServiceTest.java
@@ -43,8 +43,6 @@
 import android.content.ComponentName;
 import android.content.pm.PackageManager;
 import android.hardware.biometrics.IBiometricService;
-import android.hardware.biometrics.fingerprint.IFingerprint;
-import android.hardware.biometrics.fingerprint.SensorProps;
 import android.hardware.fingerprint.FingerprintAuthenticateOptions;
 import android.hardware.fingerprint.FingerprintSensorConfigurations;
 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
@@ -123,10 +121,6 @@
     private IBinder mToken;
     @Mock
     private VirtualDeviceManagerInternal mVdmInternal;
-    @Mock
-    private IFingerprint mDefaultFingerprintDaemon;
-    @Mock
-    private IFingerprint mVirtualFingerprintDaemon;
 
     @Captor
     private ArgumentCaptor<FingerprintAuthenticateOptions> mAuthenticateOptionsCaptor;
@@ -145,8 +139,6 @@
                     false /* resetLockoutRequiresHardwareAuthToken */);
     private FingerprintSensorConfigurations mFingerprintSensorConfigurations;
     private FingerprintService mService;
-    private final SensorProps mDefaultSensorProps = new SensorProps();
-    private final SensorProps mVirtualSensorProps = new SensorProps();
 
     @Before
     public void setup() throws Exception {
@@ -159,10 +151,6 @@
                 .thenAnswer(i -> i.getArguments()[0].equals(ID_DEFAULT));
         when(mFingerprintVirtual.containsSensor(anyInt()))
                 .thenAnswer(i -> i.getArguments()[0].equals(ID_VIRTUAL));
-        when(mDefaultFingerprintDaemon.getSensorProps()).thenReturn(
-                new SensorProps[]{mDefaultSensorProps});
-        when(mVirtualFingerprintDaemon.getSensorProps()).thenReturn(
-                new SensorProps[]{mVirtualSensorProps});
 
         mContext.addMockSystemService(AppOpsManager.class, mAppOpsManager);
         for (int permission : List.of(OP_USE_BIOMETRIC, OP_USE_FINGERPRINT)) {
@@ -177,15 +165,7 @@
 
         mFingerprintSensorConfigurations = new FingerprintSensorConfigurations(
                 true /* resetLockoutRequiresHardwareAuthToken */);
-        mFingerprintSensorConfigurations.addAidlSensors(new String[]{NAME_DEFAULT, NAME_VIRTUAL},
-                (name) -> {
-                    if (name.equals(IFingerprint.DESCRIPTOR + "/" + NAME_DEFAULT)) {
-                        return mDefaultFingerprintDaemon;
-                    } else if (name.equals(IFingerprint.DESCRIPTOR + "/" + NAME_VIRTUAL)) {
-                        return mVirtualFingerprintDaemon;
-                    }
-                    return null;
-                });
+        mFingerprintSensorConfigurations.addAidlSensors(new String[]{NAME_DEFAULT, NAME_VIRTUAL});
     }
 
     private void initServiceWith(String... aidlInstances) {
@@ -270,15 +250,7 @@
     public void registerAuthenticatorsLegacy_virtualAlwaysWhenNoOther() throws Exception {
         mFingerprintSensorConfigurations =
                 new FingerprintSensorConfigurations(true);
-        mFingerprintSensorConfigurations.addAidlSensors(new String[]{NAME_VIRTUAL},
-                        (name) -> {
-                            if (name.equals(IFingerprint.DESCRIPTOR + "/" + NAME_DEFAULT)) {
-                                return mDefaultFingerprintDaemon;
-                            } else if (name.equals(IFingerprint.DESCRIPTOR + "/" + NAME_VIRTUAL)) {
-                                return mVirtualFingerprintDaemon;
-                            }
-                            return null;
-                        });
+        mFingerprintSensorConfigurations.addAidlSensors(new String[]{NAME_VIRTUAL});
         initServiceWith(NAME_VIRTUAL);
 
         mService.mServiceWrapper.registerAuthenticatorsLegacy(mFingerprintSensorConfigurations);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 173a1b6..1355092 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -1634,6 +1634,28 @@
         assertThat(transition.isInTransientHide(top.getTask())).isTrue();
     }
 
+    /**
+     * Tests ATMS#startActivityWithScreenshot should collect display content for creating snapshot.
+     */
+    @Test
+    public void testActivityStartWithScreenshot() {
+        final ActivityStarter starter = prepareStarter(0 /* flags */);
+        starter.setFreezeScreen(true);
+
+        registerTestTransitionPlayer();
+
+        final Intent intent = new Intent();
+        intent.setComponent(ActivityBuilder.getDefaultComponent());
+        starter.setReason("testActivityStartWithScreenshot")
+                .setIntent(intent)
+                .execute();
+
+        final TransitionController controller = mRootWindowContainer.mTransitionController;
+        final Transition transition = controller.getCollectingTransition();
+        final Transition.ChangeInfo targetChangeInfo = transition.mChanges.get(mDisplayContent);
+        assertThat(targetChangeInfo).isNotNull();
+    }
+
     @Test
     public void testActivityStart_expectAddedToRecentTask() {
         RecentTasks recentTasks = mock(RecentTasks.class);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index ed99108..400f9bb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -38,18 +38,22 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.never;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.ActivityManager;
+import android.app.ActivityManager.TaskDescription;
 import android.app.IApplicationThread;
 import android.app.PictureInPictureParams;
 import android.app.servertransaction.ClientTransactionItem;
@@ -62,6 +66,7 @@
 import android.os.LocaleList;
 import android.os.PowerManagerInternal;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.platform.test.annotations.Presubmit;
 import android.view.Display;
 import android.view.DisplayInfo;
@@ -1099,4 +1104,61 @@
 
         verify(mClientLifecycleManager).onLayoutContinued();
     }
+
+    @Test
+    public void testGetTaskDescriptionIcon_matchingUid() {
+        // Ensure that we do not hold MANAGE_ACTIVITY_TASKS
+        doThrow(new SecurityException()).when(mAtm).enforceActivityTaskPermission(any());
+
+        final String filePath = "abc/def";
+        // Create an activity with a task description at the test icon filepath
+        final ActivityRecord activity = new ActivityBuilder(mAtm)
+                .setUid(android.os.Process.myUid())
+                .setCreateTask(true)
+                .build();
+        final TaskDescription td = new TaskDescription.Builder().build();
+        td.setIconFilename(filePath);
+        activity.setTaskDescription(td);
+
+        // Verify this calls and does not throw a security exception
+        try {
+            mAtm.getTaskDescriptionIcon(filePath, activity.mUserId);
+        } catch (SecurityException e) {
+            fail("Unexpected security exception: " + e);
+        } catch (IllegalArgumentException e) {
+            // Ok, the file doesn't actually exist
+        }
+    }
+
+    @Test
+    public void testGetTaskDescriptionIcon_noMatchingActivity_expectException() {
+        // Ensure that we do not hold MANAGE_ACTIVITY_TASKS
+        doThrow(new SecurityException()).when(mAtm).enforceActivityTaskPermission(any());
+
+        final String filePath = "abc/def";
+
+        // Verify this throws a security exception due to no matching activity
+        assertThrows(SecurityException.class,
+                () -> mAtm.getTaskDescriptionIcon(filePath, UserHandle.myUserId()));
+    }
+
+    @Test
+    public void testGetTaskDescriptionIcon_noMatchingUid_expectException() {
+        // Ensure that we do not hold MANAGE_ACTIVITY_TASKS
+        doThrow(new SecurityException()).when(mAtm).enforceActivityTaskPermission(any());
+
+        final String filePath = "abc/def";
+        // Create an activity with a task description at the test icon filepath
+        final ActivityRecord activity = new ActivityBuilder(mAtm)
+                .setCreateTask(true)
+                .setUid(101010)
+                .build();
+        final TaskDescription td = new TaskDescription.Builder().build();
+        td.setIconFilename(filePath);
+        activity.setTaskDescription(td);
+
+        // Verify this throws a security exception due to no matching UID
+        assertThrows(SecurityException.class,
+                () -> mAtm.getTaskDescriptionIcon(filePath, activity.mUserId));
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index bfa191e..75b84d1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -1472,7 +1472,6 @@
         assertSecurityException(expectCallable, () -> mAtm.registerTaskStackListener(null));
         assertSecurityException(expectCallable,
                 () -> mAtm.unregisterTaskStackListener(null));
-        assertSecurityException(expectCallable, () -> mAtm.getTaskDescription(0));
         assertSecurityException(expectCallable, () -> mAtm.cancelTaskWindowTransition(0));
         assertSecurityException(expectCallable, () -> mAtm.startRecentsActivity(null, 0,
                 null));
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 680738b..856ad2a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -27,7 +27,6 @@
 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_16_9;
 import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_3_2;
@@ -1943,7 +1942,8 @@
         assertThat(mActivity.inSizeCompatMode()).isTrue();
         assertActivityMaxBoundsSandboxed();
 
-        final int scale = dh / dw;
+
+	final int scale = dh / dw;
 
         // App bounds should be dh / scale x dw / scale
         assertEquals(dw, rotatedDisplayBounds.width());
@@ -4148,37 +4148,6 @@
     }
 
     @Test
-    public void testFixedAspectRatioAppInPortraitCloseToSquareDisplay_notInSizeCompat() {
-        setUpDisplaySizeWithApp(2200, 2280);
-        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
-        final DisplayContent display = mActivity.mDisplayContent;
-        // Simulate taskbar, final app bounds are (0, 0, 2200, 2130) - landscape
-        final WindowState navbar = createWindow(null, TYPE_NAVIGATION_BAR, mDisplayContent,
-                "navbar");
-        final Binder owner = new Binder();
-        navbar.mAttrs.providedInsets = new InsetsFrameProvider[] {
-                new InsetsFrameProvider(owner, 0, WindowInsets.Type.navigationBars())
-                        .setInsetsSize(Insets.of(0, 0, 0, 150))
-        };
-        display.getDisplayPolicy().addWindowLw(navbar, navbar.mAttrs);
-        assertTrue(navbar.providesDisplayDecorInsets()
-                && display.getDisplayPolicy().updateDecorInsetsInfo());
-        display.sendNewConfiguration();
-
-        prepareMinAspectRatio(mActivity, OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE,
-                SCREEN_ORIENTATION_LANDSCAPE);
-        // To force config to update again but with the same landscape orientation.
-        mActivity.setRequestedOrientation(SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
-
-        assertTrue(mActivity.shouldCreateCompatDisplayInsets());
-        assertNotNull(mActivity.getCompatDisplayInsets());
-        // Activity is not letterboxed for fixed orientation because orientation is respected
-        // with insets, and should not be in size compat mode
-        assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
-        assertFalse(mActivity.inSizeCompatMode());
-    }
-
-    @Test
     public void testApplyAspectRatio_activityAlignWithParentAppVertical() {
         if (Flags.insetsDecoupledConfiguration()) {
             // TODO (b/151861875): Re-enable it. This is disabled temporarily because the config
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index dab966b..1ca808f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -833,7 +833,7 @@
         final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build();
         final ActivityRecord.CompatDisplayInsets compatInsets =
                 new ActivityRecord.CompatDisplayInsets(
-                        display, activity, /* letterboxedContainerBounds */ null);
+                        display, activity, /* fixedOrientationBounds= */ null);
         task.computeConfigResourceOverrides(inOutConfig, parentConfig, compatInsets);
 
         assertEquals(largerLandscapeBounds, inOutConfig.windowConfiguration.getAppBounds());