Merge "Adds missing permission annotation to HubEndpointSession" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 3c2ae5a..371177c 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -1220,6 +1220,17 @@
 }
 
 java_aconfig_library {
+    name: "device_policy_aconfig_flags_java_export",
+    aconfig_declarations: "device_policy_aconfig_flags",
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+    min_sdk_version: "30",
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.permission",
+    ],
+}
+
+java_aconfig_library {
     name: "device_policy_aconfig_flags_lib_host",
     aconfig_declarations: "device_policy_aconfig_flags",
     host_supported: true,
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index 58763a7..d9ff190 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -165,6 +165,7 @@
     ],
     host_supported: true,
     test_suites: ["general-tests"],
+    require_root: true,
     srcs: [
         "tests/BinaryStreamVisitorTests.cpp",
         "tests/CommandLineOptionsTests.cpp",
diff --git a/cmds/idmap2/libidmap2/ResourceContainer.cpp b/cmds/idmap2/libidmap2/ResourceContainer.cpp
index 57ae354..f22a481 100644
--- a/cmds/idmap2/libidmap2/ResourceContainer.cpp
+++ b/cmds/idmap2/libidmap2/ResourceContainer.cpp
@@ -22,6 +22,7 @@
 #include <utility>
 #include <vector>
 
+#include "android-base/scopeguard.h"
 #include "androidfw/ApkAssets.h"
 #include "androidfw/AssetManager.h"
 #include "androidfw/Util.h"
@@ -269,27 +270,40 @@
   std::unique_ptr<AssetManager2> am;
   ZipAssetsProvider* zip_assets;
 
-  static Result<ResState> Initialize(std::unique_ptr<ZipAssetsProvider> zip,
+  static Result<ResState> Initialize(std::unique_ptr<ZipAssetsProvider>&& zip,
                                      package_property_t flags) {
     ResState state;
     state.zip_assets = zip.get();
     if ((state.apk_assets = ApkAssets::Load(std::move(zip), flags)) == nullptr) {
-      return Error("failed to load apk asset");
+      return Error("failed to load apk asset for '%s'",
+                   state.zip_assets->GetDebugName().c_str());
     }
 
+    // Make sure we put ZipAssetsProvider where we took it if initialization fails, so the
+    // original object stays valid for any next call it may get.
+    auto scoped_restore_zip_assets = android::base::ScopeGuard([&zip, &state]() {
+      zip = std::unique_ptr<ZipAssetsProvider>(
+          static_cast<ZipAssetsProvider*>(
+              std::move(const_cast<ApkAssets&>(*state.apk_assets)).TakeAssetsProvider().release()));
+    });
+
     if ((state.arsc = state.apk_assets->GetLoadedArsc()) == nullptr) {
-      return Error("failed to retrieve loaded arsc");
+      return Error("failed to retrieve loaded arsc for '%s'",
+                   state.zip_assets->GetDebugName().c_str());
     }
 
     if ((state.package = GetPackageAtIndex0(state.arsc)) == nullptr) {
-      return Error("failed to retrieve loaded package at index 0");
+      return Error("failed to retrieve loaded package at index 0 for '%s'",
+                   state.zip_assets->GetDebugName().c_str());
     }
 
     state.am = std::make_unique<AssetManager2>();
     if (!state.am->SetApkAssets({state.apk_assets}, false)) {
-      return Error("failed to create asset manager");
+      return Error("failed to create asset manager for '%s'",
+                   state.zip_assets->GetDebugName().c_str());
     }
 
+    scoped_restore_zip_assets.Disable();
     return state;
   }
 };
diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp
index 1b656e8..7093614 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -214,6 +214,20 @@
   ASSERT_EQ(idmap->GetHeader()->GetOverlayName(), TestConstants::OVERLAY_NAME_ALL_POLICIES);
 }
 
+TEST(IdmapTests, TargetContainerWorksAfterError) {
+  auto target = TargetResourceContainer::FromPath(GetTestDataPath() + "/target/target-bad.apk");
+  ASSERT_TRUE(target);
+
+  auto crc = target->get()->GetCrc();
+  ASSERT_TRUE(crc);
+
+  // This call tries to construct the full ApkAssets state, and fails.
+  ASSERT_FALSE(target->get()->DefinesOverlayable());
+  auto crc2 = target->get()->GetCrc();
+  ASSERT_TRUE(crc2);
+  EXPECT_EQ(*crc, *crc2);
+}
+
 TEST(IdmapTests, CreateIdmapDataFromApkAssets) {
   std::string target_apk_path = GetTestDataPath() + "/target/target.apk";
   std::string overlay_apk_path = GetTestDataPath() + "/overlay/overlay.apk";
diff --git a/cmds/idmap2/tests/data/target/target-bad.apk b/cmds/idmap2/tests/data/target/target-bad.apk
new file mode 100644
index 0000000..fd86782
--- /dev/null
+++ b/cmds/idmap2/tests/data/target/target-bad.apk
Binary files differ
diff --git a/core/api/current.txt b/core/api/current.txt
index 1b42977..f3d19ca 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -247,6 +247,7 @@
     field public static final String READ_BASIC_PHONE_STATE = "android.permission.READ_BASIC_PHONE_STATE";
     field public static final String READ_CALENDAR = "android.permission.READ_CALENDAR";
     field public static final String READ_CALL_LOG = "android.permission.READ_CALL_LOG";
+    field @FlaggedApi("android.media.tv.flags.media_quality_fw") public static final String READ_COLOR_ZONES = "android.permission.READ_COLOR_ZONES";
     field public static final String READ_CONTACTS = "android.permission.READ_CONTACTS";
     field @FlaggedApi("com.android.server.feature.flags.enable_read_dropbox_permission") public static final String READ_DROPBOX_DATA = "android.permission.READ_DROPBOX_DATA";
     field public static final String READ_EXTERNAL_STORAGE = "android.permission.READ_EXTERNAL_STORAGE";
@@ -17082,7 +17083,7 @@
     method public void arcTo(@NonNull android.graphics.RectF, float, float);
     method public void arcTo(float, float, float, float, float, float, boolean);
     method public void close();
-    method @Deprecated public void computeBounds(@NonNull android.graphics.RectF, boolean);
+    method public void computeBounds(@NonNull android.graphics.RectF, boolean);
     method @FlaggedApi("com.android.graphics.flags.exact_compute_bounds") public void computeBounds(@NonNull android.graphics.RectF);
     method public void conicTo(float, float, float, float, float);
     method public void cubicTo(float, float, float, float, float, float);
@@ -27160,10 +27161,10 @@
     method public int describeContents();
     method public int getColorFormat();
     method public int getCompressAlgorithm();
-    method @IntRange(from=0) public int getHorizontalZonesNumber();
+    method @IntRange(from=0, to=128) public int getHorizontalZonesNumber();
     method @NonNull public String getPackageName();
     method public int getSource();
-    method @IntRange(from=0) public int getVerticalZonesNumber();
+    method @IntRange(from=0, to=80) public int getVerticalZonesNumber();
     method @NonNull public int[] getZonesColors();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.media.quality.AmbientBacklightMetadata> CREATOR;
@@ -40810,13 +40811,14 @@
 
   public abstract class AutofillService extends android.app.Service {
     ctor public AutofillService();
-    method @Nullable public final android.service.autofill.FillEventHistory getFillEventHistory();
+    method @Deprecated @FlaggedApi("android.service.autofill.autofill_session_destroyed") @Nullable public final android.service.autofill.FillEventHistory getFillEventHistory();
     method public final android.os.IBinder onBind(android.content.Intent);
     method public void onConnected();
     method public void onDisconnected();
     method public abstract void onFillRequest(@NonNull android.service.autofill.FillRequest, @NonNull android.os.CancellationSignal, @NonNull android.service.autofill.FillCallback);
     method public abstract void onSaveRequest(@NonNull android.service.autofill.SaveRequest, @NonNull android.service.autofill.SaveCallback);
     method public void onSavedDatasetsInfoRequest(@NonNull android.service.autofill.SavedDatasetsInfoCallback);
+    method @FlaggedApi("android.service.autofill.autofill_session_destroyed") public void onSessionDestroyed(@Nullable android.service.autofill.FillEventHistory);
     field public static final String EXTRA_FILL_RESPONSE = "android.service.autofill.extra.FILL_RESPONSE";
     field public static final String SERVICE_INTERFACE = "android.service.autofill.AutofillService";
     field public static final String SERVICE_META_DATA = "android.autofill";
@@ -53395,6 +53397,7 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.view.Surface> CREATOR;
     field public static final int FRAME_RATE_COMPATIBILITY_DEFAULT = 0; // 0x0
     field public static final int FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1; // 0x1
+    field @FlaggedApi("com.android.graphics.surfaceflinger.flags.arr_setframerate_gte_enum") public static final int FRAME_RATE_COMPATIBILITY_GTE = 2; // 0x2
     field public static final int ROTATION_0 = 0; // 0x0
     field public static final int ROTATION_180 = 2; // 0x2
     field public static final int ROTATION_270 = 3; // 0x3
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index fe6e995..bca2ce2 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -482,6 +482,10 @@
     field public static final long TRACE_TAG_NETWORK = 2097152L; // 0x200000L
   }
 
+  public class UpdateEngine {
+    method @FlaggedApi("android.os.update_engine_api") public void triggerPostinstall(@NonNull String);
+  }
+
 }
 
 package android.os.storage {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index e7efa24..a593970 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -78,6 +78,7 @@
     field @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public static final String BIND_ON_DEVICE_INTELLIGENCE_SERVICE = "android.permission.BIND_ON_DEVICE_INTELLIGENCE_SERVICE";
     field @FlaggedApi("android.app.ondeviceintelligence.flags.enable_on_device_intelligence") public static final String BIND_ON_DEVICE_SANDBOXED_INFERENCE_SERVICE = "android.permission.BIND_ON_DEVICE_SANDBOXED_INFERENCE_SERVICE";
     field public static final String BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE = "android.permission.BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE";
+    field @FlaggedApi("android.location.flags.population_density_provider") public static final String BIND_POPULATION_DENSITY_PROVIDER_SERVICE = "android.permission.BIND_POPULATION_DENSITY_PROVIDER_SERVICE";
     field public static final String BIND_PRINT_RECOMMENDATION_SERVICE = "android.permission.BIND_PRINT_RECOMMENDATION_SERVICE";
     field public static final String BIND_REMOTE_LOCKSCREEN_VALIDATION_SERVICE = "android.permission.BIND_REMOTE_LOCKSCREEN_VALIDATION_SERVICE";
     field public static final String BIND_RESOLVER_RANKER_SERVICE = "android.permission.BIND_RESOLVER_RANKER_SERVICE";
@@ -1290,6 +1291,7 @@
     method @FlaggedApi("android.app.live_wallpaper_content_handling") @Nullable @RequiresPermission(android.Manifest.permission.READ_WALLPAPER_INTERNAL) public android.app.wallpaper.WallpaperInstance getWallpaperInstance(int);
     method public void setDisplayOffset(android.os.IBinder, int, int);
     method @FlaggedApi("com.android.window.flags.multi_crop") @RequiresPermission(android.Manifest.permission.SET_WALLPAPER) public int setStreamWithCrops(@NonNull java.io.InputStream, @NonNull android.util.SparseArray<android.graphics.Rect>, boolean, int) throws java.io.IOException;
+    method @FlaggedApi("android.app.live_wallpaper_content_handling") @RequiresPermission(android.Manifest.permission.SET_WALLPAPER) public int setStreamWithDescription(@NonNull java.io.InputStream, @NonNull android.app.wallpaper.WallpaperDescription, boolean, int) throws java.io.IOException;
     method @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT) public boolean setWallpaperComponent(android.content.ComponentName);
     method @FlaggedApi("android.app.live_wallpaper_content_handling") @RequiresPermission(allOf={android.Manifest.permission.SET_WALLPAPER_COMPONENT, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}, conditional=true) public boolean setWallpaperComponentWithDescription(@NonNull android.app.wallpaper.WallpaperDescription, int);
     method @RequiresPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT) public boolean setWallpaperComponentWithFlags(@NonNull android.content.ComponentName, int);
@@ -3301,6 +3303,14 @@
 
 }
 
+package android.app.wallpaper {
+
+  @FlaggedApi("android.app.live_wallpaper_content_handling") public final class WallpaperDescription implements android.os.Parcelable {
+    method @NonNull public android.util.SparseArray<android.graphics.Rect> getCropHints();
+  }
+
+}
+
 package android.app.wallpapereffectsgeneration {
 
   public final class CameraAttributes implements android.os.Parcelable {
@@ -8126,6 +8136,8 @@
     method @NonNull public java.util.List<android.media.quality.SoundProfile> getSoundProfilesByPackage(@NonNull String);
     method public void setAutoPictureQualityEnabled(boolean);
     method public void setAutoSoundQualityEnabled(boolean);
+    method public boolean setDefaultPictureProfile(@Nullable String);
+    method public boolean setDefaultSoundProfile(@Nullable String);
     method public void setPictureProfileAllowList(@NonNull java.util.List<java.lang.String>);
     method public void setSoundProfileAllowList(@NonNull java.util.List<java.lang.String>);
     method public void setSuperResolutionEnabled(boolean);
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 603677e..5442ab7 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -543,7 +543,6 @@
     method @FlaggedApi("com.android.window.flags.multi_crop") @RequiresPermission(android.Manifest.permission.SET_WALLPAPER) public int setBitmapWithCrops(@Nullable android.graphics.Bitmap, @NonNull java.util.Map<android.graphics.Point,android.graphics.Rect>, boolean, int) throws java.io.IOException;
     method @FlaggedApi("android.app.live_wallpaper_content_handling") @RequiresPermission(android.Manifest.permission.SET_WALLPAPER) public int setBitmapWithDescription(@Nullable android.graphics.Bitmap, @NonNull android.app.wallpaper.WallpaperDescription, boolean, int) throws java.io.IOException;
     method @FlaggedApi("com.android.window.flags.multi_crop") @RequiresPermission(android.Manifest.permission.SET_WALLPAPER) public int setStreamWithCrops(@NonNull java.io.InputStream, @NonNull java.util.Map<android.graphics.Point,android.graphics.Rect>, boolean, int) throws java.io.IOException;
-    method @FlaggedApi("android.app.live_wallpaper_content_handling") @RequiresPermission(android.Manifest.permission.SET_WALLPAPER) public int setStreamWithDescription(@NonNull java.io.InputStream, @NonNull android.app.wallpaper.WallpaperDescription, boolean, int) throws java.io.IOException;
     method public void setWallpaperZoomOut(@NonNull android.os.IBinder, float);
     method public boolean shouldEnableWideColorGamut();
     method public boolean wallpaperSupportsWcg(int);
diff --git a/core/java/android/app/AppOpsManager.aidl b/core/java/android/app/AppOpsManager.aidl
index b4dee2e..56ed290 100644
--- a/core/java/android/app/AppOpsManager.aidl
+++ b/core/java/android/app/AppOpsManager.aidl
@@ -19,6 +19,7 @@
 parcelable AppOpsManager.PackageOps;
 parcelable AppOpsManager.NoteOpEventProxyInfo;
 parcelable AppOpsManager.NoteOpEvent;
+parcelable AppOpsManager.NotedOp;
 parcelable AppOpsManager.OpFeatureEntry;
 parcelable AppOpsManager.OpEntry;
 
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 1913812..c789e28 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -262,6 +262,24 @@
 
     private static final Object sLock = new Object();
 
+    // A map that records noted times for each op.
+    private final ArrayMap<NotedOp, Integer> mPendingNotedOps = new ArrayMap<>();
+    private final HandlerThread mHandlerThread;
+    private final Handler mHandler;
+    private static final int NOTE_OP_BATCHING_DELAY_MILLIS = 1000;
+
+    private boolean isNoteOpBatchingSupported() {
+        // If noteOp is called from system server no IPC is made, hence we don't need batching.
+        if (Process.myUid() == Process.SYSTEM_UID) {
+            return false;
+        }
+        return Flags.noteOpBatchingEnabled();
+    }
+
+    private final Object mBatchedNoteOpLock = new Object();
+    @GuardedBy("mBatchedNoteOpLock")
+    private boolean mIsBatchedNoteOpCallScheduled = false;
+
     /** Current {@link OnOpNotedCallback}. Change via {@link #setOnOpNotedCallback} */
     @GuardedBy("sLock")
     private static @Nullable OnOpNotedCallback sOnOpNotedCallback;
@@ -7466,6 +7484,135 @@
     }
 
     /**
+     * A NotedOp is an app op grouped in noteOp API and sent to the system server in a batch
+     *
+     * @hide
+     */
+    public static final class NotedOp implements Parcelable {
+        private final @IntRange(from = 0, to = _NUM_OP - 1) int mOp;
+        private final @IntRange(from = 0) int mUid;
+        private final @Nullable String mPackageName;
+        private final @Nullable String mAttributionTag;
+        private final int mVirtualDeviceId;
+        private final @Nullable String mMessage;
+        private final boolean mShouldCollectAsyncNotedOp;
+        private final boolean mShouldCollectMessage;
+
+        public NotedOp(int op, int uid, @Nullable String packageName,
+                @Nullable String attributionTag, int virtualDeviceId, @Nullable String message,
+                boolean shouldCollectAsyncNotedOp, boolean shouldCollectMessage) {
+            mOp = op;
+            mUid = uid;
+            mPackageName = packageName;
+            mAttributionTag = attributionTag;
+            mVirtualDeviceId = virtualDeviceId;
+            mMessage = message;
+            mShouldCollectAsyncNotedOp = shouldCollectAsyncNotedOp;
+            mShouldCollectMessage = shouldCollectMessage;
+        }
+
+        NotedOp(Parcel source) {
+            mOp = source.readInt();
+            mUid = source.readInt();
+            mPackageName = source.readString();
+            mAttributionTag = source.readString();
+            mVirtualDeviceId = source.readInt();
+            mMessage = source.readString();
+            mShouldCollectAsyncNotedOp = source.readBoolean();
+            mShouldCollectMessage = source.readBoolean();
+        }
+
+        public int getOp() {
+            return mOp;
+        }
+
+        public int getUid() {
+            return mUid;
+        }
+
+        public @Nullable String getPackageName() {
+            return mPackageName;
+        }
+
+        public @Nullable String getAttributionTag() {
+            return mAttributionTag;
+        }
+
+        public int getVirtualDeviceId() {
+            return mVirtualDeviceId;
+        }
+
+        public @Nullable String getMessage() {
+            return mMessage;
+        }
+
+        public boolean getShouldCollectAsyncNotedOp() {
+            return mShouldCollectAsyncNotedOp;
+        }
+
+        public boolean getShouldCollectMessage() {
+            return mShouldCollectMessage;
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(@NonNull Parcel dest, int flags) {
+            dest.writeInt(mOp);
+            dest.writeInt(mUid);
+            dest.writeString(mPackageName);
+            dest.writeString(mAttributionTag);
+            dest.writeInt(mVirtualDeviceId);
+            dest.writeString(mMessage);
+            dest.writeBoolean(mShouldCollectAsyncNotedOp);
+            dest.writeBoolean(mShouldCollectMessage);
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+            NotedOp that = (NotedOp) o;
+            return mOp == that.mOp && mUid == that.mUid && Objects.equals(mPackageName,
+                    that.mPackageName) && Objects.equals(mAttributionTag, that.mAttributionTag)
+                    && mVirtualDeviceId == that.mVirtualDeviceId && Objects.equals(mMessage,
+                    that.mMessage) && Objects.equals(mShouldCollectAsyncNotedOp,
+                    that.mShouldCollectAsyncNotedOp) && Objects.equals(mShouldCollectMessage,
+                    that.mShouldCollectMessage);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mOp, mUid, mPackageName, mAttributionTag, mVirtualDeviceId,
+                    mMessage, mShouldCollectAsyncNotedOp, mShouldCollectMessage);
+        }
+
+        @Override
+        public String toString() {
+            return "NotedOp{" + "mOp=" + mOp + ", mUid=" + mUid + ", mPackageName=" + mPackageName
+                    + ", mAttributionTag=" + mAttributionTag + ", mVirtualDeviceId="
+                    + mVirtualDeviceId + ", mMessage=" + mMessage + ", mShouldCollectAsyncNotedOp="
+                    + mShouldCollectAsyncNotedOp + ", mShouldCollectMessage="
+                    + mShouldCollectMessage + "}";
+        }
+
+
+        public static final @NonNull Creator<NotedOp> CREATOR =
+                new Creator<>() {
+                    @Override public NotedOp createFromParcel(Parcel source) {
+                        return new NotedOp(source);
+                    }
+
+                    @Override public NotedOp[] newArray(int size) {
+                        return new NotedOp[size];
+                    }
+                };
+    }
+
+    /**
      * Computes the sum of the counts for the given flags in between the begin and
      * end UID states.
      *
@@ -7979,6 +8126,9 @@
     AppOpsManager(Context context, IAppOpsService service) {
         mContext = context;
         mService = service;
+        mHandlerThread = new HandlerThread("AppOpsManager");
+        mHandlerThread.start();
+        mHandler = mHandlerThread.getThreadHandler();
 
         if (mContext != null) {
             final PackageManager pm = mContext.getPackageManager();
@@ -9315,15 +9465,74 @@
                 }
             }
 
-            SyncNotedAppOp syncOp;
-            if (virtualDeviceId == Context.DEVICE_ID_DEFAULT) {
-                syncOp = mService.noteOperation(op, uid, packageName, attributionTag,
-                        collectionMode == COLLECT_ASYNC, message, shouldCollectMessage);
-            } else {
-                syncOp = mService.noteOperationForDevice(op, uid, packageName, attributionTag,
-                    virtualDeviceId, collectionMode == COLLECT_ASYNC, message,
-                    shouldCollectMessage);
+            SyncNotedAppOp syncOp = null;
+            boolean skipBinderCall = false;
+            if (isNoteOpBatchingSupported()) {
+                int mode = sAppOpModeCache.query(
+                        new AppOpModeQuery(op, uid, packageName, virtualDeviceId, attributionTag,
+                                "noteOpNoThrow"));
+                // For FOREGROUND mode, we still need to make a binder call to the system service
+                // to translate it to ALLOWED or IGNORED. So no batching is needed.
+                if (mode != MODE_FOREGROUND) {
+                    synchronized (mBatchedNoteOpLock) {
+                        NotedOp notedOp = new NotedOp(op, uid, packageName, attributionTag,
+                                virtualDeviceId, message, collectionMode == COLLECT_ASYNC,
+                                shouldCollectMessage);
+
+                        // Batch same noteOp calls and send them with their counters to the system
+                        // service asynchronously. The time window for batching is specified in
+                        // NOTE_OP_BATCHING_DELAY_MILLIS. Always allow the first noteOp call to go
+                        // through binder API. Accumulate subsequent same noteOp calls during the
+                        // time window in mPendingNotedOps.
+                        if (!mPendingNotedOps.containsKey(notedOp)) {
+                            mPendingNotedOps.put(notedOp, 0);
+                        } else {
+                            skipBinderCall = true;
+                            mPendingNotedOps.merge(notedOp, 1, Integer::sum);
+                        }
+
+                        if (!mIsBatchedNoteOpCallScheduled) {
+                            mHandler.postDelayed(() -> {
+                                ArrayMap<NotedOp, Integer> pendingNotedOpsCopy;
+                                synchronized(mBatchedNoteOpLock) {
+                                    mIsBatchedNoteOpCallScheduled = false;
+                                    pendingNotedOpsCopy =
+                                            new ArrayMap<NotedOp, Integer>(mPendingNotedOps);
+                                    mPendingNotedOps.clear();
+                                }
+                                for (int i = pendingNotedOpsCopy.size() - 1; i >= 0; i--) {
+                                    if (pendingNotedOpsCopy.valueAt(i) == 0) {
+                                        pendingNotedOpsCopy.removeAt(i);
+                                    }
+                                }
+                                if (!pendingNotedOpsCopy.isEmpty()) {
+                                    try {
+                                        mService.noteOperationsInBatch(pendingNotedOpsCopy);
+                                    } catch (RemoteException e) {
+                                        throw e.rethrowFromSystemServer();
+                                    }
+                                }
+                            }, NOTE_OP_BATCHING_DELAY_MILLIS);
+
+                            mIsBatchedNoteOpCallScheduled = true;
+                        }
+                    }
+
+                    syncOp = new SyncNotedAppOp(mode, op, attributionTag, packageName);
+                }
             }
+
+            if (!skipBinderCall) {
+                if (virtualDeviceId == Context.DEVICE_ID_DEFAULT) {
+                    syncOp = mService.noteOperation(op, uid, packageName, attributionTag,
+                            collectionMode == COLLECT_ASYNC, message, shouldCollectMessage);
+                } else {
+                    syncOp = mService.noteOperationForDevice(op, uid, packageName, attributionTag,
+                            virtualDeviceId, collectionMode == COLLECT_ASYNC, message,
+                            shouldCollectMessage);
+                }
+            }
+
             if (syncOp.getOpMode() == MODE_ALLOWED) {
                 if (collectionMode == COLLECT_SELF) {
                     collectNotedOpForSelf(syncOp);
diff --git a/core/java/android/app/AppOpsManagerInternal.java b/core/java/android/app/AppOpsManagerInternal.java
index b21defb..8b7ea0f 100644
--- a/core/java/android/app/AppOpsManagerInternal.java
+++ b/core/java/android/app/AppOpsManagerInternal.java
@@ -29,7 +29,7 @@
 import com.android.internal.util.function.DodecFunction;
 import com.android.internal.util.function.HexConsumer;
 import com.android.internal.util.function.HexFunction;
-import com.android.internal.util.function.OctFunction;
+import com.android.internal.util.function.NonaFunction;
 import com.android.internal.util.function.QuadFunction;
 import com.android.internal.util.function.UndecFunction;
 
@@ -86,9 +86,9 @@
          */
         SyncNotedAppOp noteOperation(int code, int uid, @Nullable String packageName,
                 @Nullable String featureId, int virtualDeviceId, boolean shouldCollectAsyncNotedOp,
-                @Nullable String message, boolean shouldCollectMessage,
-                @NonNull OctFunction<Integer, Integer, String, String, Integer, Boolean, String,
-                        Boolean, SyncNotedAppOp> superImpl);
+                @Nullable String message, boolean shouldCollectMessage, int notedCount,
+                @NonNull NonaFunction<Integer, Integer, String, String, Integer, Boolean, String,
+                        Boolean, Integer, SyncNotedAppOp> superImpl);
 
         /**
          * Allows overriding note proxy operation behavior.
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index a8671cf..89e25e7 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -2092,7 +2092,7 @@
 
     /**
      * Returns the description of the designated wallpaper. Returns null if the lock screen
-     * wallpaper is requested lock screen wallpaper is not set.
+     * wallpaper is requested and lock screen wallpaper is not set.
 
      * @param which Specifies wallpaper to request (home or lock).
      * @throws IllegalArgumentException if {@code which} is not exactly one of
@@ -2733,7 +2733,7 @@
      * @hide
      */
     @FlaggedApi(FLAG_LIVE_WALLPAPER_CONTENT_HANDLING)
-    @TestApi
+    @SystemApi
     @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
     public int setStreamWithDescription(@NonNull InputStream bitmapData,
             @NonNull WallpaperDescription description, boolean allowBackup,
diff --git a/core/java/android/app/admin/UnknownAuthority.java b/core/java/android/app/admin/UnknownAuthority.java
index 82dcf7e..bebffde 100644
--- a/core/java/android/app/admin/UnknownAuthority.java
+++ b/core/java/android/app/admin/UnknownAuthority.java
@@ -74,14 +74,14 @@
     @Override
     public boolean equals(@Nullable Object o) {
         if (this == o) return true;
-        if (o != null && getClass() == o.getClass()) return false;
+        if (o == null || getClass() != o.getClass()) return false;
         UnknownAuthority other = (UnknownAuthority) o;
         return Objects.equals(mName, other.mName);
     }
 
     @Override
     public int hashCode() {
-        return mName.hashCode();
+        return Objects.hashCode(mName);
     }
 
     @Override
diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig
index 22bc356..361ba73 100644
--- a/core/java/android/app/admin/flags/flags.aconfig
+++ b/core/java/android/app/admin/flags/flags.aconfig
@@ -398,6 +398,7 @@
 
 flag {
   name: "split_create_managed_profile_enabled"
+  is_exported: true
   namespace: "enterprise"
   description: "Split up existing create and provision managed profile API."
   bug: "375382324"
diff --git a/core/java/android/app/wallpaper/WallpaperDescription.java b/core/java/android/app/wallpaper/WallpaperDescription.java
index 3ee00ca..ca2d9e6 100644
--- a/core/java/android/app/wallpaper/WallpaperDescription.java
+++ b/core/java/android/app/wallpaper/WallpaperDescription.java
@@ -20,6 +20,7 @@
 
 import android.annotation.FlaggedApi;
 import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.app.WallpaperInfo;
 import android.app.WallpaperManager;
@@ -153,6 +154,7 @@
      * {@link Builder#setCropHints(SparseArray)}
      * @hide
      */
+    @SystemApi
     @NonNull
     public SparseArray<Rect> getCropHints() {
         return mCropHints;
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index d766017..a577ec0 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -6187,7 +6187,8 @@
      * {@link #EXTRA_CHOOSER_MODIFY_SHARE_ACTION},
      * {@link #EXTRA_METADATA_TEXT},
      * {@link #EXTRA_CHOOSER_REFINEMENT_INTENT_SENDER},
-     * {@link #EXTRA_CHOOSER_RESULT_INTENT_SENDER}.
+     * {@link #EXTRA_CHOOSER_RESULT_INTENT_SENDER},
+     * {@link #EXTRA_EXCLUDE_COMPONENTS}.
      * </p>
      */
     public static final String EXTRA_CHOOSER_ADDITIONAL_CONTENT_URI =
diff --git a/core/java/android/os/CombinedMessageQueue/MessageQueue.java b/core/java/android/os/CombinedMessageQueue/MessageQueue.java
index 23114c4..804e8fa 100644
--- a/core/java/android/os/CombinedMessageQueue/MessageQueue.java
+++ b/core/java/android/os/CombinedMessageQueue/MessageQueue.java
@@ -19,6 +19,8 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.TestApi;
+import android.app.ActivityThread;
+import android.app.Instrumentation;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Process;
 import android.os.UserHandle;
@@ -119,7 +121,7 @@
 
     MessageQueue(boolean quitAllowed) {
         initIsProcessAllowedToUseConcurrent();
-        mUseConcurrent = sIsProcessAllowedToUseConcurrent;
+        mUseConcurrent = sIsProcessAllowedToUseConcurrent && !isInstrumenting();
         mQuitAllowed = quitAllowed;
         mPtr = nativeInit();
     }
@@ -172,6 +174,15 @@
         }
     }
 
+    private static boolean isInstrumenting() {
+        final ActivityThread activityThread = ActivityThread.currentActivityThread();
+        if (activityThread == null) {
+            return false;
+        }
+        final Instrumentation instrumentation = activityThread.getInstrumentation();
+        return instrumentation != null && instrumentation.isInstrumenting();
+    }
+
     @Override
     protected void finalize() throws Throwable {
         try {
diff --git a/core/java/android/os/CpuHeadroomParamsInternal.aidl b/core/java/android/os/CpuHeadroomParamsInternal.aidl
index d572f965..12b2093 100644
--- a/core/java/android/os/CpuHeadroomParamsInternal.aidl
+++ b/core/java/android/os/CpuHeadroomParamsInternal.aidl
@@ -28,6 +28,5 @@
     int[] tids;
     int calculationWindowMillis = 1000;
     CpuHeadroomParams.CalculationType calculationType = CpuHeadroomParams.CalculationType.MIN;
-    CpuHeadroomParams.SelectionType selectionType = CpuHeadroomParams.SelectionType.ALL;
 }
 
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index bf7116d..6855d95 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -50,6 +50,7 @@
 
 import dalvik.annotation.optimization.CriticalNative;
 import dalvik.annotation.optimization.FastNative;
+import dalvik.annotation.optimization.NeverInline;
 
 import libcore.util.SneakyThrow;
 
@@ -587,6 +588,17 @@
         return parcel;
     }
 
+    @NeverInline
+    private void errorUsedWhileRecycling() {
+        Log.wtf(TAG, "Parcel used while recycled. "
+                + Log.getStackTraceString(new Throwable())
+                + " Original recycle call (if DEBUG_RECYCLE): ", mStack);
+    }
+
+    private void assertNotRecycled() {
+        if (mRecycled) errorUsedWhileRecycling();
+    }
+
     /**
      * Put a Parcel object back into the pool.  You must not touch
      * the object after this call.
@@ -635,6 +647,7 @@
      * @hide
      */
     public void setReadWriteHelper(@Nullable ReadWriteHelper helper) {
+        assertNotRecycled();
         mReadWriteHelper = helper != null ? helper : ReadWriteHelper.DEFAULT;
     }
 
@@ -644,6 +657,7 @@
      * @hide
      */
     public boolean hasReadWriteHelper() {
+        assertNotRecycled();
         return (mReadWriteHelper != null) && (mReadWriteHelper != ReadWriteHelper.DEFAULT);
     }
 
@@ -670,6 +684,7 @@
      * @hide
      */
     public final void markSensitive() {
+        assertNotRecycled();
         nativeMarkSensitive(mNativePtr);
     }
 
@@ -686,6 +701,7 @@
      * @hide
      */
     public final boolean isForRpc() {
+        assertNotRecycled();
         return nativeIsForRpc(mNativePtr);
     }
 
@@ -693,21 +709,25 @@
     @ParcelFlags
     @TestApi
     public int getFlags() {
+        assertNotRecycled();
         return mFlags;
     }
 
     /** @hide */
     public void setFlags(@ParcelFlags int flags) {
+        assertNotRecycled();
         mFlags = flags;
     }
 
     /** @hide */
     public void addFlags(@ParcelFlags int flags) {
+        assertNotRecycled();
         mFlags |= flags;
     }
 
     /** @hide */
     private boolean hasFlags(@ParcelFlags int flags) {
+        assertNotRecycled();
         return (mFlags & flags) == flags;
     }
 
@@ -720,6 +740,7 @@
     // We don't really need to protect it; even if 3p / non-system apps, nothing would happen.
     // This would only work when used on a reply parcel by a binder object that's allowed-blocking.
     public void setPropagateAllowBlocking() {
+        assertNotRecycled();
         addFlags(FLAG_PROPAGATE_ALLOW_BLOCKING);
     }
 
@@ -727,6 +748,7 @@
      * Returns the total amount of data contained in the parcel.
      */
     public int dataSize() {
+        assertNotRecycled();
         return nativeDataSize(mNativePtr);
     }
 
@@ -735,6 +757,7 @@
      * parcel.  That is, {@link #dataSize}-{@link #dataPosition}.
      */
     public final int dataAvail() {
+        assertNotRecycled();
         return nativeDataAvail(mNativePtr);
     }
 
@@ -743,6 +766,7 @@
      * more than {@link #dataSize}.
      */
     public final int dataPosition() {
+        assertNotRecycled();
         return nativeDataPosition(mNativePtr);
     }
 
@@ -753,6 +777,7 @@
      * data buffer.
      */
     public final int dataCapacity() {
+        assertNotRecycled();
         return nativeDataCapacity(mNativePtr);
     }
 
@@ -764,6 +789,7 @@
      * @param size The new number of bytes in the Parcel.
      */
     public final void setDataSize(int size) {
+        assertNotRecycled();
         nativeSetDataSize(mNativePtr, size);
     }
 
@@ -773,6 +799,7 @@
      * {@link #dataSize}.
      */
     public final void setDataPosition(int pos) {
+        assertNotRecycled();
         nativeSetDataPosition(mNativePtr, pos);
     }
 
@@ -784,11 +811,13 @@
      * with this method.
      */
     public final void setDataCapacity(int size) {
+        assertNotRecycled();
         nativeSetDataCapacity(mNativePtr, size);
     }
 
     /** @hide */
     public final boolean pushAllowFds(boolean allowFds) {
+        assertNotRecycled();
         return nativePushAllowFds(mNativePtr, allowFds);
     }
 
@@ -809,6 +838,7 @@
      * in different versions of the platform.
      */
     public final byte[] marshall() {
+        assertNotRecycled();
         return nativeMarshall(mNativePtr);
     }
 
@@ -816,15 +846,18 @@
      * Fills the raw bytes of this Parcel with the supplied data.
      */
     public final void unmarshall(@NonNull byte[] data, int offset, int length) {
+        assertNotRecycled();
         nativeUnmarshall(mNativePtr, data, offset, length);
     }
 
     public final void appendFrom(Parcel parcel, int offset, int length) {
+        assertNotRecycled();
         nativeAppendFrom(mNativePtr, parcel.mNativePtr, offset, length);
     }
 
     /** @hide */
     public int compareData(Parcel other) {
+        assertNotRecycled();
         return nativeCompareData(mNativePtr, other.mNativePtr);
     }
 
@@ -835,6 +868,7 @@
 
     /** @hide */
     public final void setClassCookie(Class clz, Object cookie) {
+        assertNotRecycled();
         if (mClassCookies == null) {
             mClassCookies = new ArrayMap<>();
         }
@@ -844,11 +878,13 @@
     /** @hide */
     @Nullable
     public final Object getClassCookie(Class clz) {
+        assertNotRecycled();
         return mClassCookies != null ? mClassCookies.get(clz) : null;
     }
 
     /** @hide */
     public void removeClassCookie(Class clz, Object expectedCookie) {
+        assertNotRecycled();
         if (mClassCookies != null) {
             Object removedCookie = mClassCookies.remove(clz);
             if (removedCookie != expectedCookie) {
@@ -866,21 +902,25 @@
      * @hide
      */
     public boolean hasClassCookie(Class clz) {
+        assertNotRecycled();
         return mClassCookies != null && mClassCookies.containsKey(clz);
     }
 
     /** @hide */
     public final void adoptClassCookies(Parcel from) {
+        assertNotRecycled();
         mClassCookies = from.mClassCookies;
     }
 
     /** @hide */
     public Map<Class, Object> copyClassCookies() {
+        assertNotRecycled();
         return new ArrayMap<>(mClassCookies);
     }
 
     /** @hide */
     public void putClassCookies(Map<Class, Object> cookies) {
+        assertNotRecycled();
         if (cookies == null) {
             return;
         }
@@ -894,6 +934,7 @@
      * Report whether the parcel contains any marshalled file descriptors.
      */
     public boolean hasFileDescriptors() {
+        assertNotRecycled();
         return nativeHasFileDescriptors(mNativePtr);
     }
 
@@ -909,6 +950,7 @@
      * @throws IllegalArgumentException if the parameters are out of the permitted ranges.
      */
     public boolean hasFileDescriptors(int offset, int length) {
+        assertNotRecycled();
         return nativeHasFileDescriptorsInRange(mNativePtr, offset, length);
     }
 
@@ -993,6 +1035,7 @@
      * @hide
      */
     public boolean hasBinders() {
+        assertNotRecycled();
         return nativeHasBinders(mNativePtr);
     }
 
@@ -1010,6 +1053,7 @@
      * @hide
      */
     public boolean hasBinders(int offset, int length) {
+        assertNotRecycled();
         return nativeHasBindersInRange(mNativePtr, offset, length);
     }
 
@@ -1020,6 +1064,7 @@
      * at the beginning of transactions as a header.
      */
     public final void writeInterfaceToken(@NonNull String interfaceName) {
+        assertNotRecycled();
         nativeWriteInterfaceToken(mNativePtr, interfaceName);
     }
 
@@ -1030,6 +1075,7 @@
      * should propagate to the caller.
      */
     public final void enforceInterface(@NonNull String interfaceName) {
+        assertNotRecycled();
         nativeEnforceInterface(mNativePtr, interfaceName);
     }
 
@@ -1040,6 +1086,7 @@
      * When used over binder, this exception should propagate to the caller.
      */
     public void enforceNoDataAvail() {
+        assertNotRecycled();
         final int n = dataAvail();
         if (n > 0) {
             throw new BadParcelableException("Parcel data not fully consumed, unread size: " + n);
@@ -1056,6 +1103,7 @@
      * @hide
      */
     public boolean replaceCallingWorkSourceUid(int workSourceUid) {
+        assertNotRecycled();
         return nativeReplaceCallingWorkSourceUid(mNativePtr, workSourceUid);
     }
 
@@ -1072,6 +1120,7 @@
      * @hide
      */
     public int readCallingWorkSourceUid() {
+        assertNotRecycled();
         return nativeReadCallingWorkSourceUid(mNativePtr);
     }
 
@@ -1081,6 +1130,7 @@
      * @param b Bytes to place into the parcel.
      */
     public final void writeByteArray(@Nullable byte[] b) {
+        assertNotRecycled();
         writeByteArray(b, 0, (b != null) ? b.length : 0);
     }
 
@@ -1092,6 +1142,7 @@
      * @param len Number of bytes to write.
      */
     public final void writeByteArray(@Nullable byte[] b, int offset, int len) {
+        assertNotRecycled();
         if (b == null) {
             writeInt(-1);
             return;
@@ -1113,6 +1164,7 @@
      * @see #readBlob()
      */
     public final void writeBlob(@Nullable byte[] b) {
+        assertNotRecycled();
         writeBlob(b, 0, (b != null) ? b.length : 0);
     }
 
@@ -1131,6 +1183,7 @@
      * @see #readBlob()
      */
     public final void writeBlob(@Nullable byte[] b, int offset, int len) {
+        assertNotRecycled();
         if (b == null) {
             writeInt(-1);
             return;
@@ -1149,6 +1202,7 @@
      * growing dataCapacity() if needed.
      */
     public final void writeInt(int val) {
+        assertNotRecycled();
         int err = nativeWriteInt(mNativePtr, val);
         if (err != OK) {
             nativeSignalExceptionForError(err);
@@ -1160,6 +1214,7 @@
      * growing dataCapacity() if needed.
      */
     public final void writeLong(long val) {
+        assertNotRecycled();
         int err = nativeWriteLong(mNativePtr, val);
         if (err != OK) {
             nativeSignalExceptionForError(err);
@@ -1171,6 +1226,7 @@
      * dataPosition(), growing dataCapacity() if needed.
      */
     public final void writeFloat(float val) {
+        assertNotRecycled();
         int err = nativeWriteFloat(mNativePtr, val);
         if (err != OK) {
             nativeSignalExceptionForError(err);
@@ -1182,6 +1238,7 @@
      * current dataPosition(), growing dataCapacity() if needed.
      */
     public final void writeDouble(double val) {
+        assertNotRecycled();
         int err = nativeWriteDouble(mNativePtr, val);
         if (err != OK) {
             nativeSignalExceptionForError(err);
@@ -1193,16 +1250,19 @@
      * growing dataCapacity() if needed.
      */
     public final void writeString(@Nullable String val) {
+        assertNotRecycled();
         writeString16(val);
     }
 
     /** {@hide} */
     public final void writeString8(@Nullable String val) {
+        assertNotRecycled();
         mReadWriteHelper.writeString8(this, val);
     }
 
     /** {@hide} */
     public final void writeString16(@Nullable String val) {
+        assertNotRecycled();
         mReadWriteHelper.writeString16(this, val);
     }
 
@@ -1214,16 +1274,19 @@
      * @hide
      */
     public void writeStringNoHelper(@Nullable String val) {
+        assertNotRecycled();
         writeString16NoHelper(val);
     }
 
     /** {@hide} */
     public void writeString8NoHelper(@Nullable String val) {
+        assertNotRecycled();
         nativeWriteString8(mNativePtr, val);
     }
 
     /** {@hide} */
     public void writeString16NoHelper(@Nullable String val) {
+        assertNotRecycled();
         nativeWriteString16(mNativePtr, val);
     }
 
@@ -1235,6 +1298,7 @@
      * for true or false, respectively, but may change in the future.
      */
     public final void writeBoolean(boolean val) {
+        assertNotRecycled();
         writeInt(val ? 1 : 0);
     }
 
@@ -1246,6 +1310,7 @@
     @UnsupportedAppUsage
     @RavenwoodThrow(blockedBy = android.text.Spanned.class)
     public final void writeCharSequence(@Nullable CharSequence val) {
+        assertNotRecycled();
         TextUtils.writeToParcel(val, this, 0);
     }
 
@@ -1254,6 +1319,7 @@
      * growing dataCapacity() if needed.
      */
     public final void writeStrongBinder(IBinder val) {
+        assertNotRecycled();
         nativeWriteStrongBinder(mNativePtr, val);
     }
 
@@ -1262,6 +1328,7 @@
      * growing dataCapacity() if needed.
      */
     public final void writeStrongInterface(IInterface val) {
+        assertNotRecycled();
         writeStrongBinder(val == null ? null : val.asBinder());
     }
 
@@ -1276,6 +1343,7 @@
      * if {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set.</p>
      */
     public final void writeFileDescriptor(@NonNull FileDescriptor val) {
+        assertNotRecycled();
         nativeWriteFileDescriptor(mNativePtr, val);
     }
 
@@ -1284,6 +1352,7 @@
      * This will be the new name for writeFileDescriptor, for consistency.
      **/
     public final void writeRawFileDescriptor(@NonNull FileDescriptor val) {
+        assertNotRecycled();
         nativeWriteFileDescriptor(mNativePtr, val);
     }
 
@@ -1294,6 +1363,7 @@
      * @param value The array of objects to be written.
      */
     public final void writeRawFileDescriptorArray(@Nullable FileDescriptor[] value) {
+        assertNotRecycled();
         if (value != null) {
             int N = value.length;
             writeInt(N);
@@ -1313,6 +1383,7 @@
      * the future.
      */
     public final void writeByte(byte val) {
+        assertNotRecycled();
         writeInt(val);
     }
 
@@ -1328,6 +1399,7 @@
      * allows you to avoid mysterious type errors at the point of marshalling.
      */
     public final void writeMap(@Nullable Map val) {
+        assertNotRecycled();
         writeMapInternal((Map<String, Object>) val);
     }
 
@@ -1336,6 +1408,7 @@
      * growing dataCapacity() if needed.  The Map keys must be String objects.
      */
     /* package */ void writeMapInternal(@Nullable Map<String,Object> val) {
+        assertNotRecycled();
         if (val == null) {
             writeInt(-1);
             return;
@@ -1361,6 +1434,7 @@
      * growing dataCapacity() if needed.  The Map keys must be String objects.
      */
     /* package */ void writeArrayMapInternal(@Nullable ArrayMap<String, Object> val) {
+        assertNotRecycled();
         if (val == null) {
             writeInt(-1);
             return;
@@ -1390,6 +1464,7 @@
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public void writeArrayMap(@Nullable ArrayMap<String, Object> val) {
+        assertNotRecycled();
         writeArrayMapInternal(val);
     }
 
@@ -1408,6 +1483,7 @@
      */
     public <T extends Parcelable> void writeTypedArrayMap(@Nullable ArrayMap<String, T> val,
             int parcelableFlags) {
+        assertNotRecycled();
         if (val == null) {
             writeInt(-1);
             return;
@@ -1429,6 +1505,7 @@
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public void writeArraySet(@Nullable ArraySet<? extends Object> val) {
+        assertNotRecycled();
         final int size = (val != null) ? val.size() : -1;
         writeInt(size);
         for (int i = 0; i < size; i++) {
@@ -1441,6 +1518,7 @@
      * growing dataCapacity() if needed.
      */
     public final void writeBundle(@Nullable Bundle val) {
+        assertNotRecycled();
         if (val == null) {
             writeInt(-1);
             return;
@@ -1454,6 +1532,7 @@
      * growing dataCapacity() if needed.
      */
     public final void writePersistableBundle(@Nullable PersistableBundle val) {
+        assertNotRecycled();
         if (val == null) {
             writeInt(-1);
             return;
@@ -1467,6 +1546,7 @@
      * growing dataCapacity() if needed.
      */
     public final void writeSize(@NonNull Size val) {
+        assertNotRecycled();
         writeInt(val.getWidth());
         writeInt(val.getHeight());
     }
@@ -1476,6 +1556,7 @@
      * growing dataCapacity() if needed.
      */
     public final void writeSizeF(@NonNull SizeF val) {
+        assertNotRecycled();
         writeFloat(val.getWidth());
         writeFloat(val.getHeight());
     }
@@ -1486,6 +1567,7 @@
      * {@link #writeValue} and must follow the specification there.
      */
     public final void writeList(@Nullable List val) {
+        assertNotRecycled();
         if (val == null) {
             writeInt(-1);
             return;
@@ -1505,6 +1587,7 @@
      * {@link #writeValue} and must follow the specification there.
      */
     public final void writeArray(@Nullable Object[] val) {
+        assertNotRecycled();
         if (val == null) {
             writeInt(-1);
             return;
@@ -1525,6 +1608,7 @@
      * specification there.
      */
     public final <T> void writeSparseArray(@Nullable SparseArray<T> val) {
+        assertNotRecycled();
         if (val == null) {
             writeInt(-1);
             return;
@@ -1540,6 +1624,7 @@
     }
 
     public final void writeSparseBooleanArray(@Nullable SparseBooleanArray val) {
+        assertNotRecycled();
         if (val == null) {
             writeInt(-1);
             return;
@@ -1558,6 +1643,7 @@
      * @hide
      */
     public final void writeSparseIntArray(@Nullable SparseIntArray val) {
+        assertNotRecycled();
         if (val == null) {
             writeInt(-1);
             return;
@@ -1573,6 +1659,7 @@
     }
 
     public final void writeBooleanArray(@Nullable boolean[] val) {
+        assertNotRecycled();
         if (val != null) {
             int N = val.length;
             writeInt(N);
@@ -1607,6 +1694,7 @@
     }
 
     private void ensureWithinMemoryLimit(int typeSize, @NonNull int... dimensions) {
+        assertNotRecycled();
         // For Multidimensional arrays, Calculate total object
         // which will be allocated.
         int totalObjects = 1;
@@ -1624,6 +1712,7 @@
     }
 
     private void ensureWithinMemoryLimit(int typeSize, int length) {
+        assertNotRecycled();
         int estimatedAllocationSize = 0;
         try {
             estimatedAllocationSize = Math.multiplyExact(typeSize, length);
@@ -1647,6 +1736,7 @@
 
     @Nullable
     public final boolean[] createBooleanArray() {
+        assertNotRecycled();
         int N = readInt();
         ensureWithinMemoryLimit(SIZE_BOOLEAN, N);
         // >>2 as a fast divide-by-4 works in the create*Array() functions
@@ -1664,6 +1754,7 @@
     }
 
     public final void readBooleanArray(@NonNull boolean[] val) {
+        assertNotRecycled();
         int N = readInt();
         if (N == val.length) {
             for (int i=0; i<N; i++) {
@@ -1676,6 +1767,7 @@
 
     /** @hide */
     public void writeShortArray(@Nullable short[] val) {
+        assertNotRecycled();
         if (val != null) {
             int n = val.length;
             writeInt(n);
@@ -1690,6 +1782,7 @@
     /** @hide */
     @Nullable
     public short[] createShortArray() {
+        assertNotRecycled();
         int n = readInt();
         ensureWithinMemoryLimit(SIZE_SHORT, n);
         if (n >= 0 && n <= (dataAvail() >> 2)) {
@@ -1705,6 +1798,7 @@
 
     /** @hide */
     public void readShortArray(@NonNull short[] val) {
+        assertNotRecycled();
         int n = readInt();
         if (n == val.length) {
             for (int i = 0; i < n; i++) {
@@ -1716,6 +1810,7 @@
     }
 
     public final void writeCharArray(@Nullable char[] val) {
+        assertNotRecycled();
         if (val != null) {
             int N = val.length;
             writeInt(N);
@@ -1729,6 +1824,7 @@
 
     @Nullable
     public final char[] createCharArray() {
+        assertNotRecycled();
         int N = readInt();
         ensureWithinMemoryLimit(SIZE_CHAR, N);
         if (N >= 0 && N <= (dataAvail() >> 2)) {
@@ -1743,6 +1839,7 @@
     }
 
     public final void readCharArray(@NonNull char[] val) {
+        assertNotRecycled();
         int N = readInt();
         if (N == val.length) {
             for (int i=0; i<N; i++) {
@@ -1754,6 +1851,7 @@
     }
 
     public final void writeIntArray(@Nullable int[] val) {
+        assertNotRecycled();
         if (val != null) {
             int N = val.length;
             writeInt(N);
@@ -1767,6 +1865,7 @@
 
     @Nullable
     public final int[] createIntArray() {
+        assertNotRecycled();
         int N = readInt();
         ensureWithinMemoryLimit(SIZE_INT, N);
         if (N >= 0 && N <= (dataAvail() >> 2)) {
@@ -1781,6 +1880,7 @@
     }
 
     public final void readIntArray(@NonNull int[] val) {
+        assertNotRecycled();
         int N = readInt();
         if (N == val.length) {
             for (int i=0; i<N; i++) {
@@ -1792,6 +1892,7 @@
     }
 
     public final void writeLongArray(@Nullable long[] val) {
+        assertNotRecycled();
         if (val != null) {
             int N = val.length;
             writeInt(N);
@@ -1805,6 +1906,7 @@
 
     @Nullable
     public final long[] createLongArray() {
+        assertNotRecycled();
         int N = readInt();
         ensureWithinMemoryLimit(SIZE_LONG, N);
         // >>3 because stored longs are 64 bits
@@ -1820,6 +1922,7 @@
     }
 
     public final void readLongArray(@NonNull long[] val) {
+        assertNotRecycled();
         int N = readInt();
         if (N == val.length) {
             for (int i=0; i<N; i++) {
@@ -1831,6 +1934,7 @@
     }
 
     public final void writeFloatArray(@Nullable float[] val) {
+        assertNotRecycled();
         if (val != null) {
             int N = val.length;
             writeInt(N);
@@ -1844,6 +1948,7 @@
 
     @Nullable
     public final float[] createFloatArray() {
+        assertNotRecycled();
         int N = readInt();
         ensureWithinMemoryLimit(SIZE_FLOAT, N);
         // >>2 because stored floats are 4 bytes
@@ -1859,6 +1964,7 @@
     }
 
     public final void readFloatArray(@NonNull float[] val) {
+        assertNotRecycled();
         int N = readInt();
         if (N == val.length) {
             for (int i=0; i<N; i++) {
@@ -1870,6 +1976,7 @@
     }
 
     public final void writeDoubleArray(@Nullable double[] val) {
+        assertNotRecycled();
         if (val != null) {
             int N = val.length;
             writeInt(N);
@@ -1883,6 +1990,7 @@
 
     @Nullable
     public final double[] createDoubleArray() {
+        assertNotRecycled();
         int N = readInt();
         ensureWithinMemoryLimit(SIZE_DOUBLE, N);
         // >>3 because stored doubles are 8 bytes
@@ -1898,6 +2006,7 @@
     }
 
     public final void readDoubleArray(@NonNull double[] val) {
+        assertNotRecycled();
         int N = readInt();
         if (N == val.length) {
             for (int i=0; i<N; i++) {
@@ -1909,20 +2018,24 @@
     }
 
     public final void writeStringArray(@Nullable String[] val) {
+        assertNotRecycled();
         writeString16Array(val);
     }
 
     @Nullable
     public final String[] createStringArray() {
+        assertNotRecycled();
         return createString16Array();
     }
 
     public final void readStringArray(@NonNull String[] val) {
+        assertNotRecycled();
         readString16Array(val);
     }
 
     /** {@hide} */
     public final void writeString8Array(@Nullable String[] val) {
+        assertNotRecycled();
         if (val != null) {
             int N = val.length;
             writeInt(N);
@@ -1937,6 +2050,7 @@
     /** {@hide} */
     @Nullable
     public final String[] createString8Array() {
+        assertNotRecycled();
         int N = readInt();
         ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N);
         if (N >= 0) {
@@ -1952,6 +2066,7 @@
 
     /** {@hide} */
     public final void readString8Array(@NonNull String[] val) {
+        assertNotRecycled();
         int N = readInt();
         if (N == val.length) {
             for (int i=0; i<N; i++) {
@@ -1964,6 +2079,7 @@
 
     /** {@hide} */
     public final void writeString16Array(@Nullable String[] val) {
+        assertNotRecycled();
         if (val != null) {
             int N = val.length;
             writeInt(N);
@@ -1978,6 +2094,7 @@
     /** {@hide} */
     @Nullable
     public final String[] createString16Array() {
+        assertNotRecycled();
         int N = readInt();
         ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N);
         if (N >= 0) {
@@ -1993,6 +2110,7 @@
 
     /** {@hide} */
     public final void readString16Array(@NonNull String[] val) {
+        assertNotRecycled();
         int N = readInt();
         if (N == val.length) {
             for (int i=0; i<N; i++) {
@@ -2004,6 +2122,7 @@
     }
 
     public final void writeBinderArray(@Nullable IBinder[] val) {
+        assertNotRecycled();
         if (val != null) {
             int N = val.length;
             writeInt(N);
@@ -2028,6 +2147,7 @@
      */
     public final <T extends IInterface> void writeInterfaceArray(
             @SuppressLint("ArrayReturn") @Nullable T[] val) {
+        assertNotRecycled();
         if (val != null) {
             int N = val.length;
             writeInt(N);
@@ -2043,6 +2163,7 @@
      * @hide
      */
     public final void writeCharSequenceArray(@Nullable CharSequence[] val) {
+        assertNotRecycled();
         if (val != null) {
             int N = val.length;
             writeInt(N);
@@ -2058,6 +2179,7 @@
      * @hide
      */
     public final void writeCharSequenceList(@Nullable ArrayList<CharSequence> val) {
+        assertNotRecycled();
         if (val != null) {
             int N = val.size();
             writeInt(N);
@@ -2071,6 +2193,7 @@
 
     @Nullable
     public final IBinder[] createBinderArray() {
+        assertNotRecycled();
         int N = readInt();
         ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N);
         if (N >= 0) {
@@ -2085,6 +2208,7 @@
     }
 
     public final void readBinderArray(@NonNull IBinder[] val) {
+        assertNotRecycled();
         int N = readInt();
         if (N == val.length) {
             for (int i=0; i<N; i++) {
@@ -2106,6 +2230,7 @@
     @Nullable
     public final <T extends IInterface> T[] createInterfaceArray(
             @NonNull IntFunction<T[]> newArray, @NonNull Function<IBinder, T> asInterface) {
+        assertNotRecycled();
         int N = readInt();
         ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N);
         if (N >= 0) {
@@ -2130,6 +2255,7 @@
     public final <T extends IInterface> void readInterfaceArray(
             @SuppressLint("ArrayReturn") @NonNull T[] val,
             @NonNull Function<IBinder, T> asInterface) {
+        assertNotRecycled();
         int N = readInt();
         if (N == val.length) {
             for (int i=0; i<N; i++) {
@@ -2155,6 +2281,7 @@
      * @see Parcelable
      */
     public final <T extends Parcelable> void writeTypedList(@Nullable List<T> val) {
+        assertNotRecycled();
         writeTypedList(val, 0);
     }
 
@@ -2174,6 +2301,7 @@
      */
     public final <T extends Parcelable> void writeTypedSparseArray(@Nullable SparseArray<T> val,
             int parcelableFlags) {
+        assertNotRecycled();
         if (val == null) {
             writeInt(-1);
             return;
@@ -2203,6 +2331,7 @@
      * @see Parcelable
      */
     public <T extends Parcelable> void writeTypedList(@Nullable List<T> val, int parcelableFlags) {
+        assertNotRecycled();
         if (val == null) {
             writeInt(-1);
             return;
@@ -2228,6 +2357,7 @@
      * @see #readStringList
      */
     public final void writeStringList(@Nullable List<String> val) {
+        assertNotRecycled();
         if (val == null) {
             writeInt(-1);
             return;
@@ -2253,6 +2383,7 @@
      * @see #readBinderList
      */
     public final void writeBinderList(@Nullable List<IBinder> val) {
+        assertNotRecycled();
         if (val == null) {
             writeInt(-1);
             return;
@@ -2275,6 +2406,7 @@
      * @see #readInterfaceList
      */
     public final <T extends IInterface> void writeInterfaceList(@Nullable List<T> val) {
+        assertNotRecycled();
         if (val == null) {
             writeInt(-1);
             return;
@@ -2296,6 +2428,7 @@
      * @see #readParcelableList(List, ClassLoader)
      */
     public final <T extends Parcelable> void writeParcelableList(@Nullable List<T> val, int flags) {
+        assertNotRecycled();
         if (val == null) {
             writeInt(-1);
             return;
@@ -2330,6 +2463,7 @@
      */
     public final <T extends Parcelable> void writeTypedArray(@Nullable T[] val,
             int parcelableFlags) {
+        assertNotRecycled();
         if (val != null) {
             int N = val.length;
             writeInt(N);
@@ -2352,6 +2486,7 @@
      */
     public final <T extends Parcelable> void writeTypedObject(@Nullable T val,
             int parcelableFlags) {
+        assertNotRecycled();
         if (val != null) {
             writeInt(1);
             val.writeToParcel(this, parcelableFlags);
@@ -2389,6 +2524,7 @@
      */
     public <T> void writeFixedArray(@Nullable T val, int parcelableFlags,
             @NonNull int... dimensions) {
+        assertNotRecycled();
         if (val == null) {
             writeInt(-1);
             return;
@@ -2500,6 +2636,7 @@
      * should be used).</p>
      */
     public final void writeValue(@Nullable Object v) {
+        assertNotRecycled();
         if (v instanceof LazyValue) {
             LazyValue value = (LazyValue) v;
             value.writeToParcel(this);
@@ -2617,6 +2754,7 @@
      * @hide
      */
     public void writeValue(int type, @Nullable Object v) {
+        assertNotRecycled();
         switch (type) {
             case VAL_NULL:
                 break;
@@ -2730,6 +2868,7 @@
      * {@link Parcelable#writeToParcel(Parcel, int) Parcelable.writeToParcel()}.
      */
     public final void writeParcelable(@Nullable Parcelable p, int parcelableFlags) {
+        assertNotRecycled();
         if (p == null) {
             writeString(null);
             return;
@@ -2745,6 +2884,7 @@
      * @see #readParcelableCreator
      */
     public final void writeParcelableCreator(@NonNull Parcelable p) {
+        assertNotRecycled();
         String name = p.getClass().getName();
         writeString(name);
     }
@@ -2783,6 +2923,7 @@
      */
     @TestApi
     public boolean allowSquashing() {
+        assertNotRecycled();
         boolean previous = mAllowSquashing;
         mAllowSquashing = true;
         return previous;
@@ -2794,6 +2935,7 @@
      */
     @TestApi
     public void restoreAllowSquashing(boolean previous) {
+        assertNotRecycled();
         mAllowSquashing = previous;
         if (!mAllowSquashing) {
             mWrittenSquashableParcelables = null;
@@ -2850,6 +2992,7 @@
      * @hide
      */
     public boolean maybeWriteSquashed(@NonNull Parcelable p) {
+        assertNotRecycled();
         if (!mAllowSquashing) {
             // Don't squash, and don't put it in the map either.
             writeInt(0);
@@ -2900,6 +3043,7 @@
     @SuppressWarnings("unchecked")
     @Nullable
     public <T extends Parcelable> T readSquashed(SquashReadHelper<T> reader) {
+        assertNotRecycled();
         final int offset = readInt();
         final int pos = dataPosition();
 
@@ -2933,6 +3077,7 @@
      * using the other approaches to writing data in to a Parcel.
      */
     public final void writeSerializable(@Nullable Serializable s) {
+        assertNotRecycled();
         if (s == null) {
             writeString(null);
             return;
@@ -2985,6 +3130,7 @@
      */
     @RavenwoodReplace(blockedBy = AppOpsManager.class)
     public final void writeException(@NonNull Exception e) {
+        assertNotRecycled();
         AppOpsManager.prefixParcelWithAppOpsIfNeeded(this);
 
         int code = getExceptionCode(e);
@@ -3065,6 +3211,7 @@
 
     /** @hide */
     public void writeStackTrace(@NonNull Throwable e) {
+        assertNotRecycled();
         final int sizePosition = dataPosition();
         writeInt(0); // Header size will be filled in later
         StackTraceElement[] stackTrace = e.getStackTrace();
@@ -3090,6 +3237,7 @@
      */
     @RavenwoodReplace(blockedBy = AppOpsManager.class)
     public final void writeNoException() {
+        assertNotRecycled();
         AppOpsManager.prefixParcelWithAppOpsIfNeeded(this);
 
         // Despite the name of this function ("write no exception"),
@@ -3133,6 +3281,7 @@
      * @see #writeNoException
      */
     public final void readException() {
+        assertNotRecycled();
         int code = readExceptionCode();
         if (code != 0) {
             String msg = readString();
@@ -3156,6 +3305,7 @@
     @UnsupportedAppUsage
     @TestApi
     public final int readExceptionCode() {
+        assertNotRecycled();
         int code = readInt();
         if (code == EX_HAS_NOTED_APPOPS_REPLY_HEADER) {
             AppOpsManager.readAndLogNotedAppops(this);
@@ -3189,6 +3339,7 @@
      * @param msg The exception message.
      */
     public final void readException(int code, String msg) {
+        assertNotRecycled();
         String remoteStackTrace = null;
         final int remoteStackPayloadSize = readInt();
         if (remoteStackPayloadSize > 0) {
@@ -3219,6 +3370,7 @@
 
     /** @hide */
     public Exception createExceptionOrNull(int code, String msg) {
+        assertNotRecycled();
         switch (code) {
             case EX_PARCELABLE:
                 if (readInt() > 0) {
@@ -3251,6 +3403,7 @@
      * Read an integer value from the parcel at the current dataPosition().
      */
     public final int readInt() {
+        assertNotRecycled();
         return nativeReadInt(mNativePtr);
     }
 
@@ -3258,6 +3411,7 @@
      * Read a long integer value from the parcel at the current dataPosition().
      */
     public final long readLong() {
+        assertNotRecycled();
         return nativeReadLong(mNativePtr);
     }
 
@@ -3266,6 +3420,7 @@
      * dataPosition().
      */
     public final float readFloat() {
+        assertNotRecycled();
         return nativeReadFloat(mNativePtr);
     }
 
@@ -3274,6 +3429,7 @@
      * current dataPosition().
      */
     public final double readDouble() {
+        assertNotRecycled();
         return nativeReadDouble(mNativePtr);
     }
 
@@ -3282,16 +3438,19 @@
      */
     @Nullable
     public final String readString() {
+        assertNotRecycled();
         return readString16();
     }
 
     /** {@hide} */
     public final @Nullable String readString8() {
+        assertNotRecycled();
         return mReadWriteHelper.readString8(this);
     }
 
     /** {@hide} */
     public final @Nullable String readString16() {
+        assertNotRecycled();
         return mReadWriteHelper.readString16(this);
     }
 
@@ -3303,16 +3462,19 @@
      * @hide
      */
     public @Nullable String readStringNoHelper() {
+        assertNotRecycled();
         return readString16NoHelper();
     }
 
     /** {@hide} */
     public @Nullable String readString8NoHelper() {
+        assertNotRecycled();
         return nativeReadString8(mNativePtr);
     }
 
     /** {@hide} */
     public @Nullable String readString16NoHelper() {
+        assertNotRecycled();
         return nativeReadString16(mNativePtr);
     }
 
@@ -3320,6 +3482,7 @@
      * Read a boolean value from the parcel at the current dataPosition().
      */
     public final boolean readBoolean() {
+        assertNotRecycled();
         return readInt() != 0;
     }
 
@@ -3330,6 +3493,7 @@
     @UnsupportedAppUsage
     @Nullable
     public final CharSequence readCharSequence() {
+        assertNotRecycled();
         return TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(this);
     }
 
@@ -3337,6 +3501,7 @@
      * Read an object from the parcel at the current dataPosition().
      */
     public final IBinder readStrongBinder() {
+        assertNotRecycled();
         final IBinder result = nativeReadStrongBinder(mNativePtr);
 
         // If it's a reply from a method with @PropagateAllowBlocking, then inherit allow-blocking
@@ -3352,6 +3517,7 @@
      * Read a FileDescriptor from the parcel at the current dataPosition().
      */
     public final ParcelFileDescriptor readFileDescriptor() {
+        assertNotRecycled();
         FileDescriptor fd = nativeReadFileDescriptor(mNativePtr);
         return fd != null ? new ParcelFileDescriptor(fd) : null;
     }
@@ -3359,6 +3525,7 @@
     /** {@hide} */
     @UnsupportedAppUsage
     public final FileDescriptor readRawFileDescriptor() {
+        assertNotRecycled();
         return nativeReadFileDescriptor(mNativePtr);
     }
 
@@ -3369,6 +3536,7 @@
      **/
     @Nullable
     public final FileDescriptor[] createRawFileDescriptorArray() {
+        assertNotRecycled();
         int N = readInt();
         if (N < 0) {
             return null;
@@ -3388,6 +3556,7 @@
      * @return the FileDescriptor array, or null if the array is null.
      **/
     public final void readRawFileDescriptorArray(FileDescriptor[] val) {
+        assertNotRecycled();
         int N = readInt();
         if (N == val.length) {
             for (int i=0; i<N; i++) {
@@ -3402,6 +3571,7 @@
      * Read a byte value from the parcel at the current dataPosition().
      */
     public final byte readByte() {
+        assertNotRecycled();
         return (byte)(readInt() & 0xff);
     }
 
@@ -3416,6 +3586,7 @@
      */
     @Deprecated
     public final void readMap(@NonNull Map outVal, @Nullable ClassLoader loader) {
+        assertNotRecycled();
         readMapInternal(outVal, loader, /* clazzKey */ null, /* clazzValue */ null);
     }
 
@@ -3429,6 +3600,7 @@
     public <K, V> void readMap(@NonNull Map<? super K, ? super V> outVal,
             @Nullable ClassLoader loader, @NonNull Class<K> clazzKey,
             @NonNull Class<V> clazzValue) {
+        assertNotRecycled();
         Objects.requireNonNull(clazzKey);
         Objects.requireNonNull(clazzValue);
         readMapInternal(outVal, loader, clazzKey, clazzValue);
@@ -3447,6 +3619,7 @@
      */
     @Deprecated
     public final void readList(@NonNull List outVal, @Nullable ClassLoader loader) {
+        assertNotRecycled();
         int N = readInt();
         readListInternal(outVal, N, loader, /* clazz */ null);
     }
@@ -3468,6 +3641,7 @@
      */
     public <T> void readList(@NonNull List<? super T> outVal,
             @Nullable ClassLoader loader, @NonNull Class<T> clazz) {
+        assertNotRecycled();
         Objects.requireNonNull(clazz);
         int n = readInt();
         readListInternal(outVal, n, loader, clazz);
@@ -3487,6 +3661,7 @@
     @Deprecated
     @Nullable
     public HashMap readHashMap(@Nullable ClassLoader loader) {
+        assertNotRecycled();
         return readHashMapInternal(loader, /* clazzKey */ null, /* clazzValue */ null);
     }
 
@@ -3501,6 +3676,7 @@
     @Nullable
     public <K, V> HashMap<K, V> readHashMap(@Nullable ClassLoader loader,
             @NonNull Class<? extends K> clazzKey, @NonNull Class<? extends V> clazzValue) {
+        assertNotRecycled();
         Objects.requireNonNull(clazzKey);
         Objects.requireNonNull(clazzValue);
         return readHashMapInternal(loader, clazzKey, clazzValue);
@@ -3513,6 +3689,7 @@
      */
     @Nullable
     public final Bundle readBundle() {
+        assertNotRecycled();
         return readBundle(null);
     }
 
@@ -3524,6 +3701,7 @@
      */
     @Nullable
     public final Bundle readBundle(@Nullable ClassLoader loader) {
+        assertNotRecycled();
         int length = readInt();
         if (length < 0) {
             if (Bundle.DEBUG) Log.d(TAG, "null bundle: length=" + length);
@@ -3544,6 +3722,7 @@
      */
     @Nullable
     public final PersistableBundle readPersistableBundle() {
+        assertNotRecycled();
         return readPersistableBundle(null);
     }
 
@@ -3555,6 +3734,7 @@
      */
     @Nullable
     public final PersistableBundle readPersistableBundle(@Nullable ClassLoader loader) {
+        assertNotRecycled();
         int length = readInt();
         if (length < 0) {
             if (Bundle.DEBUG) Log.d(TAG, "null bundle: length=" + length);
@@ -3573,6 +3753,7 @@
      */
     @NonNull
     public final Size readSize() {
+        assertNotRecycled();
         final int width = readInt();
         final int height = readInt();
         return new Size(width, height);
@@ -3583,6 +3764,7 @@
      */
     @NonNull
     public final SizeF readSizeF() {
+        assertNotRecycled();
         final float width = readFloat();
         final float height = readFloat();
         return new SizeF(width, height);
@@ -3593,6 +3775,7 @@
      */
     @Nullable
     public final byte[] createByteArray() {
+        assertNotRecycled();
         return nativeCreateByteArray(mNativePtr);
     }
 
@@ -3601,6 +3784,7 @@
      * given byte array.
      */
     public final void readByteArray(@NonNull byte[] val) {
+        assertNotRecycled();
         boolean valid = nativeReadByteArray(mNativePtr, val, (val != null) ? val.length : 0);
         if (!valid) {
             throw new RuntimeException("bad array lengths");
@@ -3613,6 +3797,7 @@
      */
     @Nullable
     public final byte[] readBlob() {
+        assertNotRecycled();
         return nativeReadBlob(mNativePtr);
     }
 
@@ -3623,6 +3808,7 @@
     @UnsupportedAppUsage
     @Nullable
     public final String[] readStringArray() {
+        assertNotRecycled();
         return createString16Array();
     }
 
@@ -3632,6 +3818,7 @@
      */
     @Nullable
     public final CharSequence[] readCharSequenceArray() {
+        assertNotRecycled();
         CharSequence[] array = null;
 
         int length = readInt();
@@ -3654,6 +3841,7 @@
      */
     @Nullable
     public final ArrayList<CharSequence> readCharSequenceList() {
+        assertNotRecycled();
         ArrayList<CharSequence> array = null;
 
         int length = readInt();
@@ -3683,6 +3871,7 @@
     @Deprecated
     @Nullable
     public ArrayList readArrayList(@Nullable ClassLoader loader) {
+        assertNotRecycled();
         return readArrayListInternal(loader, /* clazz */ null);
     }
 
@@ -3705,6 +3894,7 @@
     @Nullable
     public <T> ArrayList<T> readArrayList(@Nullable ClassLoader loader,
             @NonNull Class<? extends T> clazz) {
+        assertNotRecycled();
         Objects.requireNonNull(clazz);
         return readArrayListInternal(loader, clazz);
     }
@@ -3724,6 +3914,7 @@
     @Deprecated
     @Nullable
     public Object[] readArray(@Nullable ClassLoader loader) {
+        assertNotRecycled();
         return readArrayInternal(loader, /* clazz */ null);
     }
 
@@ -3745,6 +3936,7 @@
     @SuppressLint({"ArrayReturn", "NullableCollection"})
     @Nullable
     public <T> T[] readArray(@Nullable ClassLoader loader, @NonNull Class<T> clazz) {
+        assertNotRecycled();
         Objects.requireNonNull(clazz);
         return readArrayInternal(loader, clazz);
     }
@@ -3764,6 +3956,7 @@
     @Deprecated
     @Nullable
     public <T> SparseArray<T> readSparseArray(@Nullable ClassLoader loader) {
+        assertNotRecycled();
         return readSparseArrayInternal(loader, /* clazz */ null);
     }
 
@@ -3785,6 +3978,7 @@
     @Nullable
     public <T> SparseArray<T> readSparseArray(@Nullable ClassLoader loader,
             @NonNull Class<? extends T> clazz) {
+        assertNotRecycled();
         Objects.requireNonNull(clazz);
         return readSparseArrayInternal(loader, clazz);
     }
@@ -3796,6 +3990,7 @@
      */
     @Nullable
     public final SparseBooleanArray readSparseBooleanArray() {
+        assertNotRecycled();
         int N = readInt();
         if (N < 0) {
             return null;
@@ -3812,6 +4007,7 @@
      */
     @Nullable
     public final SparseIntArray readSparseIntArray() {
+        assertNotRecycled();
         int N = readInt();
         if (N < 0) {
             return null;
@@ -3836,6 +4032,7 @@
      */
     @Nullable
     public final <T> ArrayList<T> createTypedArrayList(@NonNull Parcelable.Creator<T> c) {
+        assertNotRecycled();
         int N = readInt();
         if (N < 0) {
             return null;
@@ -3859,6 +4056,7 @@
      * @see #writeTypedList
      */
     public final <T> void readTypedList(@NonNull List<T> list, @NonNull Parcelable.Creator<T> c) {
+        assertNotRecycled();
         int M = list.size();
         int N = readInt();
         int i = 0;
@@ -3888,6 +4086,7 @@
      */
     public final @Nullable <T extends Parcelable> SparseArray<T> createTypedSparseArray(
             @NonNull Parcelable.Creator<T> creator) {
+        assertNotRecycled();
         final int count = readInt();
         if (count < 0) {
             return null;
@@ -3917,6 +4116,7 @@
      */
     public final @Nullable <T extends Parcelable> ArrayMap<String, T> createTypedArrayMap(
             @NonNull Parcelable.Creator<T> creator) {
+        assertNotRecycled();
         final int count = readInt();
         if (count < 0) {
             return null;
@@ -3944,6 +4144,7 @@
      */
     @Nullable
     public final ArrayList<String> createStringArrayList() {
+        assertNotRecycled();
         int N = readInt();
         if (N < 0) {
             return null;
@@ -3970,6 +4171,7 @@
      */
     @Nullable
     public final ArrayList<IBinder> createBinderArrayList() {
+        assertNotRecycled();
         int N = readInt();
         if (N < 0) {
             return null;
@@ -3997,6 +4199,7 @@
     @Nullable
     public final <T extends IInterface> ArrayList<T> createInterfaceArrayList(
             @NonNull Function<IBinder, T> asInterface) {
+        assertNotRecycled();
         int N = readInt();
         if (N < 0) {
             return null;
@@ -4017,6 +4220,7 @@
      * @see #writeStringList
      */
     public final void readStringList(@NonNull List<String> list) {
+        assertNotRecycled();
         int M = list.size();
         int N = readInt();
         int i = 0;
@@ -4038,6 +4242,7 @@
      * @see #writeBinderList
      */
     public final void readBinderList(@NonNull List<IBinder> list) {
+        assertNotRecycled();
         int M = list.size();
         int N = readInt();
         int i = 0;
@@ -4060,6 +4265,7 @@
      */
     public final <T extends IInterface> void readInterfaceList(@NonNull List<T> list,
             @NonNull Function<IBinder, T> asInterface) {
+        assertNotRecycled();
         int M = list.size();
         int N = readInt();
         int i = 0;
@@ -4091,6 +4297,7 @@
     @NonNull
     public final <T extends Parcelable> List<T> readParcelableList(@NonNull List<T> list,
             @Nullable ClassLoader cl) {
+        assertNotRecycled();
         return readParcelableListInternal(list, cl, /*clazz*/ null);
     }
 
@@ -4112,6 +4319,7 @@
     @NonNull
     public <T> List<T> readParcelableList(@NonNull List<T> list,
             @Nullable ClassLoader cl, @NonNull Class<? extends T> clazz) {
+        assertNotRecycled();
         Objects.requireNonNull(list);
         Objects.requireNonNull(clazz);
         return readParcelableListInternal(list, cl, clazz);
@@ -4157,6 +4365,7 @@
      */
     @Nullable
     public final <T> T[] createTypedArray(@NonNull Parcelable.Creator<T> c) {
+        assertNotRecycled();
         int N = readInt();
         if (N < 0) {
             return null;
@@ -4170,6 +4379,7 @@
     }
 
     public final <T> void readTypedArray(@NonNull T[] val, @NonNull Parcelable.Creator<T> c) {
+        assertNotRecycled();
         int N = readInt();
         if (N == val.length) {
             for (int i=0; i<N; i++) {
@@ -4186,6 +4396,7 @@
      */
     @Deprecated
     public final <T> T[] readTypedArray(Parcelable.Creator<T> c) {
+        assertNotRecycled();
         return createTypedArray(c);
     }
 
@@ -4202,6 +4413,7 @@
      */
     @Nullable
     public final <T> T readTypedObject(@NonNull Parcelable.Creator<T> c) {
+        assertNotRecycled();
         if (readInt() != 0) {
             return c.createFromParcel(this);
         } else {
@@ -4228,6 +4440,7 @@
      * @see #readTypedArray
      */
     public <T> void readFixedArray(@NonNull T val) {
+        assertNotRecycled();
         Class<?> componentType = val.getClass().getComponentType();
         if (componentType == boolean.class) {
             readBooleanArray((boolean[]) val);
@@ -4268,6 +4481,7 @@
      */
     public <T, S extends IInterface> void readFixedArray(@NonNull T val,
             @NonNull Function<IBinder, S> asInterface) {
+        assertNotRecycled();
         Class<?> componentType = val.getClass().getComponentType();
         if (IInterface.class.isAssignableFrom(componentType)) {
             readInterfaceArray((S[]) val, asInterface);
@@ -4294,6 +4508,7 @@
      */
     public <T, S extends Parcelable> void readFixedArray(@NonNull T val,
             @NonNull Parcelable.Creator<S> c) {
+        assertNotRecycled();
         Class<?> componentType = val.getClass().getComponentType();
         if (Parcelable.class.isAssignableFrom(componentType)) {
             readTypedArray((S[]) val, c);
@@ -4351,6 +4566,7 @@
      */
     @Nullable
     public <T> T createFixedArray(@NonNull Class<T> cls, @NonNull int... dimensions) {
+        assertNotRecycled();
         // Check if type matches with dimensions
         // If type is one-dimensional array, delegate to other creators
         // Otherwise, create an multi-dimensional array at once and then fill it with readFixedArray
@@ -4424,6 +4640,7 @@
     @Nullable
     public <T, S extends IInterface> T createFixedArray(@NonNull Class<T> cls,
             @NonNull Function<IBinder, S> asInterface, @NonNull int... dimensions) {
+        assertNotRecycled();
         // Check if type matches with dimensions
         // If type is one-dimensional array, delegate to other creators
         // Otherwise, create an multi-dimensional array at once and then fill it with readFixedArray
@@ -4484,6 +4701,7 @@
     @Nullable
     public <T, S extends Parcelable> T createFixedArray(@NonNull Class<T> cls,
             @NonNull Parcelable.Creator<S> c, @NonNull int... dimensions) {
+        assertNotRecycled();
         // Check if type matches with dimensions
         // If type is one-dimensional array, delegate to other creators
         // Otherwise, create an multi-dimensional array at once and then fill it with readFixedArray
@@ -4547,6 +4765,7 @@
      */
     public final <T extends Parcelable> void writeParcelableArray(@Nullable T[] value,
             int parcelableFlags) {
+        assertNotRecycled();
         if (value != null) {
             int N = value.length;
             writeInt(N);
@@ -4565,6 +4784,7 @@
      */
     @Nullable
     public final Object readValue(@Nullable ClassLoader loader) {
+        assertNotRecycled();
         return readValue(loader, /* clazz */ null);
     }
 
@@ -4620,6 +4840,7 @@
      */
     @Nullable
     public Object readLazyValue(@Nullable ClassLoader loader) {
+        assertNotRecycled();
         int start = dataPosition();
         int type = readInt();
         if (isLengthPrefixed(type)) {
@@ -5022,6 +5243,7 @@
     @Deprecated
     @Nullable
     public final <T extends Parcelable> T readParcelable(@Nullable ClassLoader loader) {
+        assertNotRecycled();
         return readParcelableInternal(loader, /* clazz */ null);
     }
 
@@ -5041,6 +5263,7 @@
      */
     @Nullable
     public <T> T readParcelable(@Nullable ClassLoader loader, @NonNull Class<T> clazz) {
+        assertNotRecycled();
         Objects.requireNonNull(clazz);
         return readParcelableInternal(loader, clazz);
     }
@@ -5069,6 +5292,7 @@
     @Nullable
     public final <T extends Parcelable> T readCreator(@NonNull Parcelable.Creator<?> creator,
             @Nullable ClassLoader loader) {
+        assertNotRecycled();
         if (creator instanceof Parcelable.ClassLoaderCreator<?>) {
           Parcelable.ClassLoaderCreator<?> classLoaderCreator =
               (Parcelable.ClassLoaderCreator<?>) creator;
@@ -5096,6 +5320,7 @@
     @Deprecated
     @Nullable
     public final Parcelable.Creator<?> readParcelableCreator(@Nullable ClassLoader loader) {
+        assertNotRecycled();
         return readParcelableCreatorInternal(loader, /* clazz */ null);
     }
 
@@ -5116,6 +5341,7 @@
     @Nullable
     public <T> Parcelable.Creator<T> readParcelableCreator(
             @Nullable ClassLoader loader, @NonNull Class<T> clazz) {
+        assertNotRecycled();
         Objects.requireNonNull(clazz);
         return readParcelableCreatorInternal(loader, clazz);
     }
@@ -5238,6 +5464,7 @@
     @Deprecated
     @Nullable
     public Parcelable[] readParcelableArray(@Nullable ClassLoader loader) {
+        assertNotRecycled();
         return readParcelableArrayInternal(loader, /* clazz */ null);
     }
 
@@ -5258,6 +5485,7 @@
     @SuppressLint({"ArrayReturn", "NullableCollection"})
     @Nullable
     public <T> T[] readParcelableArray(@Nullable ClassLoader loader, @NonNull Class<T> clazz) {
+        assertNotRecycled();
         return readParcelableArrayInternal(loader, requireNonNull(clazz));
     }
 
@@ -5291,6 +5519,7 @@
     @Deprecated
     @Nullable
     public Serializable readSerializable() {
+        assertNotRecycled();
         return readSerializableInternal(/* loader */ null, /* clazz */ null);
     }
 
@@ -5307,6 +5536,7 @@
      */
     @Nullable
     public <T> T readSerializable(@Nullable ClassLoader loader, @NonNull Class<T> clazz) {
+        assertNotRecycled();
         Objects.requireNonNull(clazz);
         return readSerializableInternal(
                 loader == null ? getClass().getClassLoader() : loader, clazz);
@@ -5548,6 +5778,7 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public void readArrayMap(@NonNull ArrayMap<? super String, Object> outVal,
             @Nullable ClassLoader loader) {
+        assertNotRecycled();
         final int N = readInt();
         if (N < 0) {
             return;
@@ -5564,6 +5795,7 @@
      */
     @UnsupportedAppUsage
     public @Nullable ArraySet<? extends Object> readArraySet(@Nullable ClassLoader loader) {
+        assertNotRecycled();
         final int size = readInt();
         if (size < 0) {
             return null;
@@ -5703,6 +5935,7 @@
      * @hide For testing
      */
     public long getOpenAshmemSize() {
+        assertNotRecycled();
         return nativeGetOpenAshmemSize(mNativePtr);
     }
 
diff --git a/core/java/android/os/SELinux.java b/core/java/android/os/SELinux.java
index f64a811..11c54ef 100644
--- a/core/java/android/os/SELinux.java
+++ b/core/java/android/os/SELinux.java
@@ -193,4 +193,31 @@
             return false;
         }
     }
+
+    /**
+     * Gets the genfs labels version of the vendor. The genfs labels version is
+     * specified in {@code /vendor/etc/selinux/genfs_labels_version.txt}. The
+     * version follows the VINTF version format "YYYYMM" and affects how {@code
+     * genfs_contexts} entries are applied.
+     *
+     * <p>The genfs labels version indicates changes in the SELinux labeling
+     * scheme over time. For example:
+     * <ul>
+     *   <li>For version 202504 and later, {@code /sys/class/udc} is labeled as
+     *   {@code sysfs_udc}.
+     *   <li>For version 202404 and earlier, {@code /sys/class/udc} is labeled
+     *   as {@code sysfs}.
+     * </ul>
+     * Check {@code /system/etc/selinux/plat_sepolicy_genfs_{version}.cil} to
+     * see which labels are new in {version}.
+     *
+     * <p>Older vendors may override {@code genfs_contexts} with vendor-specific
+     * extensions. The framework must not break such labellings to maintain
+     * compatibility with such vendors, by checking the genfs labels version and
+     * implementing a fallback mechanism.
+     *
+     * @return an integer representing the genfs labels version of /vendor, in
+     *         the format YYYYMM.
+     */
+    public static final native int getGenfsLabelsVersion();
 }
diff --git a/core/java/android/os/UpdateEngine.java b/core/java/android/os/UpdateEngine.java
index 0a8f62f..81e4549 100644
--- a/core/java/android/os/UpdateEngine.java
+++ b/core/java/android/os/UpdateEngine.java
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
@@ -667,4 +668,23 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Run postinstall script for specified partition |partition|
+     *
+     * @param partition The partition to trigger postinstall runs
+     *
+     * @throws ServiceSpecificException error code of this exception would be one of
+     * https://cs.android.com/android/platform/superproject/main/+/main:system/update_engine/common/error_code.h
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_UPDATE_ENGINE_API)
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public void triggerPostinstall(@NonNull String partition) {
+        try {
+            mUpdateEngine.triggerPostinstall(partition);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig
index c2b8157..57e1b58 100644
--- a/core/java/android/permission/flags.aconfig
+++ b/core/java/android/permission/flags.aconfig
@@ -474,3 +474,12 @@
     description: "Enable cross-user roles platform API"
     bug: "367732307"
 }
+
+flag {
+    name: "rate_limit_batched_note_op_async_callbacks_enabled"
+    is_fixed_read_only: true
+    is_exported: true
+    namespace: "permissions"
+    description: "Rate limit async noteOp callbacks for batched noteOperation binder call"
+    bug: "366013082"
+}
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index 269839b..2d922b4 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -15,9 +15,12 @@
  */
 package android.service.autofill;
 
+import static android.service.autofill.Flags.FLAG_AUTOFILL_SESSION_DESTROYED;
+
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
 
 import android.annotation.CallSuper;
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
@@ -669,6 +672,14 @@
                     AutofillService.this,
                     new SavedDatasetsInfoCallbackImpl(receiver, SavedDatasetsInfo.TYPE_PASSWORDS)));
         }
+
+        @Override
+        public void onSessionDestroyed(@Nullable FillEventHistory history) {
+            mHandler.sendMessage(obtainMessage(
+                    AutofillService::onSessionDestroyed,
+                    AutofillService.this,
+                    history));
+        }
     };
 
     private Handler mHandler;
@@ -783,26 +794,42 @@
     }
 
     /**
-     * Gets the events that happened after the last
-     * {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)}
+     * Called when an Autofill context has ended and the Autofill session is finished. This will be
+     * called as the last step of the Autofill lifecycle described in {@link AutofillManager}.
+     *
+     * <p>This will also contain the finished Session's FillEventHistory, so providers do not need
+     * to explicitly call {@link #getFillEventHistory()}
+     *
+     * <p>This will usually happens whenever {@link AutofillManager#commit()} or {@link
+     * AutofillManager#cancel()} is called.
+     */
+    @FlaggedApi(FLAG_AUTOFILL_SESSION_DESTROYED)
+    public void onSessionDestroyed(@Nullable FillEventHistory history) {}
+
+    /**
+     * Gets the events that happened after the last {@link
+     * AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)}
      * call.
      *
      * <p>This method is typically used to keep track of previous user actions to optimize further
      * requests. For example, the service might return email addresses in alphabetical order by
      * default, but change that order based on the address the user picked on previous requests.
      *
-     * <p>The history is not persisted over reboots, and it's cleared every time the service
-     * replies to a {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)} by calling
-     * {@link FillCallback#onSuccess(FillResponse)} or {@link FillCallback#onFailure(CharSequence)}
-     * (if the service doesn't call any of these methods, the history will clear out after some
-     * pre-defined time). Hence, the service should call {@link #getFillEventHistory()} before
-     * finishing the {@link FillCallback}.
+     * <p>The history is not persisted over reboots, and it's cleared every time the service replies
+     * to a {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)} by calling {@link
+     * FillCallback#onSuccess(FillResponse)} or {@link FillCallback#onFailure(CharSequence)} (if the
+     * service doesn't call any of these methods, the history will clear out after some pre-defined
+     * time). Hence, the service should call {@link #getFillEventHistory()} before finishing the
+     * {@link FillCallback}.
      *
      * @return The history or {@code null} if there are no events.
-     *
      * @throws RuntimeException if the event history could not be retrieved.
+     * @deprecated Use {@link #onSessionDestroyed(FillEventHistory) instead}
      */
-    @Nullable public final FillEventHistory getFillEventHistory() {
+    @FlaggedApi(FLAG_AUTOFILL_SESSION_DESTROYED)
+    @Deprecated
+    @Nullable
+    public final FillEventHistory getFillEventHistory() {
         final AutofillManager afm = getSystemService(AutofillManager.class);
 
         if (afm == null) {
diff --git a/core/java/android/service/autofill/IAutoFillService.aidl b/core/java/android/service/autofill/IAutoFillService.aidl
index 3b64b8a..71b75e7 100644
--- a/core/java/android/service/autofill/IAutoFillService.aidl
+++ b/core/java/android/service/autofill/IAutoFillService.aidl
@@ -25,6 +25,8 @@
 import android.service.autofill.SaveRequest;
 import com.android.internal.os.IResultReceiver;
 
+parcelable FillEventHistory;
+
 /**
  * Interface from the system to an auto fill service.
  *
@@ -38,4 +40,5 @@
     void onSaveRequest(in SaveRequest request, in ISaveCallback callback);
     void onSavedPasswordCountRequest(in IResultReceiver receiver);
     void onConvertCredentialRequest(in ConvertCredentialRequest convertCredentialRequest, in IConvertCredentialCallback convertCredentialCallback);
+    void onSessionDestroyed(in FillEventHistory history);
 }
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
index bb233d2..3ff5f95 100644
--- a/core/java/android/view/DisplayEventReceiver.java
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -286,7 +286,7 @@
      * @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()}
      * timebase.
      * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair.
-     * @param modeId The new mode Id
+     * @param modeId The new mode ID
      * @param renderPeriod The render frame period, which is a multiple of the mode's vsync period
      */
     public void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId,
@@ -294,6 +294,15 @@
     }
 
     /**
+     * Called when a display mode rejection event is received.
+     *
+     * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair.
+     * @param modeId The mode ID of the mode that was rejected
+     */
+    public void onModeRejected(long physicalDisplayId, int modeId) {
+    }
+
+    /**
      * Called when a display hdcp levels change event is received.
      *
      * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair.
@@ -386,6 +395,12 @@
 
     // Called from native code.
     @SuppressWarnings("unused")
+    private void dispatchModeRejected(long physicalDisplayId, int modeId) {
+        onModeRejected(physicalDisplayId, modeId);
+    }
+
+    // Called from native code.
+    @SuppressWarnings("unused")
     private void dispatchFrameRateOverrides(long timestampNanos, long physicalDisplayId,
             FrameRateOverride[] overrides) {
         onFrameRateOverridesChanged(timestampNanos, physicalDisplayId, overrides);
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 03f9d98..6e6e87b 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -205,7 +205,8 @@
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = {"FRAME_RATE_COMPATIBILITY_"},
-            value = {FRAME_RATE_COMPATIBILITY_DEFAULT, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE})
+            value = {FRAME_RATE_COMPATIBILITY_DEFAULT, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
+                    FRAME_RATE_COMPATIBILITY_GTE})
     public @interface FrameRateCompatibility {}
 
     // From native_window.h. Keep these in sync.
@@ -214,6 +215,11 @@
      * system selects a frame rate other than what the app requested, the app will be able
      * to run at the system frame rate without requiring pull down. This value should be
      * used when displaying game content, UIs, and anything that isn't video.
+     *
+     * In Android version {@link Build.VERSION_CODES#BAKLAVA} and above, use
+     * {@link FRAME_RATE_COMPATIBILITY_DEFAULT} for game content.
+     * For other cases, see {@link FRAME_RATE_COMPATIBILITY_FIXED_SOURCE} and
+     * {@link FRAME_RATE_COMPATIBILITY_GTE}.
      */
     public static final int FRAME_RATE_COMPATIBILITY_DEFAULT = 0;
 
@@ -228,6 +234,17 @@
     public static final int FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1;
 
     /**
+     * The surface requests a frame rate that is greater than or equal to the specified frame rate.
+     * This value should be used for UIs, animations, scrolling and fling, and anything that is not
+     * a game or video.
+     *
+     * For video, use {@link FRAME_RATE_COMPATIBILITY_FIXED_SOURCE} instead. For game content, use
+     * {@link FRAME_RATE_COMPATIBILITY_DEFAULT}.
+     */
+    @FlaggedApi(com.android.graphics.surfaceflinger.flags.Flags.FLAG_ARR_SETFRAMERATE_GTE_ENUM)
+    public static final int FRAME_RATE_COMPATIBILITY_GTE = 2;
+
+    /**
      * This surface belongs to an app on the High Refresh Rate Deny list, and needs the display
      * to operate at the exact frame rate.
      *
@@ -250,13 +267,6 @@
      */
     public static final int FRAME_RATE_COMPATIBILITY_MIN = 102;
 
-    // From window.h. Keep these in sync.
-    /**
-     * The surface requests a frame rate that is greater than or equal to {@code frameRate}.
-     * @hide
-     */
-    public static final int FRAME_RATE_COMPATIBILITY_GTE = 103;
-
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = {"CHANGE_FRAME_RATE_"},
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 3133020..e9c2cf8 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -18,7 +18,6 @@
 
 import static android.adpf.Flags.adpfViewrootimplActionDownBoost;
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.content.pm.ActivityInfo.OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS;
 import static android.graphics.HardwareRenderer.SYNC_CONTEXT_IS_STOPPED;
 import static android.graphics.HardwareRenderer.SYNC_LOST_SURFACE_REWARD_IF_FOUND;
@@ -2653,8 +2652,7 @@
             mStopped = stopped;
             final ThreadedRenderer renderer = mAttachInfo.mThreadedRenderer;
             if (renderer != null) {
-                if (DEBUG_DRAW)
-                    Log.d(mTag, "WindowStopped on " + getTitle() + " set to " + mStopped);
+                if (DEBUG_DRAW) Log.d(mTag, "WindowStopped on " + getTitle() + " set to " + mStopped);
                 renderer.setStopped(mStopped);
             }
             if (!mStopped) {
@@ -7979,9 +7977,8 @@
         }
 
         private boolean moveFocusToAdjacentWindow(@FocusDirection int direction) {
-            final int windowingMode = getConfiguration().windowConfiguration.getWindowingMode();
-            if (!(windowingMode == WINDOWING_MODE_MULTI_WINDOW
-                    || windowingMode == WINDOWING_MODE_FREEFORM)) {
+            if (getConfiguration().windowConfiguration.getWindowingMode()
+                    != WINDOWING_MODE_MULTI_WINDOW) {
                 return false;
             }
             try {
diff --git a/core/java/android/view/flags/view_flags.aconfig b/core/java/android/view/flags/view_flags.aconfig
index 641b010..f6fdec9 100644
--- a/core/java/android/view/flags/view_flags.aconfig
+++ b/core/java/android/view/flags/view_flags.aconfig
@@ -142,4 +142,12 @@
     description: "Recover from buffer stuffing when SurfaceFlinger misses a frame"
     bug: "294922229"
     is_fixed_read_only: true
-}
\ No newline at end of file
+}
+
+flag {
+    name: "date_time_view_relative_time_display_configs"
+    namespace: "systemui"
+    description: "Enables DateTimeView to use additional display configurations for relative time"
+    bug: "364653005"
+    is_fixed_read_only: true
+}
diff --git a/core/java/android/widget/DateTimeView.java b/core/java/android/widget/DateTimeView.java
index 41ff69d..143b4b7 100644
--- a/core/java/android/widget/DateTimeView.java
+++ b/core/java/android/widget/DateTimeView.java
@@ -21,6 +21,7 @@
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
 import static android.text.format.DateUtils.YEAR_IN_MILLIS;
 
+import android.annotation.IntDef;
 import android.app.ActivityThread;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
@@ -41,6 +42,8 @@
 
 import com.android.internal.R;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.text.DateFormat;
 import java.time.Instant;
 import java.time.LocalDate;
@@ -70,6 +73,23 @@
     private static final int SHOW_TIME = 0;
     private static final int SHOW_MONTH_DAY_YEAR = 1;
 
+    /** @hide */
+    @IntDef(value = {UNIT_DISPLAY_LENGTH_SHORTEST, UNIT_DISPLAY_LENGTH_MEDIUM})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface UnitDisplayLength {}
+    public static final int UNIT_DISPLAY_LENGTH_SHORTEST = 0;
+    public static final int UNIT_DISPLAY_LENGTH_MEDIUM = 1;
+
+    /** @hide */
+    @IntDef(flag = true, value = {DISAMBIGUATION_TEXT_PAST, DISAMBIGUATION_TEXT_FUTURE})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DisambiguationTextMask {}
+    public static final int DISAMBIGUATION_TEXT_PAST = 0x01;
+    public static final int DISAMBIGUATION_TEXT_FUTURE = 0x02;
+
+    private final boolean mCanUseRelativeTimeDisplayConfigs =
+            android.view.flags.Flags.dateTimeViewRelativeTimeDisplayConfigs();
+
     private long mTimeMillis;
     // The LocalDateTime equivalent of mTimeMillis but truncated to minute, i.e. no seconds / nanos.
     private LocalDateTime mLocalTime;
@@ -81,6 +101,8 @@
     private static final ThreadLocal<ReceiverInfo> sReceiverInfo = new ThreadLocal<ReceiverInfo>();
     private String mNowText;
     private boolean mShowRelativeTime;
+    private int mRelativeTimeDisambiguationTextMask;
+    private int mRelativeTimeUnitDisplayLength = UNIT_DISPLAY_LENGTH_SHORTEST;
 
     public DateTimeView(Context context) {
         this(context, null);
@@ -89,20 +111,23 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public DateTimeView(Context context, AttributeSet attrs) {
         super(context, attrs);
-        final TypedArray a = context.obtainStyledAttributes(attrs,
-                com.android.internal.R.styleable.DateTimeView, 0,
-                0);
+        final TypedArray a = context.obtainStyledAttributes(
+                attrs, R.styleable.DateTimeView, 0, 0);
 
-        final int N = a.getIndexCount();
-        for (int i = 0; i < N; i++) {
-            int attr = a.getIndex(i);
-            switch (attr) {
-                case R.styleable.DateTimeView_showRelative:
-                    boolean relative = a.getBoolean(i, false);
-                    setShowRelativeTime(relative);
-                    break;
-            }
+        setShowRelativeTime(a.getBoolean(R.styleable.DateTimeView_showRelative, false));
+        if (mCanUseRelativeTimeDisplayConfigs) {
+            setRelativeTimeDisambiguationTextMask(
+                    a.getInt(
+                            R.styleable.DateTimeView_relativeTimeDisambiguationText,
+                            // The original implementation showed disambiguation text for future
+                            // times only, so continue with that default.
+                            DISAMBIGUATION_TEXT_FUTURE));
+            setRelativeTimeUnitDisplayLength(
+                    a.getInt(
+                            R.styleable.DateTimeView_relativeTimeUnitDisplayLength,
+                            UNIT_DISPLAY_LENGTH_SHORTEST));
         }
+
         a.recycle();
     }
 
@@ -150,6 +175,29 @@
         update();
     }
 
+    /** See {@link R.styleable.DateTimeView_relativeTimeDisambiguationText}. */
+    @android.view.RemotableViewMethod
+    public void setRelativeTimeDisambiguationTextMask(
+            @DisambiguationTextMask int disambiguationTextMask) {
+        if (!mCanUseRelativeTimeDisplayConfigs) {
+            return;
+        }
+        mRelativeTimeDisambiguationTextMask = disambiguationTextMask;
+        updateNowText();
+        update();
+    }
+
+    /** See {@link R.styleable.DateTimeView_relativeTimeUnitDisplayLength}. */
+    @android.view.RemotableViewMethod
+    public void setRelativeTimeUnitDisplayLength(@UnitDisplayLength int unitDisplayLength) {
+        if (!mCanUseRelativeTimeDisplayConfigs) {
+            return;
+        }
+        mRelativeTimeUnitDisplayLength = unitDisplayLength;
+        updateNowText();
+        update();
+    }
+
     /**
      * Returns whether this view shows relative time
      *
@@ -264,17 +312,11 @@
             return;
         } else if (duration < HOUR_IN_MILLIS) {
             count = (int)(duration / MINUTE_IN_MILLIS);
-            result = getContext().getResources().getString(past
-                    ? com.android.internal.R.string.duration_minutes_shortest
-                    : com.android.internal.R.string.duration_minutes_shortest_future,
-                    count);
+            result = getContext().getResources().getString(getMinutesStringId(past), count);
             millisIncrease = MINUTE_IN_MILLIS;
         } else if (duration < DAY_IN_MILLIS) {
             count = (int)(duration / HOUR_IN_MILLIS);
-            result = getContext().getResources().getString(past
-                            ? com.android.internal.R.string.duration_hours_shortest
-                            : com.android.internal.R.string.duration_hours_shortest_future,
-                            count);
+            result = getContext().getResources().getString(getHoursStringId(past), count);
             millisIncrease = HOUR_IN_MILLIS;
         } else if (duration < YEAR_IN_MILLIS) {
             // In weird cases it can become 0 because of daylight savings
@@ -283,10 +325,7 @@
             LocalDateTime localNow = toLocalDateTime(now, zoneId);
 
             count = Math.max(Math.abs(dayDistance(localDateTime, localNow)), 1);
-            result = getContext().getResources().getString(past
-                    ? com.android.internal.R.string.duration_days_shortest
-                    : com.android.internal.R.string.duration_days_shortest_future,
-                    count);
+            result = getContext().getResources().getString(getDaysStringId(past), count);
             if (past || count != 1) {
                 mUpdateTimeMillis = computeNextMidnight(localNow, zoneId);
                 millisIncrease = -1;
@@ -296,10 +335,7 @@
 
         } else {
             count = (int)(duration / YEAR_IN_MILLIS);
-            result = getContext().getResources().getString(past
-                    ? com.android.internal.R.string.duration_years_shortest
-                    : com.android.internal.R.string.duration_years_shortest_future,
-                    count);
+            result = getContext().getResources().getString(getYearsStringId(past), count);
             millisIncrease = YEAR_IN_MILLIS;
         }
         if (millisIncrease != -1) {
@@ -312,6 +348,139 @@
         maybeSetText(result);
     }
 
+    private int getMinutesStringId(boolean past) {
+        if (!mCanUseRelativeTimeDisplayConfigs) {
+            return past
+                    ? com.android.internal.R.string.duration_minutes_shortest
+                    : com.android.internal.R.string.duration_minutes_shortest_future;
+        }
+
+        if (mRelativeTimeUnitDisplayLength == UNIT_DISPLAY_LENGTH_SHORTEST) {
+            if (past && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_PAST) != 0) {
+                // "1m ago"
+                return com.android.internal.R.string.duration_minutes_shortest_past;
+            } else if (!past
+                    && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_FUTURE) != 0) {
+                // "in 1m"
+                return com.android.internal.R.string.duration_minutes_shortest_future;
+            } else {
+                // "1m"
+                return com.android.internal.R.string.duration_minutes_shortest;
+            }
+        } else { // UNIT_DISPLAY_LENGTH_MEDIUM
+            if (past && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_PAST) != 0) {
+                // "1min ago"
+                return com.android.internal.R.string.duration_minutes_medium_past;
+            } else if (!past
+                    && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_FUTURE) != 0) {
+                // "in 1min"
+                return com.android.internal.R.string.duration_minutes_medium_future;
+            } else {
+                // "1min"
+                return com.android.internal.R.string.duration_minutes_medium;
+            }
+        }
+    }
+
+    private int getHoursStringId(boolean past) {
+        if (!mCanUseRelativeTimeDisplayConfigs) {
+            return past
+                    ? com.android.internal.R.string.duration_hours_shortest
+                    : com.android.internal.R.string.duration_hours_shortest_future;
+        }
+        if (mRelativeTimeUnitDisplayLength == UNIT_DISPLAY_LENGTH_SHORTEST) {
+            if (past && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_PAST) != 0) {
+                // "1h ago"
+                return com.android.internal.R.string.duration_hours_shortest_past;
+            } else if (!past
+                    && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_FUTURE) != 0) {
+                // "in 1h"
+                return com.android.internal.R.string.duration_hours_shortest_future;
+            } else {
+                // "1h"
+                return com.android.internal.R.string.duration_hours_shortest;
+            }
+        } else { // UNIT_DISPLAY_LENGTH_MEDIUM
+            if (past && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_PAST) != 0) {
+                // "1hr ago"
+                return com.android.internal.R.string.duration_hours_medium_past;
+            } else if (!past
+                    && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_FUTURE) != 0) {
+                // "in 1hr"
+                return com.android.internal.R.string.duration_hours_medium_future;
+            } else {
+                // "1hr"
+                return com.android.internal.R.string.duration_hours_medium;
+            }
+        }
+    }
+
+    private int getDaysStringId(boolean past) {
+        if (!mCanUseRelativeTimeDisplayConfigs) {
+            return past
+                    ? com.android.internal.R.string.duration_days_shortest
+                    : com.android.internal.R.string.duration_days_shortest_future;
+        }
+        if (mRelativeTimeUnitDisplayLength == UNIT_DISPLAY_LENGTH_SHORTEST) {
+            if (past && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_PAST) != 0) {
+                // "1d ago"
+                return com.android.internal.R.string.duration_days_shortest_past;
+            } else if (!past
+                    && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_FUTURE) != 0) {
+                // "in 1d"
+                return com.android.internal.R.string.duration_days_shortest_future;
+            } else {
+                // "1d"
+                return com.android.internal.R.string.duration_days_shortest;
+            }
+        } else { // UNIT_DISPLAY_LENGTH_MEDIUM
+            if (past && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_PAST) != 0) {
+                // "1d ago"
+                return com.android.internal.R.string.duration_days_medium_past;
+            } else if (!past
+                    && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_FUTURE) != 0) {
+                // "in 1d"
+                return com.android.internal.R.string.duration_days_medium_future;
+            } else {
+                // "1d"
+                return com.android.internal.R.string.duration_days_medium;
+            }
+        }
+    }
+
+    private int getYearsStringId(boolean past) {
+        if (!mCanUseRelativeTimeDisplayConfigs) {
+            return past
+                    ? com.android.internal.R.string.duration_years_shortest
+                    : com.android.internal.R.string.duration_years_shortest_future;
+        }
+        if (mRelativeTimeUnitDisplayLength == UNIT_DISPLAY_LENGTH_SHORTEST) {
+            if (past && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_PAST) != 0) {
+                // "1y ago"
+                return com.android.internal.R.string.duration_years_shortest_past;
+            } else if (!past
+                    && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_FUTURE) != 0) {
+                // "in 1y"
+                return com.android.internal.R.string.duration_years_shortest_future;
+            } else {
+                // "1y"
+                return com.android.internal.R.string.duration_years_shortest;
+            }
+        } else { // UNIT_DISPLAY_LENGTH_MEDIUM
+            if (past && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_PAST) != 0) {
+                // "1y ago"
+                return com.android.internal.R.string.duration_years_medium_past;
+            } else if (!past
+                    && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_FUTURE) != 0) {
+                // "in 1y"
+                return com.android.internal.R.string.duration_years_medium_future;
+            } else {
+                // "1y"
+                return com.android.internal.R.string.duration_years_medium;
+            }
+        }
+    }
+
     /**
      * Sets text only if the text has actually changed. This prevents needles relayouts of this
      * view when set to wrap_content.
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 7e3b904..2cd3901 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -128,6 +128,7 @@
 import com.android.internal.util.Preconditions;
 import com.android.internal.widget.IRemoteViewsFactory;
 import com.android.internal.widget.remotecompose.core.operations.Theme;
+import com.android.internal.widget.remotecompose.core.CoreDocument;
 import com.android.internal.widget.remotecompose.player.RemoteComposeDocument;
 import com.android.internal.widget.remotecompose.player.RemoteComposePlayer;
 
@@ -5825,7 +5826,7 @@
                 }
                 try (ByteArrayInputStream is = new ByteArrayInputStream(bytes.get(0))) {
                     player.setDocument(new RemoteComposeDocument(is));
-                    player.addClickListener((viewId, metadata) -> {
+                    player.addIdActionListener((viewId, metadata) -> {
                         mActions.forEach(action -> {
                             if (viewId == action.mViewId
                                     && action instanceof SetOnClickResponse setOnClickResponse) {
@@ -9829,7 +9830,7 @@
          */
         @FlaggedApi(FLAG_DRAW_DATA_PARCEL)
         public static long getSupportedVersion() {
-            return VERSION;
+            return (long) CoreDocument.getDocumentApiLevel();
         }
 
         /**
diff --git a/core/java/android/window/SystemPerformanceHinter.java b/core/java/android/window/SystemPerformanceHinter.java
index cc2329fc..f8899c5 100644
--- a/core/java/android/window/SystemPerformanceHinter.java
+++ b/core/java/android/window/SystemPerformanceHinter.java
@@ -163,7 +163,6 @@
     // The active sessions
     private final ArrayList<HighPerfSession> mActiveSessions = new ArrayList<>();
     private final SurfaceControl.Transaction mTransaction;
-    private final PerformanceHintManager mPerfHintManager;
     private @Nullable PerformanceHintManager.Session mAdpfSession;
     private @Nullable DisplayRootProvider mDisplayRootProvider;
 
@@ -184,7 +183,6 @@
             @Nullable DisplayRootProvider displayRootProvider,
             @Nullable Supplier<SurfaceControl.Transaction> transactionSupplier) {
         mDisplayRootProvider = displayRootProvider;
-        mPerfHintManager = context.getSystemService(PerformanceHintManager.class);
         mTransaction = transactionSupplier != null
                 ? transactionSupplier.get()
                 : new SurfaceControl.Transaction();
@@ -273,7 +271,7 @@
                 asyncTraceBegin(HINT_SF_EARLY_WAKEUP, Display.INVALID_DISPLAY);
             }
         }
-        if (nowEnabled(oldGlobalFlags, newGlobalFlags, HINT_ADPF)) {
+        if (mAdpfSession != null && nowEnabled(oldGlobalFlags, newGlobalFlags, HINT_ADPF)) {
             mAdpfSession.sendHint(PerformanceHintManager.Session.CPU_LOAD_UP);
             if (isTraceEnabled) {
                 asyncTraceBegin(HINT_ADPF, Display.INVALID_DISPLAY);
@@ -323,7 +321,7 @@
                 asyncTraceEnd(HINT_SF_EARLY_WAKEUP);
             }
         }
-        if (nowDisabled(oldGlobalFlags, newGlobalFlags, HINT_ADPF)) {
+        if (mAdpfSession != null && nowDisabled(oldGlobalFlags, newGlobalFlags, HINT_ADPF)) {
             mAdpfSession.sendHint(PerformanceHintManager.Session.CPU_LOAD_RESET);
             if (isTraceEnabled) {
                 asyncTraceEnd(HINT_ADPF);
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index 4fb5fa7..5053aa8 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -460,4 +460,18 @@
     namespace: "lse_desktop_experience"
     description: "Enable multiple desktop sessions for desktop windowing."
     bug: "379158791"
+}
+
+flag {
+    name: "enable_connected_displays_dnd"
+    namespace: "lse_desktop_experience"
+    description: "Enable drag-and-drop between connected displays."
+    bug: "381793841"
+}
+
+flag {
+    name: "enable_connected_displays_window_drag"
+    namespace: "lse_desktop_experience"
+    description: "Enable window drag between connected displays."
+    bug: "381172172"
 }
\ No newline at end of file
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index 0b034b6..30f0c73 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -453,3 +453,11 @@
     is_fixed_read_only: true
     bug: "376407910"
 }
+
+flag {
+  name: "relative_insets"
+  namespace: "windowing_frontend"
+  description: "Support insets definition and calculation relative to task bounds."
+  bug: "277292497"
+  is_fixed_read_only: true
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
index e2be1f5..a27eeb8 100644
--- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
+++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
@@ -58,7 +58,6 @@
 import android.view.Window;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.Flags;
 import android.widget.Toast;
 
 import com.android.internal.R;
@@ -289,9 +288,7 @@
                     cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, DialogStatus.SHOWN,
                     userId);
         } else {
-            if (Flags.restoreA11yShortcutTargetService()) {
-                enableDefaultHardwareShortcut(userId);
-            }
+            enableDefaultHardwareShortcut(userId);
             playNotificationTone();
             if (mAlertDialog != null) {
                 mAlertDialog.dismiss();
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityServiceWarning.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityServiceWarning.java
index 3557633..2e1a0bf 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityServiceWarning.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityServiceWarning.java
@@ -29,7 +29,6 @@
 import android.view.View;
 import android.view.Window;
 import android.view.WindowManager;
-import android.view.accessibility.Flags;
 import android.widget.Button;
 import android.widget.ImageView;
 import android.widget.TextView;
@@ -65,9 +64,6 @@
         Window window = ad.getWindow();
         WindowManager.LayoutParams params = window.getAttributes();
         params.privateFlags |= SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
-        if (!Flags.warningUseDefaultDialogType()) {
-            params.type = WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
-        }
         window.setAttributes(params);
         return ad;
     }
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 2cfc680..f01aa80 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -163,4 +163,5 @@
     void finishOperationForDevice(IBinder clientId, int code, int uid, String packageName,
             @nullable String attributionTag, int virtualDeviceId);
    List<AppOpsManager.PackageOps> getPackagesForOpsForDevice(in int[] ops, String persistentDeviceId);
+   oneway void noteOperationsInBatch(in Map batchedNoteOps);
 }
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index ee5bd65..644d699 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -70,6 +70,7 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.chooser.TargetInfo;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
@@ -352,6 +353,7 @@
         findViewById(R.id.use_same_profile_browser).setOnClickListener(v -> finish());
 
         findViewById(R.id.button_open).setOnClickListener(v -> {
+            TargetInfo.refreshIntentCreatorToken(launchIntent);
             startActivityAsCaller(
                     launchIntent,
                     ActivityOptions.makeCustomAnimation(
@@ -476,6 +478,7 @@
 
     private void startActivityAsCaller(Intent newIntent, int userId) {
         try {
+            TargetInfo.refreshIntentCreatorToken(newIntent);
             startActivityAsCaller(
                     newIntent,
                     /* options= */ null,
@@ -502,6 +505,7 @@
             return;
         }
         sanitizeIntent(innerIntent);
+        TargetInfo.refreshIntentCreatorToken(intentReceived);
         startActivityAsCaller(intentReceived, null, false, getUserId());
         finish();
     }
@@ -525,6 +529,7 @@
         if (singleTabOnly) {
             intentReceived.putExtra(EXTRA_RESTRICT_TO_SINGLE_USER, true);
         }
+        TargetInfo.refreshIntentCreatorToken(intentReceived);
         startActivityAsCaller(intentReceived, null, false, userId);
         finish();
     }
diff --git a/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java b/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
index 473134e..0c65077 100644
--- a/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
+++ b/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
@@ -173,6 +173,7 @@
     @Override
     public boolean startAsCaller(ResolverActivity activity, Bundle options, int userId) {
         TargetInfo.prepareIntentForCrossProfileLaunch(mResolvedIntent, userId);
+        TargetInfo.refreshIntentCreatorToken(mResolvedIntent);
         activity.startActivityAsCaller(mResolvedIntent, options, false, userId);
         return true;
     }
@@ -180,6 +181,7 @@
     @Override
     public boolean startAsUser(Activity activity, Bundle options, UserHandle user) {
         TargetInfo.prepareIntentForCrossProfileLaunch(mResolvedIntent, user.getIdentifier());
+        TargetInfo.refreshIntentCreatorToken(mResolvedIntent);
         activity.startActivityAsUser(mResolvedIntent, options, user);
         return false;
     }
diff --git a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
index d7f3a76..0eaa43d 100644
--- a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
+++ b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
@@ -260,6 +260,7 @@
         intent.setComponent(mChooserTarget.getComponentName());
         intent.putExtras(mChooserTarget.getIntentExtras());
         TargetInfo.prepareIntentForCrossProfileLaunch(intent, userId);
+        TargetInfo.refreshIntentCreatorToken(intent);
 
         // Important: we will ignore the target security checks in ActivityManager
         // if and only if the ChooserTarget's target package is the same package
diff --git a/core/java/com/android/internal/app/chooser/TargetInfo.java b/core/java/com/android/internal/app/chooser/TargetInfo.java
index 7bb7ddc..fcf5883 100644
--- a/core/java/com/android/internal/app/chooser/TargetInfo.java
+++ b/core/java/com/android/internal/app/chooser/TargetInfo.java
@@ -17,13 +17,17 @@
 package com.android.internal.app.chooser;
 
 
+import static android.security.Flags.preventIntentRedirect;
+
 import android.app.Activity;
+import android.app.ActivityManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ResolveInfo;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
+import android.os.RemoteException;
 import android.os.UserHandle;
 
 import com.android.internal.app.ResolverActivity;
@@ -141,4 +145,20 @@
             intent.fixUris(currentUserId);
         }
     }
+
+    /**
+     * refreshes intent's creatorToken with its current intent key fields. This allows
+     * ChooserActivity to still keep original creatorToken's creator uid after making changes to
+     * the intent and still keep it valid.
+     * @param intent the intent's creatorToken needs to up refreshed.
+     */
+    static void refreshIntentCreatorToken(Intent intent) {
+        if (!preventIntentRedirect()) return;
+        try {
+            intent.setCreatorToken(ActivityManager.getService().refreshIntentCreatorToken(
+                    intent.cloneForCreatorToken()));
+        } catch (RemoteException e) {
+            throw new RuntimeException("Failure from system", e);
+        }
+    }
 }
diff --git a/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java b/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java
index c953d88..445dac7 100644
--- a/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java
+++ b/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java
@@ -25,7 +25,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.res.Flags;
-import android.content.res.XmlResourceParser;
 import android.os.Environment;
 import android.os.Process;
 import android.util.ArrayMap;
@@ -247,20 +246,23 @@
             negated = true;
             featureFlag = featureFlag.substring(1).strip();
         }
-        final Boolean flagValue = getFlagValue(featureFlag);
-        boolean shouldSkip = false;
+        Boolean flagValue = getFlagValue(featureFlag);
+        boolean isUndefined = false;
         if (flagValue == null) {
-            Slog.w(LOG_TAG, "Skipping element " + parser.getName()
-                    + " due to unknown feature flag " + featureFlag);
-            shouldSkip = true;
-        } else if (flagValue == negated) {
+            isUndefined = true;
+            flagValue = false;
+        }
+        boolean shouldSkip = false;
+        if (flagValue == negated) {
             // Skip if flag==false && attr=="flag" OR flag==true && attr=="!flag" (negated)
-            Slog.i(LOG_TAG, "Skipping element " + parser.getName()
-                    + " behind feature flag " + featureFlag + " = " + flagValue);
             shouldSkip = true;
         }
         if (pkg != null && android.content.pm.Flags.includeFeatureFlagsInPackageCacher()) {
-            pkg.addFeatureFlag(featureFlag, flagValue);
+            if (isUndefined) {
+                pkg.addFeatureFlag(featureFlag, null);
+            } else {
+                pkg.addFeatureFlag(featureFlag, flagValue);
+            }
         }
         return shouldSkip;
     }
diff --git a/core/java/com/android/internal/widget/remotecompose/accessibility/AndroidPlatformSemanticNodeApplier.java b/core/java/com/android/internal/widget/remotecompose/accessibility/AndroidPlatformSemanticNodeApplier.java
index 410e021..1bdbaa4 100644
--- a/core/java/com/android/internal/widget/remotecompose/accessibility/AndroidPlatformSemanticNodeApplier.java
+++ b/core/java/com/android/internal/widget/remotecompose/accessibility/AndroidPlatformSemanticNodeApplier.java
@@ -15,157 +15,72 @@
  */
 package com.android.internal.widget.remotecompose.accessibility;
 
-import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.graphics.Rect;
 import android.view.accessibility.AccessibilityNodeInfo;
 
-import com.android.internal.widget.remotecompose.core.operations.layout.Component;
-import com.android.internal.widget.remotecompose.core.semantics.AccessibilitySemantics;
-import com.android.internal.widget.remotecompose.core.semantics.AccessibleComponent;
-import com.android.internal.widget.remotecompose.core.semantics.CoreSemantics;
-
-import java.util.List;
-
 public class AndroidPlatformSemanticNodeApplier
-        implements SemanticNodeApplier<AccessibilityNodeInfo, Component, AccessibilitySemantics> {
+        extends BaseSemanticNodeApplier<AccessibilityNodeInfo> {
 
     private static final String ROLE_DESCRIPTION_KEY = "AccessibilityNodeInfo.roleDescription";
 
     @Override
-    public void applyComponent(
-            @NonNull
-                    RemoteComposeDocumentAccessibility<Component, AccessibilitySemantics>
-                            remoteComposeAccessibility,
-            AccessibilityNodeInfo nodeInfo,
-            Component component,
-            List<AccessibilitySemantics> semantics) {
-        if (component instanceof AccessibleComponent) {
-            applyContentDescription(
-                    ((AccessibleComponent) component).getContentDescriptionId(),
-                    nodeInfo,
-                    remoteComposeAccessibility);
-
-            applyRole(((AccessibleComponent) component).getRole(), nodeInfo);
+    protected void setClickable(AccessibilityNodeInfo nodeInfo, boolean clickable) {
+        nodeInfo.setClickable(clickable);
+        if (clickable) {
+            nodeInfo.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK);
+        } else {
+            nodeInfo.removeAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK);
         }
+    }
 
-        applySemantics(remoteComposeAccessibility, nodeInfo, semantics);
+    @Override
+    protected void setEnabled(AccessibilityNodeInfo nodeInfo, boolean enabled) {
+        nodeInfo.setEnabled(enabled);
+    }
 
-        float[] locationInWindow = new float[2];
-        component.getLocationInWindow(locationInWindow);
-        Rect bounds =
-                new Rect(
-                        (int) locationInWindow[0],
-                        (int) locationInWindow[1],
-                        (int) (locationInWindow[0] + component.getWidth()),
-                        (int) (locationInWindow[1] + component.getHeight()));
-        //noinspection deprecation
+    @Override
+    protected CharSequence getStateDescription(AccessibilityNodeInfo nodeInfo) {
+        return nodeInfo.getStateDescription();
+    }
+
+    @Override
+    protected void setStateDescription(AccessibilityNodeInfo nodeInfo, CharSequence description) {
+        nodeInfo.setStateDescription(description);
+    }
+
+    @Override
+    protected void setRoleDescription(AccessibilityNodeInfo nodeInfo, String description) {
+        nodeInfo.getExtras().putCharSequence(ROLE_DESCRIPTION_KEY, description);
+    }
+
+    @Override
+    protected CharSequence getText(AccessibilityNodeInfo nodeInfo) {
+        return nodeInfo.getText();
+    }
+
+    @Override
+    protected void setText(AccessibilityNodeInfo nodeInfo, CharSequence text) {
+        nodeInfo.setText(text);
+    }
+
+    @Override
+    protected CharSequence getContentDescription(AccessibilityNodeInfo nodeInfo) {
+        return nodeInfo.getContentDescription();
+    }
+
+    @Override
+    protected void setContentDescription(AccessibilityNodeInfo nodeInfo, CharSequence description) {
+        nodeInfo.setContentDescription(description);
+    }
+
+    @Override
+    protected void setBoundsInScreen(AccessibilityNodeInfo nodeInfo, Rect bounds) {
         nodeInfo.setBoundsInParent(bounds);
         nodeInfo.setBoundsInScreen(bounds);
-
-        if (component instanceof AccessibleComponent) {
-            applyContentDescription(
-                    ((AccessibleComponent) component).getContentDescriptionId(),
-                    nodeInfo,
-                    remoteComposeAccessibility);
-
-            applyText(
-                    ((AccessibleComponent) component).getTextId(),
-                    nodeInfo,
-                    remoteComposeAccessibility);
-
-            applyRole(((AccessibleComponent) component).getRole(), nodeInfo);
-        }
-
-        applySemantics(remoteComposeAccessibility, nodeInfo, semantics);
-
-        if (nodeInfo.getText() == null && nodeInfo.getContentDescription() == null) {
-            nodeInfo.setContentDescription("");
-        }
     }
 
-    public void applySemantics(
-            RemoteComposeDocumentAccessibility<Component, AccessibilitySemantics>
-                    remoteComposeAccessibility,
-            AccessibilityNodeInfo nodeInfo,
-            List<AccessibilitySemantics> semantics) {
-        for (AccessibilitySemantics semantic : semantics) {
-            if (semantic.isInterestingForSemantics()) {
-                if (semantic instanceof CoreSemantics) {
-                    applyCoreSemantics(
-                            remoteComposeAccessibility, nodeInfo, (CoreSemantics) semantic);
-                } else if (semantic instanceof AccessibleComponent) {
-                    AccessibleComponent s = (AccessibleComponent) semantic;
-
-                    applyContentDescription(
-                            s.getContentDescriptionId(), nodeInfo, remoteComposeAccessibility);
-
-                    applyRole(s.getRole(), nodeInfo);
-
-                    applyText(s.getTextId(), nodeInfo, remoteComposeAccessibility);
-
-                    if (s.isClickable()) {
-                        nodeInfo.setClickable(true);
-                        nodeInfo.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK);
-                    }
-                }
-            }
-        }
-    }
-
-    private void applyCoreSemantics(
-            RemoteComposeDocumentAccessibility<Component, AccessibilitySemantics>
-                    remoteComposeAccessibility,
-            AccessibilityNodeInfo nodeInfo,
-            CoreSemantics semantics) {
-        applyContentDescription(
-                semantics.getContentDescriptionId(), nodeInfo, remoteComposeAccessibility);
-
-        applyRole(semantics.getRole(), nodeInfo);
-
-        applyText(semantics.getTextId(), nodeInfo, remoteComposeAccessibility);
-
-        applyStateDescription(
-                semantics.getStateDescriptionId(), nodeInfo, remoteComposeAccessibility);
-
-        nodeInfo.setEnabled(semantics.mEnabled);
-    }
-
-    void applyRole(@Nullable AccessibleComponent.Role role, AccessibilityNodeInfo nodeInfo) {
-        if (role != null) {
-            nodeInfo.getExtras().putCharSequence(ROLE_DESCRIPTION_KEY, role.getDescription());
-        }
-    }
-
-    void applyContentDescription(
-            @Nullable Integer contentDescriptionId,
-            AccessibilityNodeInfo nodeInfo,
-            RemoteComposeDocumentAccessibility<Component, AccessibilitySemantics>
-                    remoteComposeAccessibility) {
-        if (contentDescriptionId != null) {
-            nodeInfo.setContentDescription(
-                    remoteComposeAccessibility.stringValue(contentDescriptionId));
-        }
-    }
-
-    void applyText(
-            @Nullable Integer textId,
-            AccessibilityNodeInfo nodeInfo,
-            RemoteComposeDocumentAccessibility<Component, AccessibilitySemantics>
-                    remoteComposeAccessibility) {
-        if (textId != null) {
-            nodeInfo.setText(remoteComposeAccessibility.stringValue(textId));
-        }
-    }
-
-    void applyStateDescription(
-            @Nullable Integer stateDescriptionId,
-            AccessibilityNodeInfo nodeInfo,
-            RemoteComposeDocumentAccessibility<Component, AccessibilitySemantics>
-                    remoteComposeAccessibility) {
-        if (stateDescriptionId != null) {
-            nodeInfo.setStateDescription(
-                    remoteComposeAccessibility.stringValue(stateDescriptionId));
-        }
+    @Override
+    protected void setUniqueId(AccessibilityNodeInfo nodeInfo, String id) {
+        nodeInfo.setUniqueId(id);
     }
 }
diff --git a/core/java/com/android/internal/widget/remotecompose/accessibility/BaseSemanticNodeApplier.java b/core/java/com/android/internal/widget/remotecompose/accessibility/BaseSemanticNodeApplier.java
new file mode 100644
index 0000000..228afb8
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/accessibility/BaseSemanticNodeApplier.java
@@ -0,0 +1,208 @@
+/*
+ * 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.internal.widget.remotecompose.accessibility;
+
+import android.graphics.Rect;
+
+import com.android.internal.widget.remotecompose.core.operations.layout.Component;
+import com.android.internal.widget.remotecompose.core.semantics.AccessibilitySemantics;
+import com.android.internal.widget.remotecompose.core.semantics.AccessibleComponent;
+import com.android.internal.widget.remotecompose.core.semantics.CoreSemantics;
+
+import java.util.List;
+
+/**
+ * Base class for applying semantic information to a node.
+ *
+ * <p>This class provides common functionality for applying semantic information extracted from
+ * Compose UI components to a node representation used for accessibility purposes. It handles
+ * applying properties like content description, text, role, clickability, and bounds.
+ *
+ * <p>Subclasses are responsible for implementing methods to actually set these properties on the
+ * specific node type they handle.
+ *
+ * @param <N> The type of node this applier works with.
+ */
+public abstract class BaseSemanticNodeApplier<N> implements SemanticNodeApplier<N> {
+    @Override
+    public void applyComponent(
+            RemoteComposeDocumentAccessibility remoteComposeAccessibility,
+            N nodeInfo,
+            Component component,
+            List<AccessibilitySemantics> semantics) {
+        float[] locationInWindow = new float[2];
+        component.getLocationInWindow(locationInWindow);
+        Rect bounds =
+                new Rect(
+                        (int) locationInWindow[0],
+                        (int) locationInWindow[1],
+                        (int) (locationInWindow[0] + component.getWidth()),
+                        (int) (locationInWindow[1] + component.getHeight()));
+        setBoundsInScreen(nodeInfo, bounds);
+
+        setUniqueId(nodeInfo, String.valueOf(component.getComponentId()));
+
+        if (component instanceof AccessibleComponent) {
+            applyContentDescription(
+                    ((AccessibleComponent) component).getContentDescriptionId(),
+                    nodeInfo,
+                    remoteComposeAccessibility);
+
+            applyText(
+                    ((AccessibleComponent) component).getTextId(),
+                    nodeInfo,
+                    remoteComposeAccessibility);
+
+            applyRole(((AccessibleComponent) component).getRole(), nodeInfo);
+        }
+
+        applySemantics(remoteComposeAccessibility, nodeInfo, semantics);
+
+        if (getText(nodeInfo) == null && getContentDescription(nodeInfo) == null) {
+            setContentDescription(nodeInfo, "");
+        }
+    }
+
+    protected void applySemantics(
+            RemoteComposeDocumentAccessibility remoteComposeAccessibility,
+            N nodeInfo,
+            List<AccessibilitySemantics> semantics) {
+        for (AccessibilitySemantics semantic : semantics) {
+            if (semantic.isInterestingForSemantics()) {
+                if (semantic instanceof CoreSemantics) {
+                    CoreSemantics coreSemantics = (CoreSemantics) semantic;
+                    applyCoreSemantics(remoteComposeAccessibility, nodeInfo, coreSemantics);
+                } else if (semantic instanceof AccessibleComponent) {
+                    AccessibleComponent accessibleComponent = (AccessibleComponent) semantic;
+                    if (accessibleComponent.isClickable()) {
+                        setClickable(nodeInfo, true);
+                    }
+
+                    if (accessibleComponent.getContentDescriptionId() != null) {
+                        applyContentDescription(
+                                accessibleComponent.getContentDescriptionId(),
+                                nodeInfo,
+                                remoteComposeAccessibility);
+                    }
+
+                    if (accessibleComponent.getTextId() != null) {
+                        applyText(
+                                accessibleComponent.getTextId(),
+                                nodeInfo,
+                                remoteComposeAccessibility);
+                    }
+
+                    applyRole(accessibleComponent.getRole(), nodeInfo);
+                }
+            }
+        }
+    }
+
+    protected void applyCoreSemantics(
+            RemoteComposeDocumentAccessibility remoteComposeAccessibility,
+            N nodeInfo,
+            CoreSemantics coreSemantics) {
+        applyContentDescription(
+                coreSemantics.getContentDescriptionId(), nodeInfo, remoteComposeAccessibility);
+
+        applyRole(coreSemantics.getRole(), nodeInfo);
+
+        applyText(coreSemantics.getTextId(), nodeInfo, remoteComposeAccessibility);
+
+        applyStateDescription(
+                coreSemantics.getStateDescriptionId(), nodeInfo, remoteComposeAccessibility);
+
+        if (!coreSemantics.mEnabled) {
+            setEnabled(nodeInfo, false);
+        }
+    }
+
+    protected void applyStateDescription(
+            Integer stateDescriptionId,
+            N nodeInfo,
+            RemoteComposeDocumentAccessibility remoteComposeAccessibility) {
+        if (stateDescriptionId != null) {
+            setStateDescription(
+                    nodeInfo,
+                    appendNullable(
+                            getStateDescription(nodeInfo),
+                            remoteComposeAccessibility.stringValue(stateDescriptionId)));
+        }
+    }
+
+    protected void applyRole(AccessibleComponent.Role role, N nodeInfo) {
+        if (role != null) {
+            setRoleDescription(nodeInfo, role.getDescription());
+        }
+    }
+
+    protected void applyText(
+            Integer textId,
+            N nodeInfo,
+            RemoteComposeDocumentAccessibility remoteComposeAccessibility) {
+        if (textId != null) {
+            setText(
+                    nodeInfo,
+                    appendNullable(
+                            getText(nodeInfo), remoteComposeAccessibility.stringValue(textId)));
+        }
+    }
+
+    protected void applyContentDescription(
+            Integer contentDescriptionId,
+            N nodeInfo,
+            RemoteComposeDocumentAccessibility remoteComposeAccessibility) {
+        if (contentDescriptionId != null) {
+            setContentDescription(
+                    nodeInfo,
+                    appendNullable(
+                            getContentDescription(nodeInfo),
+                            remoteComposeAccessibility.stringValue(contentDescriptionId)));
+        }
+    }
+
+    private CharSequence appendNullable(CharSequence contentDescription, String value) {
+        if (contentDescription == null) {
+            return value;
+        } else if (value == null) {
+            return contentDescription;
+        } else {
+            return contentDescription + " " + value;
+        }
+    }
+
+    protected abstract void setClickable(N nodeInfo, boolean b);
+
+    protected abstract void setEnabled(N nodeInfo, boolean b);
+
+    protected abstract CharSequence getStateDescription(N nodeInfo);
+
+    protected abstract void setStateDescription(N nodeInfo, CharSequence charSequence);
+
+    protected abstract void setRoleDescription(N nodeInfo, String description);
+
+    protected abstract CharSequence getText(N nodeInfo);
+
+    protected abstract void setText(N nodeInfo, CharSequence charSequence);
+
+    protected abstract CharSequence getContentDescription(N nodeInfo);
+
+    protected abstract void setContentDescription(N nodeInfo, CharSequence charSequence);
+
+    protected abstract void setBoundsInScreen(N nodeInfo, Rect bounds);
+
+    protected abstract void setUniqueId(N nodeInfo, String s);
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/accessibility/CoreDocumentAccessibility.java b/core/java/com/android/internal/widget/remotecompose/accessibility/CoreDocumentAccessibility.java
index 66a7f02..2cd4f03 100644
--- a/core/java/com/android/internal/widget/remotecompose/accessibility/CoreDocumentAccessibility.java
+++ b/core/java/com/android/internal/widget/remotecompose/accessibility/CoreDocumentAccessibility.java
@@ -17,10 +17,10 @@
 
 import android.annotation.Nullable;
 import android.graphics.PointF;
-import android.graphics.Rect;
 import android.os.Bundle;
 
 import com.android.internal.widget.remotecompose.core.CoreDocument;
+import com.android.internal.widget.remotecompose.core.Operation;
 import com.android.internal.widget.remotecompose.core.operations.layout.ClickModifierOperation;
 import com.android.internal.widget.remotecompose.core.operations.layout.Component;
 import com.android.internal.widget.remotecompose.core.operations.layout.LayoutComponent;
@@ -31,9 +31,9 @@
 import com.android.internal.widget.remotecompose.core.semantics.AccessibleComponent;
 import com.android.internal.widget.remotecompose.core.semantics.CoreSemantics;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
-import java.util.Objects;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -43,12 +43,9 @@
  * list of modifiers that must be tagged with {@link AccessibilitySemantics} either incidentally
  * (see {@link ClickModifierOperation}) or explicitly (see {@link CoreSemantics}).
  */
-public class CoreDocumentAccessibility
-        implements RemoteComposeDocumentAccessibility<Component, AccessibilitySemantics> {
+public class CoreDocumentAccessibility implements RemoteComposeDocumentAccessibility {
     private final CoreDocument mDocument;
 
-    private final Rect mMissingBounds = new Rect(0, 0, 1, 1);
-
     public CoreDocumentAccessibility(CoreDocument document) {
         this.mDocument = document;
     }
@@ -74,17 +71,25 @@
     }
 
     @Override
-    public List<CoreSemantics.Mode> mergeMode(Component component) {
+    public CoreSemantics.Mode mergeMode(Component component) {
         if (!(component instanceof LayoutComponent)) {
-            return Collections.singletonList(CoreSemantics.Mode.SET);
+            return CoreSemantics.Mode.SET;
         }
 
-        return ((LayoutComponent) component)
-                .getComponentModifiers().getList().stream()
-                        .filter(i -> i instanceof AccessibleComponent)
-                        .map(i -> ((AccessibleComponent) i).getMode())
-                        .filter(Objects::nonNull)
-                        .collect(Collectors.toList());
+        CoreSemantics.Mode result = CoreSemantics.Mode.SET;
+
+        for (ModifierOperation modifier :
+                ((LayoutComponent) component).getComponentModifiers().getList()) {
+            if (modifier instanceof AccessibleComponent) {
+                AccessibleComponent semantics = (AccessibleComponent) modifier;
+
+                if (semantics.getMode().ordinal() > result.ordinal()) {
+                    result = semantics.getMode();
+                }
+            }
+        }
+
+        return result;
     }
 
     @Override
@@ -101,6 +106,7 @@
     @Override
     public String stringValue(int id) {
         Object value = mDocument.getRemoteComposeState().getFromId(id);
+
         return value != null ? String.valueOf(value) : null;
     }
 
@@ -124,12 +130,33 @@
     }
 
     @Override
-    public List<Integer> semanticallyRelevantChildComponents(Component component) {
-        return componentStream(component)
-                .filter(i -> i.getComponentId() != component.getComponentId())
-                .filter(CoreDocumentAccessibility::isInteresting)
-                .map(Component::getComponentId)
-                .collect(Collectors.toList());
+    public List<Integer> semanticallyRelevantChildComponents(
+            Component component, boolean useUnmergedTree) {
+        if (!component.isVisible()) {
+            return Collections.emptyList();
+        }
+
+        CoreSemantics.Mode mergeMode = mergeMode(component);
+        if (mergeMode == CoreSemantics.Mode.CLEAR_AND_SET
+                || (!useUnmergedTree && mergeMode == CoreSemantics.Mode.MERGE)) {
+            return Collections.emptyList();
+        }
+
+        ArrayList<Integer> result = new ArrayList<>();
+
+        for (Operation child : component.mList) {
+            if (child instanceof Component) {
+                if (isInteresting((Component) child)) {
+                    result.add(((Component) child).getComponentId());
+                } else {
+                    result.addAll(
+                            semanticallyRelevantChildComponents(
+                                    (Component) child, useUnmergedTree));
+                }
+            }
+        }
+
+        return result;
     }
 
     static Stream<Component> componentStream(Component root) {
@@ -153,12 +180,13 @@
     }
 
     static boolean isInteresting(Component component) {
-        boolean interesting =
-                isContainerWithSemantics(component)
-                        || modifiersStream(component)
-                                .anyMatch(CoreDocumentAccessibility::isModifierWithSemantics);
+        if (!component.isVisible()) {
+            return false;
+        }
 
-        return interesting && component.isVisible();
+        return isContainerWithSemantics(component)
+                || modifiersStream(component)
+                        .anyMatch(CoreDocumentAccessibility::isModifierWithSemantics);
     }
 
     static boolean isModifierWithSemantics(ModifierOperation modifier) {
diff --git a/core/java/com/android/internal/widget/remotecompose/accessibility/PlatformRemoteComposeAccessibilityRegistrar.java b/core/java/com/android/internal/widget/remotecompose/accessibility/PlatformRemoteComposeAccessibilityRegistrar.java
new file mode 100644
index 0000000..010253e
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/accessibility/PlatformRemoteComposeAccessibilityRegistrar.java
@@ -0,0 +1,46 @@
+/*
+ * 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.internal.widget.remotecompose.accessibility;
+
+import android.annotation.NonNull;
+import android.view.View;
+
+import com.android.internal.widget.remotecompose.core.CoreDocument;
+
+/**
+ * Trivial wrapper for calling setAccessibilityDelegate on a View. This exists primarily because the
+ * RemoteDocumentPlayer is either running in the platform on a known API version, or outside in
+ * which case it must use the Androidx ViewCompat class.
+ */
+public class PlatformRemoteComposeAccessibilityRegistrar
+        implements RemoteComposeAccessibilityRegistrar {
+    public PlatformRemoteComposeTouchHelper forRemoteComposePlayer(
+            View player, @NonNull CoreDocument coreDocument) {
+        return new PlatformRemoteComposeTouchHelper(
+                player,
+                new CoreDocumentAccessibility(coreDocument),
+                new AndroidPlatformSemanticNodeApplier());
+    }
+
+    public void setAccessibilityDelegate(View remoteComposePlayer, CoreDocument document) {
+        remoteComposePlayer.setAccessibilityDelegate(
+                forRemoteComposePlayer(remoteComposePlayer, document));
+    }
+
+    public void clearAccessibilityDelegate(View remoteComposePlayer) {
+        remoteComposePlayer.setAccessibilityDelegate(null);
+    }
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/accessibility/PlatformRemoteComposeTouchHelper.java b/core/java/com/android/internal/widget/remotecompose/accessibility/PlatformRemoteComposeTouchHelper.java
index c9ad28a..39a2ab3 100644
--- a/core/java/com/android/internal/widget/remotecompose/accessibility/PlatformRemoteComposeTouchHelper.java
+++ b/core/java/com/android/internal/widget/remotecompose/accessibility/PlatformRemoteComposeTouchHelper.java
@@ -37,24 +37,23 @@
 import java.util.Set;
 import java.util.Stack;
 
-public class PlatformRemoteComposeTouchHelper<N, C, S> extends ExploreByTouchHelper {
-    private final RemoteComposeDocumentAccessibility<C, S> mRemoteDocA11y;
+public class PlatformRemoteComposeTouchHelper extends ExploreByTouchHelper {
+    private final RemoteComposeDocumentAccessibility mRemoteDocA11y;
 
-    private final SemanticNodeApplier<AccessibilityNodeInfo, C, S> mApplier;
+    private final SemanticNodeApplier<AccessibilityNodeInfo> mApplier;
 
     public PlatformRemoteComposeTouchHelper(
             View host,
-            RemoteComposeDocumentAccessibility<C, S> remoteDocA11y,
-            SemanticNodeApplier<AccessibilityNodeInfo, C, S> applier) {
+            RemoteComposeDocumentAccessibility remoteDocA11y,
+            SemanticNodeApplier<AccessibilityNodeInfo> applier) {
         super(host);
         this.mRemoteDocA11y = remoteDocA11y;
         this.mApplier = applier;
     }
 
-    public static PlatformRemoteComposeTouchHelper<
-                    AccessibilityNodeInfo, Component, AccessibilitySemantics>
-            forRemoteComposePlayer(View player, @NonNull CoreDocument coreDocument) {
-        return new PlatformRemoteComposeTouchHelper<>(
+    public static PlatformRemoteComposeTouchHelper forRemoteComposePlayer(
+            View player, @NonNull CoreDocument coreDocument) {
+        return new PlatformRemoteComposeTouchHelper(
                 player,
                 new CoreDocumentAccessibility(coreDocument),
                 new AndroidPlatformSemanticNodeApplier());
@@ -104,18 +103,21 @@
             Integer componentId = toVisit.remove(0);
 
             if (visited.add(componentId)) {
-                virtualViewIds.add(componentId);
+                Component component = mRemoteDocA11y.findComponentById(componentId);
 
-                C component = mRemoteDocA11y.findComponentById(componentId);
+                // Only include the root when it has semantics such as content description
+                if (!RootId.equals(componentId)
+                        || !mRemoteDocA11y.semanticModifiersForComponent(component).isEmpty()) {
+                    virtualViewIds.add(componentId);
+                }
 
                 if (component != null) {
-                    boolean allSet =
-                            mRemoteDocA11y.mergeMode(component).stream()
-                                    .allMatch(i -> i == Mode.SET);
+                    Mode mergeMode = mRemoteDocA11y.mergeMode(component);
 
-                    if (allSet) {
+                    if (mergeMode == Mode.SET) {
                         List<Integer> childViews =
-                                mRemoteDocA11y.semanticallyRelevantChildComponents(component);
+                                mRemoteDocA11y.semanticallyRelevantChildComponents(
+                                        component, false);
 
                         toVisit.addAll(childViews);
                     }
@@ -127,32 +129,34 @@
     @Override
     public void onPopulateNodeForVirtualView(
             int virtualViewId, @NonNull AccessibilityNodeInfo node) {
-        C component = mRemoteDocA11y.findComponentById(virtualViewId);
+        Component component = mRemoteDocA11y.findComponentById(virtualViewId);
 
-        List<Mode> mode = mRemoteDocA11y.mergeMode(component);
+        Mode mergeMode = mRemoteDocA11y.mergeMode(component);
 
-        if (mode.contains(Mode.MERGE)) {
+        // default to enabled
+        node.setEnabled(true);
+
+        if (mergeMode == Mode.MERGE) {
             List<Integer> childViews =
-                    mRemoteDocA11y.semanticallyRelevantChildComponents(component);
+                    mRemoteDocA11y.semanticallyRelevantChildComponents(component, true);
 
             for (Integer childView : childViews) {
                 onPopulateNodeForVirtualView(childView, node);
             }
         }
 
-        List<S> semantics = mRemoteDocA11y.semanticModifiersForComponent(component);
+        List<AccessibilitySemantics> semantics =
+                mRemoteDocA11y.semanticModifiersForComponent(component);
         mApplier.applyComponent(mRemoteDocA11y, node, component, semantics);
     }
 
     @Override
-    protected void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) {
-        // TODO
-    }
+    protected void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) {}
 
     @Override
     protected boolean onPerformActionForVirtualView(
             int virtualViewId, int action, @Nullable Bundle arguments) {
-        C component = mRemoteDocA11y.findComponentById(virtualViewId);
+        Component component = mRemoteDocA11y.findComponentById(virtualViewId);
 
         if (component != null) {
             return mRemoteDocA11y.performAction(component, action, arguments);
diff --git a/core/java/com/android/internal/widget/remotecompose/accessibility/RemoteComposeAccessibilityRegistrar.java b/core/java/com/android/internal/widget/remotecompose/accessibility/RemoteComposeAccessibilityRegistrar.java
new file mode 100644
index 0000000..7e8236b
--- /dev/null
+++ b/core/java/com/android/internal/widget/remotecompose/accessibility/RemoteComposeAccessibilityRegistrar.java
@@ -0,0 +1,33 @@
+/*
+ * 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.internal.widget.remotecompose.accessibility;
+
+import android.view.View;
+
+import com.android.internal.widget.remotecompose.core.CoreDocument;
+
+/**
+ * Interface for registering and clearing accessibility delegates for remote compose players.
+ *
+ * <p>This interface is responsible for managing the accessibility delegate associated with a remote
+ * compose player view. It allows for setting and clearing the delegate, which is used to handle
+ * accessibility events and provide accessibility information for the remote compose content.
+ */
+public interface RemoteComposeAccessibilityRegistrar {
+    void setAccessibilityDelegate(View remoteComposePlayer, CoreDocument document);
+
+    void clearAccessibilityDelegate(View remoteComposePlayer);
+}
diff --git a/core/java/com/android/internal/widget/remotecompose/accessibility/RemoteComposeDocumentAccessibility.java b/core/java/com/android/internal/widget/remotecompose/accessibility/RemoteComposeDocumentAccessibility.java
index 14977be..50f75e4 100644
--- a/core/java/com/android/internal/widget/remotecompose/accessibility/RemoteComposeDocumentAccessibility.java
+++ b/core/java/com/android/internal/widget/remotecompose/accessibility/RemoteComposeDocumentAccessibility.java
@@ -20,6 +20,8 @@
 import android.os.Bundle;
 import android.view.View;
 
+import com.android.internal.widget.remotecompose.core.operations.layout.Component;
+import com.android.internal.widget.remotecompose.core.semantics.AccessibilitySemantics;
 import com.android.internal.widget.remotecompose.core.semantics.CoreSemantics;
 
 import java.util.List;
@@ -28,11 +30,8 @@
  * Interface for interacting with the accessibility features of a remote Compose UI. This interface
  * provides methods to perform actions, retrieve state, and query the accessibility tree of the
  * remote Compose UI.
- *
- * @param <C> The type of component in the remote Compose UI.
- * @param <S> The type representing semantic modifiers applied to components.
  */
-public interface RemoteComposeDocumentAccessibility<C, S> {
+public interface RemoteComposeDocumentAccessibility {
     // Matches ExploreByTouchHelper.HOST_ID
     Integer RootId = View.NO_ID;
 
@@ -47,7 +46,7 @@
      * @param arguments Optional arguments for the action.
      * @return {@code true} if the action was performed successfully, {@code false} otherwise.
      */
-    boolean performAction(C component, int action, Bundle arguments);
+    boolean performAction(Component component, int action, Bundle arguments);
 
     /**
      * Retrieves the string value associated with the given ID.
@@ -65,9 +64,10 @@
      *
      * @param component The component to retrieve child view IDs from, or [RootId] for the top
      *     level.
+     * @param useUnmergedTree Whether to include merged children
      * @return A list of integer IDs representing the child views of the component.
      */
-    List<Integer> semanticallyRelevantChildComponents(C component);
+    List<Integer> semanticallyRelevantChildComponents(Component component, boolean useUnmergedTree);
 
     /**
      * Retrieves the semantic modifiers associated with a given component.
@@ -75,16 +75,16 @@
      * @param component The component for which to retrieve semantic modifiers.
      * @return A list of semantic modifiers applicable to the component.
      */
-    List<S> semanticModifiersForComponent(C component);
+    List<AccessibilitySemantics> semanticModifiersForComponent(Component component);
 
     /**
      * Gets all applied merge modes of the given component. A Merge mode is one of Set, Merge or
      * Clear and describes how to apply and combine hierarchical semantics.
      *
      * @param component The component to merge the mode for.
-     * @return A list of merged modes, potentially conflicting but to be resolved by the caller.
+     * @return The effective merge modes, potentially conflicting but resolved to a single value.
      */
-    List<CoreSemantics.Mode> mergeMode(C component);
+    CoreSemantics.Mode mergeMode(Component component);
 
     /**
      * Finds a component by its ID.
@@ -93,7 +93,7 @@
      * @return the component with the given ID, or {@code null} if no such component exists
      */
     @Nullable
-    C findComponentById(int id);
+    Component findComponentById(int id);
 
     @Nullable
     Integer getComponentIdAt(PointF point);
diff --git a/core/java/com/android/internal/widget/remotecompose/accessibility/RemoteComposeTouchHelper.java b/core/java/com/android/internal/widget/remotecompose/accessibility/RemoteComposeTouchHelper.java
index 4ff7892..1364102 100644
--- a/core/java/com/android/internal/widget/remotecompose/accessibility/RemoteComposeTouchHelper.java
+++ b/core/java/com/android/internal/widget/remotecompose/accessibility/RemoteComposeTouchHelper.java
@@ -15,17 +15,11 @@
  */
 package com.android.internal.widget.remotecompose.accessibility;
 
-import android.annotation.NonNull;
-import android.view.View;
-
-import com.android.internal.widget.remotecompose.core.CoreDocument;
-
+/**
+ * This class is the entry point for finding the AccessibilityDelegate for a RemoteCompose document.
+ */
 public class RemoteComposeTouchHelper {
-    public static View.AccessibilityDelegate forRemoteComposePlayer(
-            View player, @NonNull CoreDocument coreDocument) {
-        return new PlatformRemoteComposeTouchHelper<>(
-                player,
-                new CoreDocumentAccessibility(coreDocument),
-                new AndroidPlatformSemanticNodeApplier());
-    }
+    /** Get the platform specific accessibility delegate registrar */
+    public static final RemoteComposeAccessibilityRegistrar REGISTRAR =
+            new PlatformRemoteComposeAccessibilityRegistrar();
 }
diff --git a/core/java/com/android/internal/widget/remotecompose/accessibility/SemanticNodeApplier.java b/core/java/com/android/internal/widget/remotecompose/accessibility/SemanticNodeApplier.java
index 4368329..832b542 100644
--- a/core/java/com/android/internal/widget/remotecompose/accessibility/SemanticNodeApplier.java
+++ b/core/java/com/android/internal/widget/remotecompose/accessibility/SemanticNodeApplier.java
@@ -15,6 +15,9 @@
  */
 package com.android.internal.widget.remotecompose.accessibility;
 
+import com.android.internal.widget.remotecompose.core.operations.layout.Component;
+import com.android.internal.widget.remotecompose.core.semantics.AccessibilitySemantics;
+
 import java.util.List;
 
 /**
@@ -29,15 +32,13 @@
  *
  * @param <N> The type representing information about the node. This could be an Androidx
  *     `AccessibilityNodeInfoCompat`, or potentially a platform `AccessibilityNodeInfo`.
- * @param <C> The type of component in the remote Compose UI.
- * @param <S> The type representing a single semantic property or action.
  */
-public interface SemanticNodeApplier<N, C, S> {
+public interface SemanticNodeApplier<N> {
     void applyComponent(
-            RemoteComposeDocumentAccessibility<C, S> remoteComposeAccessibility,
+            RemoteComposeDocumentAccessibility remoteComposeAccessibility,
             N nodeInfo,
-            C component,
-            List<S> semantics);
+            Component component,
+            List<AccessibilitySemantics> semantics);
 
     String VIRTUAL_VIEW_ID_KEY = "VirtualViewId";
 }
diff --git a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java
index 5bc3bca..da880e1 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java
@@ -24,6 +24,8 @@
 import com.android.internal.widget.remotecompose.core.operations.IntegerExpression;
 import com.android.internal.widget.remotecompose.core.operations.NamedVariable;
 import com.android.internal.widget.remotecompose.core.operations.RootContentBehavior;
+import com.android.internal.widget.remotecompose.core.operations.ShaderData;
+import com.android.internal.widget.remotecompose.core.operations.TextData;
 import com.android.internal.widget.remotecompose.core.operations.Theme;
 import com.android.internal.widget.remotecompose.core.operations.layout.ClickModifierOperation;
 import com.android.internal.widget.remotecompose.core.operations.layout.Component;
@@ -45,6 +47,7 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -441,11 +444,11 @@
         mActionListeners.clear();
     }
 
-    public interface ClickCallbacks {
-        void click(int id, @Nullable String metadata);
+    public interface IdActionCallback {
+        void onAction(int id, @Nullable String metadata);
     }
 
-    @NonNull HashSet<ClickCallbacks> mClickListeners = new HashSet<>();
+    @NonNull HashSet<IdActionCallback> mIdActionListeners = new HashSet<>();
     @NonNull HashSet<TouchListener> mTouchListeners = new HashSet<>();
     @NonNull HashSet<ClickAreaRepresentation> mClickAreas = new HashSet<>();
 
@@ -470,6 +473,21 @@
         float mBottom;
         @Nullable final String mMetadata;
 
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (!(o instanceof ClickAreaRepresentation)) return false;
+            ClickAreaRepresentation that = (ClickAreaRepresentation) o;
+            return mId == that.mId
+                    && Objects.equals(mContentDescription, that.mContentDescription)
+                    && Objects.equals(mMetadata, that.mMetadata);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mId, mContentDescription, mMetadata);
+        }
+
         public ClickAreaRepresentation(
                 int id,
                 @Nullable String contentDescription,
@@ -754,9 +772,13 @@
             float right,
             float bottom,
             @Nullable String metadata) {
-        mClickAreas.add(
+
+        ClickAreaRepresentation car =
                 new ClickAreaRepresentation(
-                        id, contentDescription, left, top, right, bottom, metadata));
+                        id, contentDescription, left, top, right, bottom, metadata);
+
+        boolean old = mClickAreas.remove(car);
+        mClickAreas.add(car);
     }
 
     /**
@@ -769,12 +791,12 @@
     }
 
     /**
-     * Add a click listener. This will get called when a click is detected on the document
+     * Add an id action listener. This will get called when e.g. a click is detected on the document
      *
-     * @param callback called when a click area has been hit, passing the click are id and metadata.
+     * @param callback called when an action is executed, passing the id and metadata.
      */
-    public void addClickListener(@NonNull ClickCallbacks callback) {
-        mClickListeners.add(callback);
+    public void addIdActionListener(@NonNull IdActionCallback callback) {
+        mIdActionListeners.add(callback);
     }
 
     /**
@@ -783,8 +805,8 @@
      * @return set of click listeners
      */
     @NonNull
-    public HashSet<CoreDocument.ClickCallbacks> getClickListeners() {
-        return mClickListeners;
+    public HashSet<IdActionCallback> getIdActionListeners() {
+        return mIdActionListeners;
     }
 
     /**
@@ -813,15 +835,15 @@
                 warnClickListeners(clickArea);
             }
         }
-        for (ClickCallbacks listener : mClickListeners) {
-            listener.click(id, "");
+        for (IdActionCallback listener : mIdActionListeners) {
+            listener.onAction(id, "");
         }
     }
 
     /** Warn click listeners when a click area is activated */
     private void warnClickListeners(@NonNull ClickAreaRepresentation clickArea) {
-        for (ClickCallbacks listener : mClickListeners) {
-            listener.click(clickArea.mId, clickArea.mMetadata);
+        for (IdActionCallback listener : mIdActionListeners) {
+            listener.onAction(clickArea.mId, clickArea.mMetadata);
         }
     }
 
@@ -1067,7 +1089,6 @@
             mRepaintNext = 1;
         }
         context.mMode = RemoteContext.ContextMode.UNSET;
-        // System.out.println(">>   " + (  System.nanoTime() - time)*1E-6f+" ms");
         if (DEBUG && mRootLayoutComponent != null) {
             System.out.println(mRootLayoutComponent.displayHierarchy());
         }
@@ -1163,4 +1184,30 @@
     public List<Operation> getOperations() {
         return mOperations;
     }
+
+    /** defines if a shader can be run */
+    public interface ShaderControl {
+        boolean isShaderValid(String shader);
+    }
+
+    /**
+     * validate the shaders
+     *
+     * @param context the remote context
+     * @param ctl the call back to allow evaluation of shaders
+     */
+    public void checkShaders(RemoteContext context, ShaderControl ctl) {
+        int count = 0;
+        for (Operation op : mOperations) {
+            if (op instanceof TextData) {
+                op.apply(context);
+            }
+            if (op instanceof ShaderData) {
+                ShaderData sd = (ShaderData) op;
+                int id = sd.getShaderTextId();
+                String str = context.getText(id);
+                sd.enable(ctl.isShaderValid(str));
+            }
+        }
+    }
 }
diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
index 003acb7..c03f44b 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
@@ -493,6 +493,9 @@
 
     public static final int ID_DENSITY = 27;
 
+    /** Defines when the last build was made */
+    public static final int ID_API_LEVEL = 28;
+
     public static final float FLOAT_DENSITY = Utils.asNan(ID_DENSITY);
 
     /** CONTINUOUS_SEC is seconds from midnight looping every hour 0-3600 */
@@ -566,6 +569,9 @@
     /** Ambient light level in SI lux */
     public static final float FLOAT_LIGHT = Utils.asNan(ID_LIGHT);
 
+    /** When was this player built */
+    public static final float FLOAT_API_LEVEL = Utils.asNan(ID_API_LEVEL);
+
     ///////////////////////////////////////////////////////////////////////////////////////////////
     // Click handling
     ///////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java b/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java
index 0ed6005..cd7ebec 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java
@@ -24,6 +24,8 @@
 
 /** This generates the standard system variables for time. */
 public class TimeVariables {
+    private static final float BUILD = 0.01f;
+
     /**
      * This class populates all time variables in the system
      *
@@ -57,6 +59,7 @@
         context.loadFloat(RemoteContext.ID_CALENDAR_MONTH, month);
         context.loadFloat(RemoteContext.ID_DAY_OF_MONTH, month);
         context.loadFloat(RemoteContext.ID_WEEK_DAY, day_week);
+        context.loadFloat(RemoteContext.ID_API_LEVEL, CoreDocument.getDocumentApiLevel() + BUILD);
     }
 
     /**
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ClickArea.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ClickArea.java
index efd31af..29124d0 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ClickArea.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ClickArea.java
@@ -21,6 +21,7 @@
 import com.android.internal.widget.remotecompose.core.Operations;
 import com.android.internal.widget.remotecompose.core.RemoteComposeOperation;
 import com.android.internal.widget.remotecompose.core.RemoteContext;
+import com.android.internal.widget.remotecompose.core.VariableSupport;
 import com.android.internal.widget.remotecompose.core.WireBuffer;
 import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
 import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
@@ -29,7 +30,8 @@
 import java.util.List;
 
 /** Add a click area to the document */
-public class ClickArea extends Operation implements RemoteComposeOperation, AccessibleComponent {
+public class ClickArea extends Operation
+        implements RemoteComposeOperation, AccessibleComponent, VariableSupport {
     private static final int OP_CODE = Operations.CLICK_AREA;
     private static final String CLASS_NAME = "ClickArea";
     int mId;
@@ -38,6 +40,10 @@
     float mTop;
     float mRight;
     float mBottom;
+    float mOutLeft;
+    float mOutTop;
+    float mOutRight;
+    float mOutBottom;
     int mMetadata;
 
     /**
@@ -62,11 +68,35 @@
             int metadata) {
         this.mId = id;
         this.mContentDescription = contentDescription;
-        this.mLeft = left;
-        this.mTop = top;
-        this.mRight = right;
-        this.mBottom = bottom;
-        this.mMetadata = metadata;
+        mOutLeft = mLeft = left;
+        mOutTop = mTop = top;
+        mOutRight = mRight = right;
+        mOutBottom = mBottom = bottom;
+        mMetadata = metadata;
+    }
+
+    @Override
+    public void registerListening(@NonNull RemoteContext context) {
+        if (Float.isNaN(mLeft)) {
+            context.listensTo(Utils.idFromNan(mLeft), this);
+        }
+        if (Float.isNaN(mTop)) {
+            context.listensTo(Utils.idFromNan(mTop), this);
+        }
+        if (Float.isNaN(mRight)) {
+            context.listensTo(Utils.idFromNan(mRight), this);
+        }
+        if (Float.isNaN(mBottom)) {
+            context.listensTo(Utils.idFromNan(mBottom), this);
+        }
+    }
+
+    @Override
+    public void updateVariables(@NonNull RemoteContext context) {
+        mOutLeft = Float.isNaN(mLeft) ? context.getFloat(Utils.idFromNan(mLeft)) : mLeft;
+        mOutTop = Float.isNaN(mTop) ? context.getFloat(Utils.idFromNan(mTop)) : mTop;
+        mRight = Float.isNaN(mRight) ? context.getFloat(Utils.idFromNan(mRight)) : mRight;
+        mOutBottom = Float.isNaN(mBottom) ? context.getFloat(Utils.idFromNan(mBottom)) : mBottom;
     }
 
     @Override
@@ -105,7 +135,8 @@
         if (context.getMode() != RemoteContext.ContextMode.DATA) {
             return;
         }
-        context.addClickArea(mId, mContentDescription, mLeft, mTop, mRight, mBottom, mMetadata);
+        context.addClickArea(
+                mId, mContentDescription, mOutLeft, mOutTop, mOutRight, mOutBottom, mMetadata);
     }
 
     @NonNull
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java
index 8e4098e..891367e 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ShaderData.java
@@ -50,6 +50,7 @@
     @Nullable HashMap<String, float[]> mUniformFloatMap = null;
     @Nullable HashMap<String, int[]> mUniformIntMap;
     @Nullable HashMap<String, Integer> mUniformBitmapMap = null;
+    private boolean mShaderValid = false;
 
     public ShaderData(
             int shaderID,
@@ -358,7 +359,9 @@
 
     @Override
     public void apply(@NonNull RemoteContext context) {
-        context.loadShader(mShaderID, this);
+        if (mShaderValid) {
+            context.loadShader(mShaderID, this);
+        }
     }
 
     @NonNull
@@ -366,4 +369,13 @@
     public String deepToString(@NonNull String indent) {
         return indent + toString();
     }
+
+    /**
+     * Enable or disable the shader
+     *
+     * @param shaderValid if true shader can be used
+     */
+    public void enable(boolean shaderValid) {
+        mShaderValid = shaderValid;
+    }
 }
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java b/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java
index f42abfc..14b72af 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/TouchExpression.java
@@ -366,6 +366,7 @@
 
     /**
      * Set the component the touch expression is in (if any)
+     *
      * @param component the component, or null if outside
      */
     public void setComponent(@Nullable Component component) {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/MarqueeModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/MarqueeModifierOperation.java
index 8b6d497..9588e99 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/MarqueeModifierOperation.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/MarqueeModifierOperation.java
@@ -92,9 +92,7 @@
         return false;
     }
 
-    /**
-     * Reset the modifier
-     */
+    /** Reset the modifier */
     public void reset() {
         mLastTime = 0;
         mScrollX = 0f;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/semantics/CoreSemantics.java b/core/java/com/android/internal/widget/remotecompose/core/semantics/CoreSemantics.java
index b8166e6..4047dd2 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/semantics/CoreSemantics.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/semantics/CoreSemantics.java
@@ -48,6 +48,11 @@
     }
 
     @Override
+    public Mode getMode() {
+        return mMode;
+    }
+
+    @Override
     public void write(WireBuffer buffer) {
         buffer.writeInt(mContentDescriptionId);
         buffer.writeByte((mRole != null) ? mRole.ordinal() : -1);
@@ -78,6 +83,10 @@
     public String toString() {
         StringBuilder builder = new StringBuilder();
         builder.append("SEMANTICS");
+        if (mMode != Mode.SET) {
+            builder.append(" ");
+            builder.append(mMode);
+        }
         if (mRole != null) {
             builder.append(" ");
             builder.append(mRole);
diff --git a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java
index 19453a0..7dad293 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java
@@ -32,6 +32,7 @@
 import android.widget.HorizontalScrollView;
 import android.widget.ScrollView;
 
+import com.android.internal.widget.remotecompose.accessibility.RemoteComposeTouchHelper;
 import com.android.internal.widget.remotecompose.core.CoreDocument;
 import com.android.internal.widget.remotecompose.core.RemoteContext;
 import com.android.internal.widget.remotecompose.core.operations.NamedVariable;
@@ -61,6 +62,15 @@
     }
 
     /**
+     * Returns true if the document supports drag touch events
+     *
+     * @return true if draggable content, false otherwise
+     */
+    public boolean isDraggable() {
+        return mInner.isDraggable();
+    }
+
+    /**
      * Turn on debug information
      *
      * @param debugFlags 1 to set debug on
@@ -83,9 +93,12 @@
             } else {
                 Log.e("RemoteComposePlayer", "Unsupported document ");
             }
+
+            RemoteComposeTouchHelper.REGISTRAR.setAccessibilityDelegate(this, value.getDocument());
         } else {
             mInner.setDocument(null);
-            this.setAccessibilityDelegate(null);
+
+            RemoteComposeTouchHelper.REGISTRAR.clearAccessibilityDelegate(this);
         }
         mapColors();
         setupSensors();
@@ -97,6 +110,7 @@
                         provideHapticFeedback(type);
                     }
                 });
+        mInner.checkShaders(mShaderControl);
     }
 
     /**
@@ -236,22 +250,23 @@
         mInner.clearLocalString("SYSTEM:" + name);
     }
 
-    public interface ClickCallbacks {
-        void click(int id, String metadata);
+    /** Id action callback interface */
+    public interface IdActionCallbacks {
+        void onAction(int id, String metadata);
     }
 
     /**
-     * Add a callback for handling click events on the document
+     * Add a callback for handling id actions events on the document
      *
-     * @param callback the callback lambda that will be used when a click is detected
+     * @param callback the callback lambda that will be used when a action is executed
      *     <p>The parameter of the callback are:
      *     <ul>
-     *       <li>id : the id of the clicked area
-     *       <li>metadata: a client provided unstructured string associated with that area
+     *       <li>id : the id of the action
+     *       <li>metadata: a client provided unstructured string associated with that id action
      *     </ul>
      */
-    public void addClickListener(ClickCallbacks callback) {
-        mInner.addClickListener((id, metadata) -> callback.click(id, metadata));
+    public void addIdActionListener(IdActionCallbacks callback) {
+        mInner.addIdActionListener((id, metadata) -> callback.onAction(id, metadata));
     }
 
     /**
@@ -670,4 +685,19 @@
     public float getEvalTime() {
         return mInner.getEvalTime();
     }
+
+    private CoreDocument.ShaderControl mShaderControl =
+            (shader) -> {
+                return false;
+            };
+
+    /**
+     * Sets the controller for shaders. Note set before loading the document. The default is to not
+     * accept shaders.
+     *
+     * @param ctl the controller
+     */
+    public void setShaderControl(CoreDocument.ShaderControl ctl) {
+        mShaderControl = ctl;
+    }
 }
diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java
index daa44c8..0712ea4 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java
@@ -505,6 +505,9 @@
                             return;
                         }
                         ShaderData data = getShaderData(shaderId);
+                        if (data == null) {
+                            return;
+                        }
                         RuntimeShader shader = new RuntimeShader(getText(data.getShaderTextId()));
                         String[] names = data.getUniformFloatNames();
                         for (int i = 0; i < names.length; i++) {
diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java b/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java
index 8da5b9d..c7b1166 100644
--- a/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java
+++ b/core/java/com/android/internal/widget/remotecompose/player/platform/RemoteComposeCanvas.java
@@ -205,19 +205,46 @@
         return count;
     }
 
+    /**
+     * set a float externally
+     *
+     * @param id
+     * @param value
+     */
     public void setExternalFloat(int id, float value) {
         mARContext.loadFloat(id, value);
     }
 
+    /**
+     * Returns true if the document supports drag touch events
+     *
+     * @return true if draggable content, false otherwise
+     */
+    public boolean isDraggable() {
+        if (mDocument == null) {
+            return false;
+        }
+        return mDocument.getDocument().hasTouchListener();
+    }
+
+    /**
+     * Check shaders and disable them
+     *
+     * @param shaderControl the callback to validate the shader
+     */
+    public void checkShaders(CoreDocument.ShaderControl shaderControl) {
+        mDocument.getDocument().checkShaders(mARContext, shaderControl);
+    }
+
     public interface ClickCallbacks {
         void click(int id, String metadata);
     }
 
-    public void addClickListener(ClickCallbacks callback) {
+    public void addIdActionListener(ClickCallbacks callback) {
         if (mDocument == null) {
             return;
         }
-        mDocument.getDocument().addClickListener((id, metadata) -> callback.click(id, metadata));
+        mDocument.getDocument().addIdActionListener((id, metadata) -> callback.click(id, metadata));
     }
 
     public int getTheme() {
@@ -267,6 +294,7 @@
                     invalidate();
                     return true;
                 }
+                return false;
 
             case MotionEvent.ACTION_UP:
                 mInActionDown = false;
@@ -280,6 +308,7 @@
                     invalidate();
                     return true;
                 }
+                return false;
 
             case MotionEvent.ACTION_MOVE:
                 if (mInActionDown) {
@@ -293,6 +322,7 @@
                     }
                     return true;
                 }
+                return false;
         }
         return false;
     }
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index e22d958..b7a7f96 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -279,6 +279,7 @@
                 "libasync_safe",
                 "libbinderthreadstateutils",
                 "libdmabufinfo",
+                "libgenfslabelsversion.ffi",
                 "libgui_window_info_static",
                 "libkernelconfigs",
                 "libnativehelper_lazy",
diff --git a/core/jni/android_os_SELinux.cpp b/core/jni/android_os_SELinux.cpp
index 7a4670f4..805d5ad 100644
--- a/core/jni/android_os_SELinux.cpp
+++ b/core/jni/android_os_SELinux.cpp
@@ -18,18 +18,19 @@
 
 #include <errno.h>
 #include <fcntl.h>
-
-#include <utils/Log.h>
-
+#include <genfslabelsversion.h>
 #include <nativehelper/JNIPlatformHelp.h>
-#include "jni.h"
-#include "core_jni_helpers.h"
-#include "selinux/selinux.h"
-#include "selinux/android.h"
-#include <memory>
-#include <atomic>
 #include <nativehelper/ScopedLocalRef.h>
 #include <nativehelper/ScopedUtfChars.h>
+#include <utils/Log.h>
+
+#include <atomic>
+#include <memory>
+
+#include "core_jni_helpers.h"
+#include "jni.h"
+#include "selinux/android.h"
+#include "selinux/selinux.h"
 
 namespace android {
 namespace {
@@ -404,8 +405,19 @@
 }
 
 /*
+ * Function: getGenfsLabelsVersion
+ * Purpose: get which genfs labels version /vendor uses
+ * Returns: int: genfs labels version of /vendor
+ * Exceptions: none
+ */
+static jint getGenfsLabelsVersion(JNIEnv *, jclass) {
+    return get_genfs_labels_version();
+}
+
+/*
  * JNI registration.
  */
+// clang-format off
 static const JNINativeMethod method_table[] = {
     /* name,                     signature,                    funcPtr */
     { "checkSELinuxAccess"       , "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z" , (void*)checkSELinuxAccess },
@@ -420,7 +432,9 @@
     { "setFileContext"           , "(Ljava/lang/String;Ljava/lang/String;)Z"      , (void*)setFileCon       },
     { "setFSCreateContext"       , "(Ljava/lang/String;)Z"                        , (void*)setFSCreateCon   },
     { "fileSelabelLookup"        , "(Ljava/lang/String;)Ljava/lang/String;"       , (void*)fileSelabelLookup},
+    { "getGenfsLabelsVersion"    , "()I"                                          , (void *)getGenfsLabelsVersion},
 };
+// clang-format on
 
 static int log_callback(int type, const char *fmt, ...) {
     va_list ap;
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index a09c405..7ff1f8c 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -40,6 +40,7 @@
     jmethodID dispatchHotplug;
     jmethodID dispatchHotplugConnectionError;
     jmethodID dispatchModeChanged;
+    jmethodID dispatchModeRejected;
     jmethodID dispatchFrameRateOverrides;
     jmethodID dispatchHdcpLevelsChanged;
 
@@ -95,6 +96,7 @@
     void dispatchHotplugConnectionError(nsecs_t timestamp, int errorCode) override;
     void dispatchModeChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t modeId,
                              nsecs_t renderPeriod) override;
+    void dispatchModeRejected(PhysicalDisplayId displayId, int32_t modeId) override;
     void dispatchFrameRateOverrides(nsecs_t timestamp, PhysicalDisplayId displayId,
                                     std::vector<FrameRateOverride> overrides) override;
     void dispatchNullEvent(nsecs_t timestamp, PhysicalDisplayId displayId) override {}
@@ -271,6 +273,18 @@
     mMessageQueue->raiseAndClearException(env, "dispatchModeChanged");
 }
 
+void NativeDisplayEventReceiver::dispatchModeRejected(PhysicalDisplayId displayId, int32_t modeId) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+    ScopedLocalRef<jobject> receiverObj(env, GetReferent(env, mReceiverWeakGlobal));
+    if (receiverObj.get()) {
+        ALOGV("receiver %p ~ Invoking Mode Rejected handler.", this);
+        env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchModeRejected,
+                            displayId.value, modeId);
+        ALOGV("receiver %p ~ Returned from Mode Rejected handler.", this);
+    }
+}
+
 void NativeDisplayEventReceiver::dispatchFrameRateOverrides(
         nsecs_t timestamp, PhysicalDisplayId displayId, std::vector<FrameRateOverride> overrides) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
@@ -405,6 +419,9 @@
     gDisplayEventReceiverClassInfo.dispatchModeChanged =
             GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchModeChanged",
                              "(JJIJ)V");
+    gDisplayEventReceiverClassInfo.dispatchModeRejected =
+            GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchModeRejected",
+                             "(JI)V");
     gDisplayEventReceiverClassInfo.dispatchFrameRateOverrides =
             GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz,
                              "dispatchFrameRateOverrides",
diff --git a/core/res/Android.bp b/core/res/Android.bp
index aacd869..903d08b 100644
--- a/core/res/Android.bp
+++ b/core/res/Android.bp
@@ -162,6 +162,7 @@
         "android.appwidget.flags-aconfig",
         "android.companion.virtualdevice.flags-aconfig",
         "android.content.pm.flags-aconfig",
+        "android.location.flags-aconfig",
         "android.media.audio-aconfig",
         "android.provider.flags-aconfig",
         "camera_platform_flags",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 7d77ff0..a86d551 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1139,6 +1139,16 @@
                 android:protectionLevel="signature|privileged|vendorPrivileged"
                 android:featureFlag="android.media.tv.flags.media_quality_fw"/>
 
+    <!--
+        @FlaggedApi(android.media.tv.flags.Flags.FLAG_MEDIA_QUALITY_FW)
+        Allows an application to read the aggregated color zones on the screen for use cases like
+        TV ambient backlight usages.
+        <p> Protection level: normal
+    -->
+    <permission android:name="android.permission.READ_COLOR_ZONES"
+                android:protectionLevel="normal"
+                android:featureFlag="android.media.tv.flags.media_quality_fw"/>
+
     <!-- ====================================================================== -->
     <!-- Permissions for accessing external storage                             -->
     <!-- ====================================================================== -->
@@ -2145,6 +2155,21 @@
     <permission android:name="android.permission.CONTROL_AUTOMOTIVE_GNSS"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi @hide Allows an application to bind to a
+         android.service.PopulationDensityProviderService for the purpose of
+         querying population density. This prevents arbitrary clients connecting
+         to the service. The system server checks that the provider's intent
+         service explicitly sets this permission via the android:permission
+         attribute of the service.
+         This is only expected to be possessed by the system server outside of
+         tests.
+         @FlaggedApi(android.location.flags.Flags.FLAG_POPULATION_DENSITY_PROVIDER)
+         <p>Protection level: signature
+    -->
+    <permission android:name="android.permission.BIND_POPULATION_DENSITY_PROVIDER_SERVICE"
+        android:featureFlag="android.location.flags.population_density_provider"
+        android:protectionLevel="signature" />
+
     <!-- ======================================= -->
     <!-- Permissions for accessing networks -->
     <!-- ======================================= -->
diff --git a/core/res/res/layout-round-watch/alert_dialog_title_material.xml b/core/res/res/layout-round-watch/alert_dialog_title_material.xml
index 75fe760..dac1e32 100644
--- a/core/res/res/layout-round-watch/alert_dialog_title_material.xml
+++ b/core/res/res/layout-round-watch/alert_dialog_title_material.xml
@@ -14,34 +14,30 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License
   -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:orientation="vertical"
-    android:gravity="top|center_horizontal">
-
+<LinearLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingBottom="8dp"
+        android:orientation="vertical"
+        android:gravity="top|center_horizontal">
     <FrameLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:adjustViewBounds="true">
-
-        <ImageView
-            android:id="@+id/icon"
-            android:layout_width="wrap_content"
+            android:adjustViewBounds="true"
+            android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_gravity="center_horizontal"
-            android:layout_marginBottom="8dp"
-            android:maxHeight="32dp"
-            android:maxWidth="32dp"
-            android:src="@null" />
+            android:minHeight="@dimen/screen_percentage_15">
+        <ImageView android:id="@+id/icon"
+                android:adjustViewBounds="true"
+                android:maxHeight="24dp"
+                android:maxWidth="24dp"
+                android:layout_marginTop="@dimen/screen_percentage_10"
+                android:layout_gravity="center_horizontal"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:src="@null" />
     </FrameLayout>
-
-    <TextView
-        android:id="@+id/alertTitle"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginStart="@dimen/alertDialog_material_side_margin_title"
-        android:layout_marginEnd="@dimen/alertDialog_material_side_margin_title"
-        android:textAppearance="@style/TextAppearance.AlertDialog.Title"
-        android:gravity="center" />
+    <TextView android:id="@+id/alertTitle"
+            style="?android:attr/windowTitleStyle"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
 </LinearLayout>
diff --git a/core/res/res/layout-watch-v36/alert_dialog_wear_material3.xml b/core/res/res/layout-watch-v36/alert_dialog_wear_material3.xml
index af30f1b..8f75456 100644
--- a/core/res/res/layout-watch-v36/alert_dialog_wear_material3.xml
+++ b/core/res/res/layout-watch-v36/alert_dialog_wear_material3.xml
@@ -16,123 +16,98 @@
 
 <!-- This layout is the AlertDialog template. It overrides the system layout with the same name.
     Make sure to include all the existing id of the overridden alert_dialog_material.-->
-<com.android.internal.widget.WatchListDecorLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.internal.widget.WatchListDecorLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/parentPanel"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
-
     <ScrollView
         android:id="@+id/scrollView"
+        android:fillViewport="true"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:fillViewport="true">
-
-        <requestFocus />
-
+        android:layout_height="match_parent">
         <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
             android:orientation="vertical"
-            android:layout_marginStart="@dimen/alertDialog_material_side_margin"
-            android:layout_marginEnd="@dimen/alertDialog_material_side_margin"
-            android:gravity="center_vertical">
-
-            <!-- Top Spacer -->
-            <View
-                android:layout_width="match_parent"
-                android:layout_height="@dimen/alertDialog_material_top_margin" />
-
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
             <!-- Top Panel -->
             <FrameLayout
-                android:id="@+id/topPanel"
+                android:paddingLeft="?dialogPreferredPadding"
+                android:paddingRight="?dialogPreferredPadding"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
+                android:id="@+id/topPanel"
                 android:minHeight="@dimen/dialog_list_padding_top_no_title">
-
-                <include
-                    android:id="@+id/title_template"
-                    layout="@layout/alert_dialog_title_material"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content" />
+                <include android:id="@+id/title_template"
+                         android:layout_width="match_parent"
+                         android:layout_height="wrap_content"
+                         layout="@layout/alert_dialog_title_material"/>
             </FrameLayout>
 
             <!-- Content Panel -->
-            <FrameLayout
-                android:id="@+id/contentPanel"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:paddingTop="12dp">
-
-                <TextView
-                    android:id="@+id/message"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:layout_marginStart="@dimen/alertDialog_material_side_margin_body"
-                    android:layout_marginEnd="@dimen/alertDialog_material_side_margin_body"
-                    android:textAppearance="@style/TextAppearance.AlertDialog.Body1"
-                    android:gravity="center_horizontal|top" />
+            <FrameLayout android:id="@+id/contentPanel"
+                         android:layout_width="match_parent"
+                         android:layout_height="wrap_content"
+                         android:clipToPadding="false">
+                <TextView android:id="@+id/message"
+                          android:layout_width="match_parent"
+                          android:layout_height="wrap_content"
+                          android:gravity="center_horizontal|top"
+                          android:textAppearance="@style/TextAppearance.DeviceDefault.Body1"
+                          android:paddingStart="?dialogPreferredPadding"
+                          android:paddingEnd="?dialogPreferredPadding"
+                          android:paddingTop="8dip"
+                          android:paddingBottom="8dip"/>
             </FrameLayout>
 
             <!-- Custom Panel, to replace content panel if needed -->
-            <FrameLayout
-                android:id="@+id/customPanel"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:minHeight="64dp">
-
-                <FrameLayout
-                    android:id="@+android:id/custom"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content" />
+            <FrameLayout android:id="@+id/customPanel"
+                         android:layout_width="match_parent"
+                         android:layout_height="match_parent"
+                         android:minHeight="64dp">
+                <FrameLayout android:id="@+android:id/custom"
+                             android:layout_width="match_parent"
+                             android:layout_height="wrap_content" />
             </FrameLayout>
 
             <!-- Button Panel -->
             <FrameLayout
                 android:id="@+id/buttonPanel"
+                android:minHeight="@dimen/dialog_list_padding_bottom_no_buttons"
+                android:layout_weight="1"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:layout_gravity="center"
-                android:minHeight="@dimen/dialog_list_padding_bottom_no_buttons">
-
+                android:layout_gravity="center">
                 <LinearLayout
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:layout_marginTop="16dp"
                     android:layout_gravity="bottom"
-                    android:orientation="vertical">
-
-                    <Button
-                        android:id="@+id/button1"
-                        style="@*android:style/Widget.DeviceDefault.Button.Filled"
-                        android:layout_width="match_parent"
-                        android:layout_height="match_parent"
-                        android:layout_gravity="center"
-                        android:gravity="center" />
-
-                    <Button
-                        android:id="@+id/button2"
-                        style="@*android:style/Widget.DeviceDefault.Button.WearMaterial3"
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:layout_marginTop="4dp"
-                        android:layout_gravity="center"
-                        android:gravity="center" />
-
-                    <Button
-                        android:id="@+id/button3"
-                        style="?android:attr/buttonBarButtonStyle"
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:layout_gravity="center"
-                        android:gravity="center" />
+                    android:orientation="vertical"
+                    android:paddingBottom="?dialogPreferredPadding"
+                    android:measureWithLargestChild="true">
+                    <Button android:id="@+id/button2"
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_gravity="center"
+                            android:gravity="center"
+                            android:layout_weight="1"
+                            style="@*android:style/Widget.DeviceDefault.Button.WearMaterial3"/>
+                    <Button android:id="@+id/button3"
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_gravity="center"
+                            android:gravity="center"
+                            android:layout_weight="1"
+                            style="?android:attr/buttonBarButtonStyle"/>
+                    <Button android:id="@+id/button1"
+                            android:layout_width="match_parent"
+                            android:layout_height="match_parent"
+                            android:layout_gravity="center"
+                            android:gravity="center"
+                            android:layout_weight="1"
+                            style="@*android:style/Widget.DeviceDefault.Button.Filled"/>
                 </LinearLayout>
             </FrameLayout>
-
-            <!-- Bottom Spacer -->
-            <View
-                android:layout_width="match_parent"
-                android:layout_height="@dimen/alertDialog_material_bottom_margin" />
-
         </LinearLayout>
     </ScrollView>
 </com.android.internal.widget.WatchListDecorLayout>
diff --git a/core/res/res/values-w192dp/dimens_material.xml b/core/res/res/values-w192dp/dimens_material.xml
index a11eb7f..797bf5a 100644
--- a/core/res/res/values-w192dp/dimens_material.xml
+++ b/core/res/res/values-w192dp/dimens_material.xml
@@ -14,11 +14,7 @@
      limitations under the License.
 -->
 <resources>
-    <dimen name="screen_percentage_0416">7.99dp</dimen>
     <dimen name="screen_percentage_05">9.6dp</dimen>
-    <dimen name="screen_percentage_052">9.98dp</dimen>
     <dimen name="screen_percentage_10">19.2dp</dimen>
-    <dimen name="screen_percentage_12">23.04dp</dimen>
     <dimen name="screen_percentage_15">28.8dp</dimen>
-    <dimen name="screen_percentage_3646">69.99dp</dimen>
 </resources>
diff --git a/core/res/res/values-w195dp/dimens_material.xml b/core/res/res/values-w195dp/dimens_material.xml
index 346066f..7f3ad29 100644
--- a/core/res/res/values-w195dp/dimens_material.xml
+++ b/core/res/res/values-w195dp/dimens_material.xml
@@ -14,11 +14,7 @@
      limitations under the License.
 -->
 <resources>
-    <dimen name="screen_percentage_0416">8.11dp</dimen>
     <dimen name="screen_percentage_05">9.75dp</dimen>
-    <dimen name="screen_percentage_052">10.14dp</dimen>
     <dimen name="screen_percentage_10">19.5dp</dimen>
-    <dimen name="screen_percentage_12">23.4dp</dimen>
     <dimen name="screen_percentage_15">29.25dp</dimen>
-    <dimen name="screen_percentage_3646">71.09dp</dimen>
 </resources>
diff --git a/core/res/res/values-w198dp/dimens_material.xml b/core/res/res/values-w198dp/dimens_material.xml
index 4c88f05..a8aed25 100644
--- a/core/res/res/values-w198dp/dimens_material.xml
+++ b/core/res/res/values-w198dp/dimens_material.xml
@@ -14,11 +14,7 @@
      limitations under the License.
 -->
 <resources>
-    <dimen name="screen_percentage_0416">8.24dp</dimen>
     <dimen name="screen_percentage_05">9.9dp</dimen>
-    <dimen name="screen_percentage_052">10.3dp</dimen>
     <dimen name="screen_percentage_10">19.8dp</dimen>
-    <dimen name="screen_percentage_12">23.76dp</dimen>
     <dimen name="screen_percentage_15">29.7dp</dimen>
-    <dimen name="screen_percentage_3646">72.1dp</dimen>
 </resources>
diff --git a/core/res/res/values-w204dp-round-watch/dimens_material.xml b/core/res/res/values-w204dp-round-watch/dimens_material.xml
index 54bb0c9..c07d5c4 100644
--- a/core/res/res/values-w204dp-round-watch/dimens_material.xml
+++ b/core/res/res/values-w204dp-round-watch/dimens_material.xml
@@ -14,11 +14,7 @@
      limitations under the License.
 -->
 <resources>
-    <dimen name="screen_percentage_0416">8.48dp</dimen>
     <dimen name="screen_percentage_05">10.2dp</dimen>
-    <dimen name="screen_percentage_052">10.61dp</dimen>
     <dimen name="screen_percentage_10">20.4dp</dimen>
-    <dimen name="screen_percentage_12">24.48dp</dimen>
     <dimen name="screen_percentage_15">30.6dp</dimen>
-    <dimen name="screen_percentage_3646">74.42dp</dimen>
 </resources>
diff --git a/core/res/res/values-w205dp/dimens_material.xml b/core/res/res/values-w205dp/dimens_material.xml
index 60f65bb..94907ee 100644
--- a/core/res/res/values-w205dp/dimens_material.xml
+++ b/core/res/res/values-w205dp/dimens_material.xml
@@ -14,11 +14,7 @@
      limitations under the License.
 -->
 <resources>
-    <dimen name="screen_percentage_0416">8.52dp</dimen>
     <dimen name="screen_percentage_05">10.25dp</dimen>
-    <dimen name="screen_percentage_052">10.66dp</dimen>
     <dimen name="screen_percentage_10">20.5dp</dimen>
-    <dimen name="screen_percentage_12">24.6dp</dimen>
     <dimen name="screen_percentage_15">30.75dp</dimen>
-    <dimen name="screen_percentage_3646">74.78dp</dimen>
 </resources>
diff --git a/core/res/res/values-w208dp/dimens_material.xml b/core/res/res/values-w208dp/dimens_material.xml
index 7f4ccd9..069eeb0 100644
--- a/core/res/res/values-w208dp/dimens_material.xml
+++ b/core/res/res/values-w208dp/dimens_material.xml
@@ -14,11 +14,7 @@
      limitations under the License.
 -->
 <resources>
-    <dimen name="screen_percentage_0416">8.65dp</dimen>
     <dimen name="screen_percentage_05">10.4dp</dimen>
-    <dimen name="screen_percentage_052">10.82dp</dimen>
     <dimen name="screen_percentage_10">20.8dp</dimen>
-    <dimen name="screen_percentage_12">24.96dp</dimen>
     <dimen name="screen_percentage_15">31.2dp</dimen>
-    <dimen name="screen_percentage_3646">75.65dp</dimen>
 </resources>
diff --git a/core/res/res/values-w210dp-round-watch/dimens_material.xml b/core/res/res/values-w210dp-round-watch/dimens_material.xml
index ca0889e..79acf84 100644
--- a/core/res/res/values-w210dp-round-watch/dimens_material.xml
+++ b/core/res/res/values-w210dp-round-watch/dimens_material.xml
@@ -14,14 +14,6 @@
      limitations under the License.
 -->
 <resources>
-    <dimen name="screen_percentage_0416">8.73dp</dimen>
-    <dimen name="screen_percentage_05">10.5dp</dimen>
-    <dimen name="screen_percentage_052">10.92dp</dimen>
-    <dimen name="screen_percentage_10">21dp</dimen>
-    <dimen name="screen_percentage_12">25.2dp</dimen>
-    <dimen name="screen_percentage_15">31.5dp</dimen>
-    <dimen name="screen_percentage_3646">76.57dp</dimen>
-
     <dimen name="text_size_display_4_material">80sp</dimen>
     <dimen name="text_size_display_3_material">50sp</dimen>
     <dimen name="text_size_display_2_material">40sp</dimen>
diff --git a/core/res/res/values-w211dp/dimens_material.xml b/core/res/res/values-w211dp/dimens_material.xml
index c483e45..bd7ca9a 100644
--- a/core/res/res/values-w211dp/dimens_material.xml
+++ b/core/res/res/values-w211dp/dimens_material.xml
@@ -14,11 +14,7 @@
      limitations under the License.
 -->
 <resources>
-    <dimen name="screen_percentage_0416">8.77dp</dimen>
     <dimen name="screen_percentage_05">10.55dp</dimen>
-    <dimen name="screen_percentage_052">10.97dp</dimen>
     <dimen name="screen_percentage_10">21.1dp</dimen>
-    <dimen name="screen_percentage_12">25.32dp</dimen>
     <dimen name="screen_percentage_15">31.65dp</dimen>
-    <dimen name="screen_percentage_3646">76.93dp</dimen>
 </resources>
diff --git a/core/res/res/values-w213dp/dimens_material.xml b/core/res/res/values-w213dp/dimens_material.xml
index 093c298..8a4e3a0 100644
--- a/core/res/res/values-w213dp/dimens_material.xml
+++ b/core/res/res/values-w213dp/dimens_material.xml
@@ -14,11 +14,7 @@
      limitations under the License.
 -->
 <resources>
-    <dimen name="screen_percentage_0416">8.85dp</dimen>
     <dimen name="screen_percentage_05">10.65dp</dimen>
-    <dimen name="screen_percentage_052">11.07dp</dimen>
     <dimen name="screen_percentage_10">21.3dp</dimen>
-    <dimen name="screen_percentage_12">25.56dp</dimen>
     <dimen name="screen_percentage_15">31.95dp</dimen>
-    <dimen name="screen_percentage_3646">77.66dp</dimen>
 </resources>
diff --git a/core/res/res/values-w216dp/dimens_material.xml b/core/res/res/values-w216dp/dimens_material.xml
deleted file mode 100644
index 71dbf72..0000000
--- a/core/res/res/values-w216dp/dimens_material.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<resources>
-    <dimen name="screen_percentage_0416">8.99dp</dimen>
-    <dimen name="screen_percentage_05">10.8dp</dimen>
-    <dimen name="screen_percentage_052">11.23dp</dimen>
-    <dimen name="screen_percentage_10">21.6dp</dimen>
-    <dimen name="screen_percentage_12">25.92dp</dimen>
-    <dimen name="screen_percentage_15">32.4dp</dimen>
-    <dimen name="screen_percentage_3646">78.77dp</dimen>
-</resources>
diff --git a/core/res/res/values-w225dp/dimens_material.xml b/core/res/res/values-w225dp/dimens_material.xml
index 6df34a5..aa822a3 100644
--- a/core/res/res/values-w225dp/dimens_material.xml
+++ b/core/res/res/values-w225dp/dimens_material.xml
@@ -14,11 +14,7 @@
      limitations under the License.
 -->
 <resources>
-    <dimen name="screen_percentage_0416">9.36dp</dimen>
     <dimen name="screen_percentage_05">11.25dp</dimen>
-    <dimen name="screen_percentage_052">11.7dp</dimen>
     <dimen name="screen_percentage_10">22.5dp</dimen>
-    <dimen name="screen_percentage_12">27dp</dimen>
     <dimen name="screen_percentage_15">33.75dp</dimen>
-    <dimen name="screen_percentage_3646">82.46dp</dimen>
 </resources>
diff --git a/core/res/res/values-w227dp/dimens_material.xml b/core/res/res/values-w227dp/dimens_material.xml
index bbf4924..eb4df8a2 100644
--- a/core/res/res/values-w227dp/dimens_material.xml
+++ b/core/res/res/values-w227dp/dimens_material.xml
@@ -14,11 +14,7 @@
      limitations under the License.
 -->
 <resources>
-    <dimen name="screen_percentage_0416">9.44dp</dimen>
     <dimen name="screen_percentage_05">11.35dp</dimen>
-    <dimen name="screen_percentage_052">11.8dp</dimen>
     <dimen name="screen_percentage_10">22.7dp</dimen>
-    <dimen name="screen_percentage_12">27.24dp</dimen>
     <dimen name="screen_percentage_15">34.05dp</dimen>
-    <dimen name="screen_percentage_3646">83.19dp</dimen>
 </resources>
diff --git a/core/res/res/values-w228dp/dimens_material.xml b/core/res/res/values-w228dp/dimens_material.xml
index 24bbb4c..a200975 100644
--- a/core/res/res/values-w228dp/dimens_material.xml
+++ b/core/res/res/values-w228dp/dimens_material.xml
@@ -14,11 +14,7 @@
      limitations under the License.
 -->
 <resources>
-    <dimen name="screen_percentage_0416">9.48dp</dimen>
     <dimen name="screen_percentage_05">11.4dp</dimen>
-    <dimen name="screen_percentage_052">11.86dp</dimen>
     <dimen name="screen_percentage_10">22.8dp</dimen>
-    <dimen name="screen_percentage_12">27.36dp</dimen>
     <dimen name="screen_percentage_15">34.2dp</dimen>
-    <dimen name="screen_percentage_3646">83.55dp</dimen>
 </resources>
diff --git a/core/res/res/values-w240dp/dimens_material.xml b/core/res/res/values-w240dp/dimens_material.xml
index bd26c8b..a4b58fa9 100644
--- a/core/res/res/values-w240dp/dimens_material.xml
+++ b/core/res/res/values-w240dp/dimens_material.xml
@@ -14,11 +14,7 @@
      limitations under the License.
 -->
 <resources>
-    <dimen name="screen_percentage_0416">9.98dp</dimen>
     <dimen name="screen_percentage_05">12dp</dimen>
-    <dimen name="screen_percentage_052">12.48dp</dimen>
     <dimen name="screen_percentage_10">24dp</dimen>
-    <dimen name="screen_percentage_12">28.8dp</dimen>
     <dimen name="screen_percentage_15">36dp</dimen>
-    <dimen name="screen_percentage_3646">87.5dp</dimen>
 </resources>
diff --git a/core/res/res/values-watch-v36/dimens_material.xml b/core/res/res/values-watch-v36/dimens_material.xml
index c808844..7232786 100644
--- a/core/res/res/values-watch-v36/dimens_material.xml
+++ b/core/res/res/values-watch-v36/dimens_material.xml
@@ -22,26 +22,11 @@
     <dimen name="btn_lineHeight">18sp</dimen>
     <dimen name="btn_textSize">15sp</dimen>
 
-    <!-- values for material3 AlertDialog Title -->
-    <dimen name="alertDialog_material_line_height_title">18sp</dimen>
-    <dimen name="alertDialog_material_text_size_title">16sp</dimen>
-    <item name="alertDialog_material_letter_spacing_title" format="float" type="dimen">0.0125</item>
-    <dimen name="alertDialog_material_side_margin_title">@dimen/screen_percentage_12</dimen>
-
-    <!-- values for material3 AlertDialog Body -->
-    <dimen name="alertDialog_material_line_height_body_1">16sp</dimen>
-    <dimen name="alertDialog_material_text_size_body_1">14sp</dimen>
-    <item name="alertDialog_material_letter_spacing_body_1" format="float" type="dimen">0.0286</item>
-    <dimen name="alertDialog_material_side_margin_body">@dimen/screen_percentage_0416</dimen>
-
     <!-- values for material3 AlertDialog -->
     <dimen name="dialog_btn_negative_width">60dp</dimen>
     <dimen name="dialog_btn_negative_height">60dp</dimen>
     <dimen name="dialog_btn_confirm_width">62dp</dimen>
     <dimen name="dialog_btn_confirm_height">60dp</dimen>
-    <dimen name="alertDialog_material_side_margin">@dimen/screen_percentage_052</dimen>
-    <dimen name="alertDialog_material_top_margin">@dimen/screen_percentage_10</dimen>
-    <dimen name="alertDialog_material_bottom_margin">@dimen/screen_percentage_3646</dimen>
 
     <!-- Opacity factor for disabled material3 widget -->
     <dimen name="disabled_alpha_device_default">0.12</dimen>
diff --git a/core/res/res/values-watch-v36/styles_material.xml b/core/res/res/values-watch-v36/styles_material.xml
index bc2daf2..6e5ef68 100644
--- a/core/res/res/values-watch-v36/styles_material.xml
+++ b/core/res/res/values-watch-v36/styles_material.xml
@@ -102,25 +102,4 @@
         <item name="maxHeight">@dimen/progress_bar_height</item>
         <item name="mirrorForRtl">true</item>
     </style>
-
-    <!-- TextAppearance for material3 AlertDialog Body  -->
-    <style name="TextAppearance.AlertDialog.Body1" parent="TextAppearance.Material.Body1">
-        <item name="android:fontFamily">font-family-flex-device-default</item>
-        <item name="android:fontVariationSettings">"'wdth' 90, 'wght' 450, 'ROND' 100, 'GRAD' 0"</item>
-        <item name="android:textSize">@dimen/alertDialog_material_text_size_body_1</item>
-        <item name="android:lineHeight">@dimen/alertDialog_material_line_height_body_1</item>
-        <item name="android:letterSpacing">@dimen/alertDialog_material_letter_spacing_body_1</item>
-    </style>
-
-    <!-- TextAppearance for material3 AlertDialog Title  -->
-    <style name="TextAppearance.AlertDialog.Title" parent="TextAppearance.Material.Title">
-        <item name="android:fontFamily">font-family-flex-device-default</item>
-        <item name="android:fontVariationSettings">"'wdth' 100, 'wght' 550, 'ROND' 100, 'GRAD' 0"</item>
-        <item name="android:textSize">@dimen/alertDialog_material_text_size_title</item>
-        <item name="android:lineHeight">@dimen/alertDialog_material_line_height_title</item>
-        <item name="android:letterSpacing">@dimen/alertDialog_material_letter_spacing_title</item>
-        <item name="android:maxLines">2</item>
-        <item name="android:shadowRadius">0</item>
-        <item name="android:ellipsize">end</item>
-    </style>
 </resources>
\ No newline at end of file
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 8c46ccc..238aca5 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -10570,6 +10570,32 @@
 
     <declare-styleable name="DateTimeView">
         <attr name="showRelative" format="boolean" />
+        <!-- For relative times, controls what kinds of times get disambiguation text.
+
+             The default value is "future".
+
+             Does nothing if showRelative=false.
+             -->
+        <attr name="relativeTimeDisambiguationText">
+            <!-- Times in the past will have extra clarifying text indicating that the time is in
+                 the past. For example, 1 minute ago is represented as "1m ago". If this flag is not
+                 set, times in the past are represented as just "1m". -->
+            <flag name="past" value="0x01" />
+            <!-- Times in the future will have extra clarifying text indicating that the time is in
+                 the future. For example, 1 minute in the future is represented as "in 1m". If this
+                 flag is not set, times in the future are represented as just "1m". -->
+            <flag name="future" value="0x02" />
+        </attr>
+        <!-- For relative times, sets the length of the time unit displayed (minutes, hours, etc.).
+
+             Does nothing if showRelative=false.
+             -->
+        <attr name="relativeTimeUnitDisplayLength">
+            <!-- The time unit will be shown as a short as possible (1 character if possible). -->
+            <enum name="shortest" value="0" />
+            <!-- The time unit will be shortened to a medium length (2-3 characters in general). -->
+            <enum name="medium" value="1" />
+        </attr>
     </declare-styleable>
 
     <declare-styleable name="ResolverDrawerLayout_LayoutParams">
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index a2b7de1..45d0c90 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -815,6 +815,11 @@
          we rely on gravity to determine the effective orientation. -->
     <bool name="config_deskDockEnablesAccelerometer">true</bool>
 
+    <!-- Control for allowing the dock rotation functionality before provision like
+         when the SetupWizard is being shown to the user. This defaults to false to
+         preserve existing behavior. -->
+    <bool name="config_allowDockBeforeProvision">false</bool>
+
     <!-- Car dock behavior -->
 
     <!-- The number of degrees to rotate the display when the device is in a car dock.
@@ -7208,10 +7213,6 @@
          screen. -->
     <bool name="config_dragToMaximizeInDesktopMode">false</bool>
 
-    <!-- Whether showing the app handle is supported on this device.
-         If config_isDesktopModeSupported, then this has no effect -->
-    <bool name="config_enableAppHandle">false</bool>
-
     <!-- Frame rate compatibility value for Wallpaper
          FRAME_RATE_COMPATIBILITY_MIN (102) is used by default for lower power consumption -->
     <integer name="config_wallpaperFrameRateCompatibility">102</integer>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index d498b91..cfc3ddc 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3135,6 +3135,86 @@
         in <xliff:g id="count">%d</xliff:g>y
     </string>
 
+    <!-- Phrase describing a time duration using minutes that is as short as possible, preferrably one character. This version should be a past point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=14] -->
+    <string name="duration_minutes_shortest_past">
+        <xliff:g id="count">%d</xliff:g>m ago
+    </string>
+
+    <!-- Phrase describing a time duration using hours that is as short as possible, preferrably one character. This version should be a past point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=14] -->
+    <string name="duration_hours_shortest_past">
+        <xliff:g id="count">%d</xliff:g>h ago
+    </string>
+
+    <!-- Phrase describing a time duration using days that is as short as possible, preferrably one character. This version should be a past point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=14] -->
+    <string name="duration_days_shortest_past">
+        <xliff:g example="1" id="count">%d</xliff:g>d ago
+    </string>
+
+    <!-- Phrase describing a time duration using years that is as short as possible, preferrably one character. This version should be a past point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=14] -->
+    <string name="duration_years_shortest_past">
+        <xliff:g id="count">%d</xliff:g>y ago
+    </string>
+
+    <!-- Phrase describing a time duration using minutes that is a medium length, preferrably two or three characters. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=8] -->
+    <string name="duration_minutes_medium">
+        <xliff:g id="count">%d</xliff:g>min
+    </string>
+
+    <!-- Phrase describing a time duration using hours that is a medium length, preferrably two or three characters. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=8] -->
+    <string name="duration_hours_medium">
+        <xliff:g id="count">%d</xliff:g>hr
+    </string>
+
+    <!-- Phrase describing a time duration using days that is a medium length, preferrably two or three characters. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=8] -->
+    <string name="duration_days_medium">
+       <xliff:g id="count">%d</xliff:g>d
+    </string>
+
+    <!-- Phrase describing a time duration using years that is a medium length, preferrably two or three characters. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=8] -->
+    <string name="duration_years_medium">
+        <xliff:g id="count">%d</xliff:g>yr
+    </string>
+
+    <!-- Phrase describing a time duration using minutes that is a medium length, preferrably two or three characters. This version should be a future point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=18] -->
+    <string name="duration_minutes_medium_future">
+        in <xliff:g id="count">%d</xliff:g>min
+    </string>
+
+    <!-- Phrase describing a time duration using hours that is a medium length, preferrably two or three characters. This version should be a future point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=18] -->
+    <string name="duration_hours_medium_future">
+        in <xliff:g id="count">%d</xliff:g>hr
+    </string>
+
+    <!-- Phrase describing a time duration using days that is a medium length, preferrably two or three characters. This version should be a future point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=18] -->
+    <string name="duration_days_medium_future">
+        in <xliff:g example="1" id="count">%d</xliff:g>d
+    </string>
+
+    <!-- Phrase describing a time duration using years that is a medium length, preferrably two or three characters. This version should be a future point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=18] -->
+    <string name="duration_years_medium_future">
+        in <xliff:g id="count">%d</xliff:g>yr
+    </string>
+
+    <!-- Phrase describing a time duration using minutes that is a medium length, preferrably two or three characters. This version should be a past point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=18] -->
+    <string name="duration_minutes_medium_past">
+        <xliff:g id="count">%d</xliff:g>min ago
+    </string>
+
+    <!-- Phrase describing a time duration using hours that is a medium length, preferrably two or three characters. This version should be a past point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=18] -->
+    <string name="duration_hours_medium_past">
+        <xliff:g id="count">%d</xliff:g>hr ago
+    </string>
+
+    <!-- Phrase describing a time duration using days that is a medium length, preferrably two or three characters. This version should be a past point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=18] -->
+    <string name="duration_days_medium_past">
+        <xliff:g example="1" id="count">%d</xliff:g>d ago
+    </string>
+
+    <!-- Phrase describing a time duration using years that is a medium length, preferrably two or three characters. This version should be a past point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=18] -->
+    <string name="duration_years_medium_past">
+        <xliff:g id="count">%d</xliff:g>yr ago
+    </string>
+
     <!-- Phrase describing a relative time using minutes in the past that is not shown on the screen but used for accessibility. [CHAR LIMIT=NONE] -->
     <string name="duration_minutes_relative">{count, plural,
         =1 {# minute ago}
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 9a51b72..bdf579d 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1797,6 +1797,7 @@
   <java-symbol type="bool" name="config_customUserSwitchUi" />
   <java-symbol type="bool" name="config_canRemoveFirstAccount" />
   <java-symbol type="string" name="config_accountTypeToKeepFirstAccount" />
+  <java-symbol type="bool" name="config_allowDockBeforeProvision" />
   <java-symbol type="bool" name="config_deskDockEnablesAccelerometer" />
   <java-symbol type="bool" name="config_disableMenuKeyInLockScreen" />
   <java-symbol type="bool" name="config_enableCarDockHomeLaunch" />
@@ -3367,6 +3368,23 @@
   <java-symbol type="string" name="duration_hours_shortest_future" />
   <java-symbol type="string" name="duration_days_shortest_future" />
   <java-symbol type="string" name="duration_years_shortest_future" />
+  <java-symbol type="string" name="duration_minutes_shortest_past" />
+  <java-symbol type="string" name="duration_hours_shortest_past" />
+  <java-symbol type="string" name="duration_days_shortest_past" />
+  <java-symbol type="string" name="duration_years_shortest_past" />
+
+  <java-symbol type="string" name="duration_minutes_medium" />
+  <java-symbol type="string" name="duration_hours_medium" />
+  <java-symbol type="string" name="duration_days_medium" />
+  <java-symbol type="string" name="duration_years_medium" />
+  <java-symbol type="string" name="duration_minutes_medium_future" />
+  <java-symbol type="string" name="duration_hours_medium_future" />
+  <java-symbol type="string" name="duration_days_medium_future" />
+  <java-symbol type="string" name="duration_years_medium_future" />
+  <java-symbol type="string" name="duration_minutes_medium_past" />
+  <java-symbol type="string" name="duration_hours_medium_past" />
+  <java-symbol type="string" name="duration_days_medium_past" />
+  <java-symbol type="string" name="duration_years_medium_past" />
 
   <java-symbol type="string" name="duration_minutes_relative" />
   <java-symbol type="string" name="duration_hours_relative" />
@@ -5746,9 +5764,6 @@
        screen. -->
   <java-symbol type="bool" name="config_dragToMaximizeInDesktopMode" />
 
-  <!-- Whether showing the app handle is supported on this device -->
-  <java-symbol type="bool" name="config_enableAppHandle" />
-
   <!-- Frame rate compatibility value for Wallpaper -->
   <java-symbol type="integer" name="config_wallpaperFrameRateCompatibility" />
 
diff --git a/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt b/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt
index c0a9bc2..f9d449c 100644
--- a/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt
+++ b/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt
@@ -18,10 +18,7 @@
 
 import android.platform.test.annotations.Presubmit
 import android.platform.test.annotations.RequiresFlagsEnabled
-import android.platform.test.flag.junit.CheckFlagsRule
 import android.platform.test.flag.junit.DeviceFlagsValueProvider
-import android.platform.test.flag.junit.RavenwoodFlagsValueProvider
-import android.platform.test.ravenwood.RavenwoodRule
 import android.util.SparseArray
 import androidx.core.util.forEach
 import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -47,15 +44,7 @@
 class FontScaleConverterFactoryTest {
 
     @get:Rule
-    val ravenwoodRule: RavenwoodRule = RavenwoodRule.Builder().build()
-
-    @get:Rule
-    val checkFlagsRule: CheckFlagsRule =
-        if (RavenwoodRule.isOnRavenwood()) {
-            RavenwoodFlagsValueProvider.createAllOnCheckFlagsRule()
-        } else {
-            DeviceFlagsValueProvider.createCheckFlagsRule()
-        }
+    val checkFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
 
     private var defaultLookupTables: SparseArray<FontScaleConverter>? = null
 
diff --git a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
index be8ecbe..cfcd53e 100644
--- a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
+++ b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
@@ -33,8 +33,6 @@
 import android.platform.test.annotations.RequiresFlagsEnabled;
 import android.platform.test.flag.junit.CheckFlagsRule;
 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
-import android.platform.test.flag.junit.RavenwoodFlagsValueProvider;
-import android.platform.test.ravenwood.RavenwoodRule;
 import android.util.ArraySet;
 import android.util.DisplayMetrics;
 import android.util.TypedValue;
@@ -65,13 +63,7 @@
     private static final String TEST_LIB = "com.android.frameworks.coretests.bdr_helper_app1";
 
     @Rule
-    public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder().build();
-
-    @Rule
-    public final CheckFlagsRule mCheckFlagsRule =
-            RavenwoodRule.isOnRavenwood()
-                    ? RavenwoodFlagsValueProvider.createAllOnCheckFlagsRule()
-                    : DeviceFlagsValueProvider.createCheckFlagsRule();
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
 
     private ResourcesManager mResourcesManager;
     private Map<Integer, DisplayMetrics> mDisplayMetricsMap;
diff --git a/core/tests/coretests/src/android/widget/DateTimeViewTest.java b/core/tests/coretests/src/android/widget/DateTimeViewTest.java
index a8fd913..be65277 100644
--- a/core/tests/coretests/src/android/widget/DateTimeViewTest.java
+++ b/core/tests/coretests/src/android/widget/DateTimeViewTest.java
@@ -69,6 +69,141 @@
         Assert.assertFalse(dateTimeView.wasLayoutRequested());
     }
 
+    @UiThreadTest
+    @Test
+    public void disambiguationTextMask_none_noPastOrFutureDisambiguationText() {
+        final TestDateTimeView dateTimeView = new TestDateTimeView();
+        dateTimeView.setShowRelativeTime(true);
+        dateTimeView.setRelativeTimeDisambiguationTextMask(0);
+
+        // Minutes
+        dateTimeView.setTime(System.currentTimeMillis() + Duration.ofMinutes(8).toMillis());
+        Assert.assertFalse(dateTimeView.getText().toString().contains("in"));
+
+        dateTimeView.setTime(System.currentTimeMillis() - Duration.ofMinutes(8).toMillis());
+        Assert.assertFalse(dateTimeView.getText().toString().contains("ago"));
+
+        // Hours
+        dateTimeView.setTime(System.currentTimeMillis() + Duration.ofHours(4).toMillis());
+        Assert.assertFalse(dateTimeView.getText().toString().contains("in"));
+
+        dateTimeView.setTime(System.currentTimeMillis() - Duration.ofHours(4).toMillis());
+        Assert.assertFalse(dateTimeView.getText().toString().contains("ago"));
+
+        // Days
+        dateTimeView.setTime(System.currentTimeMillis() + Duration.ofDays(14).toMillis());
+        Assert.assertFalse(dateTimeView.getText().toString().contains("in"));
+
+        dateTimeView.setTime(System.currentTimeMillis() - Duration.ofDays(14).toMillis());
+        Assert.assertFalse(dateTimeView.getText().toString().contains("ago"));
+
+        // Years
+        dateTimeView.setTime(System.currentTimeMillis() + Duration.ofDays(400).toMillis());
+        Assert.assertFalse(dateTimeView.getText().toString().contains("in"));
+
+        dateTimeView.setTime(System.currentTimeMillis() - Duration.ofDays(400).toMillis());
+        Assert.assertFalse(dateTimeView.getText().toString().contains("ago"));
+    }
+
+    @UiThreadTest
+    @Test
+    public void disambiguationTextMask_bothPastAndFuture_usesPastAndFutureDisambiguationText() {
+        final TestDateTimeView dateTimeView = new TestDateTimeView();
+        dateTimeView.setShowRelativeTime(true);
+        dateTimeView.setRelativeTimeDisambiguationTextMask(
+                DateTimeView.DISAMBIGUATION_TEXT_PAST | DateTimeView.DISAMBIGUATION_TEXT_FUTURE);
+
+        // Minutes
+        dateTimeView.setTime(System.currentTimeMillis() + Duration.ofMinutes(8).toMillis());
+        Assert.assertTrue(dateTimeView.getText().toString().contains("in"));
+
+        dateTimeView.setTime(System.currentTimeMillis() - Duration.ofMinutes(8).toMillis());
+        Assert.assertTrue(dateTimeView.getText().toString().contains("ago"));
+
+        // Hours
+        dateTimeView.setTime(System.currentTimeMillis() + Duration.ofHours(4).toMillis());
+        Assert.assertTrue(dateTimeView.getText().toString().contains("in"));
+
+        dateTimeView.setTime(System.currentTimeMillis() - Duration.ofHours(4).toMillis());
+        Assert.assertTrue(dateTimeView.getText().toString().contains("ago"));
+
+        // Days
+        dateTimeView.setTime(System.currentTimeMillis() + Duration.ofDays(14).toMillis());
+        Assert.assertTrue(dateTimeView.getText().toString().contains("in"));
+
+        dateTimeView.setTime(System.currentTimeMillis() - Duration.ofDays(14).toMillis());
+        Assert.assertTrue(dateTimeView.getText().toString().contains("ago"));
+
+        // Years
+        dateTimeView.setTime(System.currentTimeMillis() + Duration.ofDays(400).toMillis());
+        Assert.assertTrue(dateTimeView.getText().toString().contains("in"));
+
+        dateTimeView.setTime(System.currentTimeMillis() - Duration.ofDays(400).toMillis());
+        Assert.assertTrue(dateTimeView.getText().toString().contains("ago"));
+    }
+
+    @UiThreadTest
+    @Test
+    public void unitDisplayLength_shortest_noMediumText() {
+        final TestDateTimeView dateTimeView = new TestDateTimeView();
+        dateTimeView.setShowRelativeTime(true);
+        dateTimeView.setRelativeTimeUnitDisplayLength(DateTimeView.UNIT_DISPLAY_LENGTH_SHORTEST);
+
+        // Minutes
+        dateTimeView.setTime(System.currentTimeMillis() + Duration.ofMinutes(8).toMillis());
+        Assert.assertFalse(dateTimeView.getText().toString().contains("min"));
+
+        dateTimeView.setTime(System.currentTimeMillis() - Duration.ofMinutes(8).toMillis());
+        Assert.assertFalse(dateTimeView.getText().toString().contains("min"));
+
+        // Hours
+        dateTimeView.setTime(System.currentTimeMillis() + Duration.ofHours(4).toMillis());
+        Assert.assertFalse(dateTimeView.getText().toString().contains("hr"));
+
+        dateTimeView.setTime(System.currentTimeMillis() - Duration.ofHours(4).toMillis());
+        Assert.assertFalse(dateTimeView.getText().toString().contains("hr"));
+
+        // Days excluded because the string is the same for both shortest length and medium length
+
+        // Years
+        dateTimeView.setTime(System.currentTimeMillis() + Duration.ofDays(400).toMillis());
+        Assert.assertFalse(dateTimeView.getText().toString().contains("yr"));
+
+        dateTimeView.setTime(System.currentTimeMillis() - Duration.ofDays(400).toMillis());
+        Assert.assertFalse(dateTimeView.getText().toString().contains("yr"));
+    }
+
+    @UiThreadTest
+    @Test
+    public void unitDisplayLength_medium_usesMediumText() {
+        final TestDateTimeView dateTimeView = new TestDateTimeView();
+        dateTimeView.setShowRelativeTime(true);
+        dateTimeView.setRelativeTimeUnitDisplayLength(DateTimeView.UNIT_DISPLAY_LENGTH_MEDIUM);
+
+        // Minutes
+        dateTimeView.setTime(System.currentTimeMillis() + Duration.ofMinutes(8).toMillis());
+        Assert.assertTrue(dateTimeView.getText().toString().contains("min"));
+
+        dateTimeView.setTime(System.currentTimeMillis() - Duration.ofMinutes(8).toMillis());
+        Assert.assertTrue(dateTimeView.getText().toString().contains("min"));
+
+        // Hours
+        dateTimeView.setTime(System.currentTimeMillis() + Duration.ofHours(4).toMillis());
+        Assert.assertTrue(dateTimeView.getText().toString().contains("hr"));
+
+        dateTimeView.setTime(System.currentTimeMillis() - Duration.ofHours(4).toMillis());
+        Assert.assertTrue(dateTimeView.getText().toString().contains("hr"));
+
+        // Days excluded because the string is the same for both shortest length and medium length
+
+        // Years
+        dateTimeView.setTime(System.currentTimeMillis() + Duration.ofDays(400).toMillis());
+        Assert.assertTrue(dateTimeView.getText().toString().contains("yr"));
+
+        dateTimeView.setTime(System.currentTimeMillis() - Duration.ofDays(400).toMillis());
+        Assert.assertTrue(dateTimeView.getText().toString().contains("yr"));
+    }
+
     private static class TestDateTimeView extends DateTimeView {
         private boolean mRequestedLayout = false;
 
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
index a6466c5..74b4de1 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
@@ -63,8 +63,6 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.Vibrator;
-import android.platform.test.annotations.EnableFlags;
-import android.platform.test.flag.junit.SetFlagsRule;
 import android.provider.Settings;
 import android.speech.tts.TextToSpeech;
 import android.speech.tts.Voice;
@@ -73,7 +71,6 @@
 import android.view.Window;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.Flags;
 import android.view.accessibility.IAccessibilityManager;
 import android.widget.Toast;
 
@@ -86,7 +83,6 @@
 
 import org.junit.AfterClass;
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -104,8 +100,6 @@
 
 @RunWith(AndroidJUnit4.class)
 public class AccessibilityShortcutControllerTest {
-    @Rule
-    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
     private static final String SERVICE_NAME_STRING = "fake.package/fake.service.name";
     private static final CharSequence PACKAGE_NAME_STRING = "Service name";
     private static final String SERVICE_NAME_SUMMARY = "Summary";
@@ -535,7 +529,6 @@
     }
 
     @Test
-    @EnableFlags(Flags.FLAG_RESTORE_A11Y_SHORTCUT_TARGET_SERVICE)
     public void testOnAccessibilityShortcut_settingNull_dialogShown_enablesDefaultShortcut()
             throws Exception {
         configureDefaultAccessibilityService();
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/dialog/AccessibilityServiceWarningTest.java b/core/tests/coretests/src/com/android/internal/accessibility/dialog/AccessibilityServiceWarningTest.java
index 8e906fd..478cef8 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/dialog/AccessibilityServiceWarningTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/dialog/AccessibilityServiceWarningTest.java
@@ -25,8 +25,6 @@
 import android.app.AlertDialog;
 import android.content.Context;
 import android.os.RemoteException;
-import android.platform.test.annotations.RequiresFlagsDisabled;
-import android.platform.test.annotations.RequiresFlagsEnabled;
 import android.platform.test.flag.junit.CheckFlagsRule;
 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.testing.AndroidTestingRunner;
@@ -35,7 +33,6 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.Window;
-import android.view.accessibility.Flags;
 import android.widget.TextView;
 
 import androidx.test.platform.app.InstrumentationRegistry;
@@ -92,19 +89,7 @@
     }
 
     @Test
-    @RequiresFlagsDisabled(Flags.FLAG_WARNING_USE_DEFAULT_DIALOG_TYPE)
-    public void createAccessibilityServiceWarningDialog_hasExpectedWindowParams_isSystemDialog() {
-        createAccessibilityServiceWarningDialog_hasExpectedWindowParams(true);
-    }
-
-    @Test
-    @RequiresFlagsEnabled(Flags.FLAG_WARNING_USE_DEFAULT_DIALOG_TYPE)
     public void createAccessibilityServiceWarningDialog_hasExpectedWindowParams_notSystemDialog() {
-        createAccessibilityServiceWarningDialog_hasExpectedWindowParams(false);
-    }
-
-    private void createAccessibilityServiceWarningDialog_hasExpectedWindowParams(
-            boolean expectSystemDialog) {
         final AlertDialog dialog =
                 AccessibilityServiceWarning.createAccessibilityServiceWarningDialog(
                         mContext,
@@ -116,11 +101,7 @@
         expect.that(dialogWindow.getAttributes().privateFlags
                 & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS).isEqualTo(
                 SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
-        if (expectSystemDialog) {
-            expect.that(dialogWindow.getAttributes().type).isEqualTo(TYPE_SYSTEM_DIALOG);
-        } else {
-            expect.that(dialogWindow.getAttributes().type).isNotEqualTo(TYPE_SYSTEM_DIALOG);
-        }
+        expect.that(dialogWindow.getAttributes().type).isNotEqualTo(TYPE_SYSTEM_DIALOG);
     }
 
     @Test
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 897fc54..a26f5e3 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -514,7 +514,6 @@
         <permission name="android.permission.RENOUNCE_PERMISSIONS" />
         <permission name="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS" />
         <permission name="android.permission.GET_PROCESS_STATE_AND_OOM_SCORE" />
-        <permission name="android.permission.READ_DROPBOX_DATA" />
         <permission name="android.permission.READ_LOGS" />
         <permission name="android.permission.BRIGHTNESS_SLIDER_USAGE" />
         <permission name="android.permission.ACCESS_AMBIENT_LIGHT_STATS" />
diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java
index 073307c..d010c52 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -301,10 +301,7 @@
      *
      * @param bounds Returns the computed bounds of the path's control points.
      * @param exact This parameter is no longer used.
-     *
-     * @deprecated use computeBounds(RectF) instead
      */
-    @Deprecated
     @SuppressWarnings({"UnusedDeclaration"})
     public void computeBounds(@NonNull RectF bounds, boolean exact) {
         computeBounds(bounds);
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt
index 5f42bb1..36acf66 100644
--- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt
@@ -31,7 +31,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import androidx.test.platform.app.InstrumentationRegistry
-import com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn
 import com.android.internal.logging.testing.UiEventLoggerFake
 import com.android.internal.protolog.ProtoLog
 import com.android.launcher3.icons.BubbleIconFactory
@@ -52,6 +51,7 @@
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.Mockito
 import org.mockito.kotlin.mock
 import org.mockito.kotlin.verify
 import java.util.concurrent.Semaphore
@@ -355,7 +355,7 @@
 
     @Test
     fun removeFromWindow_stopMonitoringSwipeUpGesture() {
-        spyOn(bubbleStackView)
+        bubbleStackView = Mockito.spy(bubbleStackView)
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
             // No way to add to window in the test environment right now so just pretend
             bubbleStackView.onDetachedFromWindow()
diff --git a/libs/WindowManager/Shell/shared/Android.bp b/libs/WindowManager/Shell/shared/Android.bp
index 5113d98..5bbda95 100644
--- a/libs/WindowManager/Shell/shared/Android.bp
+++ b/libs/WindowManager/Shell/shared/Android.bp
@@ -26,6 +26,7 @@
     name: "wm_shell-shared-utils",
     srcs: [
         "src/com/android/wm/shell/shared/TransitionUtil.java",
+        "src/com/android/wm/shell/shared/Utils.java",
     ],
 }
 
@@ -71,6 +72,7 @@
     srcs: [
         "**/desktopmode/*.java",
         "**/desktopmode/*.kt",
+        ":wm_shell-shared-utils",
     ],
     static_libs: [
         "com.android.window.flags.window-aconfig-java",
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/ShellSharedConstants.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/ShellSharedConstants.java
index 8f7a2e5..01d2201 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/ShellSharedConstants.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/ShellSharedConstants.java
@@ -20,29 +20,6 @@
  * General shell-related constants that are shared with users of the library.
  */
 public class ShellSharedConstants {
-    // See IPip.aidl
-    public static final String KEY_EXTRA_SHELL_PIP = "extra_shell_pip";
-    // See IBubbles.aidl
-    public static final String KEY_EXTRA_SHELL_BUBBLES = "extra_shell_bubbles";
-    // See ISplitScreen.aidl
-    public static final String KEY_EXTRA_SHELL_SPLIT_SCREEN = "extra_shell_split_screen";
-    // See IOneHanded.aidl
-    public static final String KEY_EXTRA_SHELL_ONE_HANDED = "extra_shell_one_handed";
-    // See IShellTransitions.aidl
-    public static final String KEY_EXTRA_SHELL_SHELL_TRANSITIONS =
-            "extra_shell_shell_transitions";
-    // See IStartingWindow.aidl
-    public static final String KEY_EXTRA_SHELL_STARTING_WINDOW =
-            "extra_shell_starting_window";
-    // See IRecentTasks.aidl
-    public static final String KEY_EXTRA_SHELL_RECENT_TASKS = "extra_shell_recent_tasks";
-    // See IBackAnimation.aidl
-    public static final String KEY_EXTRA_SHELL_BACK_ANIMATION = "extra_shell_back_animation";
-    // See IDesktopMode.aidl
-    public static final String KEY_EXTRA_SHELL_DESKTOP_MODE = "extra_shell_desktop_mode";
-    // See IDragAndDrop.aidl
-    public static final String KEY_EXTRA_SHELL_DRAG_AND_DROP = "extra_shell_drag_and_drop";
-    // See IRecentsAnimationController.aidl
     public static final String KEY_EXTRA_SHELL_CAN_HAND_OFF_ANIMATION =
             "extra_shell_can_hand_off_animation";
 }
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/Utils.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/Utils.java
new file mode 100644
index 0000000..f5e6ddd
--- /dev/null
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/Utils.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.shared;
+
+import android.annotation.NonNull;
+
+import java.util.function.Supplier;
+
+/**
+ * This class provides generic utility methods and classes for shell
+ */
+public class Utils {
+
+    /**
+     * Lazily returns object from a supplier with caching
+     * @param <T> type of object to get
+     */
+    public static class Lazy<T> {
+        private T mInstance;
+
+        /**
+         * @param supplier the supplier that defines the return value if not defined already
+         * @return the cached value or the value from the supplier
+         */
+        public final T get(@NonNull Supplier<T> supplier) {
+            if (mInstance == null) {
+                mInstance = supplier.get();
+            }
+            return mInstance;
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
index 04c17e5..4c6ef93 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
@@ -16,14 +16,19 @@
 
 package com.android.wm.shell.shared.desktopmode;
 
+import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY;
+import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY;
+
 import android.annotation.NonNull;
 import android.content.Context;
+import android.hardware.devicestate.DeviceStateManager;
 import android.os.SystemProperties;
 import android.window.DesktopModeFlags;
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.window.flags.Flags;
+import com.android.wm.shell.shared.Utils.Lazy;
 
 import java.io.PrintWriter;
 
@@ -35,6 +40,8 @@
 
     private static final String TAG = "DesktopModeStatus";
 
+    private static Lazy<Boolean> sIsFoldableDevice = new Lazy<>();
+
     /**
      * Flag to indicate whether task resizing is veiled.
      */
@@ -195,8 +202,7 @@
      * necessarily enabling desktop mode
      */
     public static boolean overridesShowAppHandle(@NonNull Context context) {
-        return Flags.showAppHandleLargeScreens()
-                && context.getResources().getBoolean(R.bool.config_enableAppHandle);
+        return Flags.showAppHandleLargeScreens() && isDeviceFoldable(context);
     }
 
     /**
@@ -244,6 +250,17 @@
     }
 
     /**
+     * @return {@code true} if this is a foldable device
+     */
+    private static boolean isDeviceFoldable(@NonNull Context context) {
+        return sIsFoldableDevice.get(() -> context.getSystemService(DeviceStateManager.class)
+                .getSupportedDeviceStates().stream().anyMatch(state ->
+                        state.hasProperty(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY)
+                                || state.hasProperty(
+                                        PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY)));
+    }
+
+    /**
      * Return {@code true} if a display should enter desktop mode by default when the windowing mode
      * of the display's root [TaskDisplayArea] is set to WINDOWING_MODE_FREEFORM.
      */
@@ -283,6 +300,6 @@
         pw.println(maxTaskLimitHandle == null ? "null" : maxTaskLimitHandle.getInt(/* def= */ -1));
 
         pw.print(innerPrefix); pw.print("showAppHandle config override=");
-        pw.print(context.getResources().getBoolean(R.bool.config_enableAppHandle));
+        pw.print(overridesShowAppHandle(context));
     }
 }
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 d59f66e..c024840 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
@@ -32,7 +32,6 @@
 import static com.android.window.flags.Flags.predictiveBackSystemAnims;
 import static com.android.window.flags.Flags.unifyBackNavigationTransition;
 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW;
-import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_BACK_ANIMATION;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -308,7 +307,7 @@
         setupAnimationDeveloperSettingsObserver(mContentResolver, mBgHandler);
         updateEnableAnimationFromFlags();
         createAdapter();
-        mShellController.addExternalInterface(KEY_EXTRA_SHELL_BACK_ANIMATION,
+        mShellController.addExternalInterface(IBackAnimation.DESCRIPTOR,
                 this::createExternalInterface, this);
         mShellCommandHandler.addDumpCallback(this::dump, this);
         mShellController.addConfigurationChangeListener(this);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 3b53c3f..bec73a1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -35,7 +35,6 @@
 import static com.android.wm.shell.bubbles.Bubbles.DISMISS_SHORTCUT_REMOVED;
 import static com.android.wm.shell.bubbles.Bubbles.DISMISS_USER_CHANGED;
 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES;
-import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_BUBBLES;
 
 import android.annotation.BinderThread;
 import android.annotation.NonNull;
@@ -522,7 +521,7 @@
         }
 
         mShellController.addConfigurationChangeListener(this);
-        mShellController.addExternalInterface(KEY_EXTRA_SHELL_BUBBLES,
+        mShellController.addExternalInterface(IBubbles.DESCRIPTOR,
                 this::createExternalInterface, this);
         mShellCommandHandler.addDumpCallback(this::dump, this);
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt
index 71318cf..1ddb834 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt
@@ -65,7 +65,9 @@
             KeyGestureEvent.KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY -> {
                 logV("Key gesture MOVE_TO_NEXT_DISPLAY is handled")
                 getGloballyFocusedFreeformTask()?.let {
-                    desktopTasksController.get().moveToNextDisplay(it.taskId)
+                    mainExecutor.execute {
+                        desktopTasksController.get().moveToNextDisplay(it.taskId)
+                    }
                 }
                 return true
             }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
index e187d2c..bccb609 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
@@ -333,7 +333,9 @@
      */
     private fun addOrMoveFreeformTaskToTop(displayId: Int, taskId: Int) {
         logD("Add or move task to top: display=%d taskId=%d", taskId, displayId)
-        desktopTaskDataByDisplayId[displayId]?.freeformTasksInZOrder?.remove(taskId)
+        desktopTaskDataByDisplayId.forEach { _, value ->
+            value.freeformTasksInZOrder.remove(taskId)
+        }
         desktopTaskDataByDisplayId.getOrCreate(displayId).freeformTasksInZOrder.add(0, taskId)
         // Unminimize the task if it is minimized.
         unminimizeTask(displayId, taskId)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index c16c805..7bb7242 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -104,7 +104,6 @@
 import com.android.wm.shell.recents.RecentsTransitionStateListener
 import com.android.wm.shell.recents.RecentsTransitionStateListener.RecentsTransitionState
 import com.android.wm.shell.recents.RecentsTransitionStateListener.TRANSITION_STATE_NOT_RUNNING
-import com.android.wm.shell.shared.ShellSharedConstants
 import com.android.wm.shell.shared.TransitionUtil
 import com.android.wm.shell.shared.annotations.ExternalThread
 import com.android.wm.shell.shared.annotations.ShellMainThread
@@ -237,7 +236,7 @@
         shellCommandHandler.addDumpCallback(this::dump, this)
         shellCommandHandler.addCommandCallback("desktopmode", desktopModeShellCommandHandler, this)
         shellController.addExternalInterface(
-            ShellSharedConstants.KEY_EXTRA_SHELL_DESKTOP_MODE,
+            IDesktopMode.DESCRIPTOR,
             { createExternalInterface() },
             this,
         )
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
index 22e8dc1..491b577 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
@@ -31,8 +31,6 @@
 import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 
-import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_DRAG_AND_DROP;
-
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
 import android.app.PendingIntent;
@@ -167,7 +165,7 @@
         mMainExecutor.executeDelayed(() -> {
             mDisplayController.addDisplayWindowListener(this);
         }, 0);
-        mShellController.addExternalInterface(KEY_EXTRA_SHELL_DRAG_AND_DROP,
+        mShellController.addExternalInterface(IDragAndDrop.DESCRIPTOR,
                 this::createExternalInterface, this);
         mShellTaskOrganizer.addTaskVanishedListener(this);
         mShellCommandHandler.addDumpCallback(this::dump, this);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
index 15472eb..8625202 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
@@ -23,7 +23,6 @@
 import static com.android.wm.shell.onehanded.OneHandedState.STATE_ENTERING;
 import static com.android.wm.shell.onehanded.OneHandedState.STATE_EXITING;
 import static com.android.wm.shell.onehanded.OneHandedState.STATE_NONE;
-import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_ONE_HANDED;
 
 import android.annotation.BinderThread;
 import android.content.ComponentName;
@@ -298,7 +297,7 @@
         mShellController.addConfigurationChangeListener(this);
         mShellController.addKeyguardChangeListener(this);
         mShellController.addUserChangeListener(this);
-        mShellController.addExternalInterface(KEY_EXTRA_SHELL_ONE_HANDED,
+        mShellController.addExternalInterface(IOneHanded.DESCRIPTOR,
                 this::createExternalInterface, this);
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/performance/PerfHintController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/performance/PerfHintController.kt
index f7977f8..c655d86 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/performance/PerfHintController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/performance/PerfHintController.kt
@@ -45,9 +45,15 @@
     private fun onInit() {
         mShellCommandHandler.addDumpCallback(this::dump, this)
         val perfHintMgr = mContext.getSystemService(PerformanceHintManager::class.java)
-        val adpfSession = perfHintMgr!!.createHintSession(intArrayOf(Process.myTid()),
-                TimeUnit.SECONDS.toNanos(1))
-        hinter.setAdpfSession(adpfSession)
+        if (perfHintMgr != null) {
+            val adpfSession = perfHintMgr.createHintSession(
+                intArrayOf(Process.myTid()),
+                TimeUnit.SECONDS.toNanos(1)
+            )
+            if (adpfSession != null) {
+                hinter.setAdpfSession(adpfSession)
+            }
+        }
     }
 
     fun dump(pw: PrintWriter, prefix: String?) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 588b887..582df48 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -32,7 +32,6 @@
 import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
 import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_USER_RESIZE;
 import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection;
-import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_PIP;
 
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
@@ -727,7 +726,7 @@
         mShellController.addConfigurationChangeListener(this);
         mShellController.addKeyguardChangeListener(this);
         mShellController.addUserChangeListener(this);
-        mShellController.addExternalInterface(KEY_EXTRA_SHELL_PIP,
+        mShellController.addExternalInterface(IPip.DESCRIPTOR,
                 this::createExternalInterface, this);
     }
 
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 2c5d346..19428ee 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
@@ -20,8 +20,6 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
 
-import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_PIP;
-
 import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.PictureInPictureParams;
@@ -213,7 +211,7 @@
                 });
 
         // Allow other outside processes to bind to PiP controller using the key below.
-        mShellController.addExternalInterface(KEY_EXTRA_SHELL_PIP,
+        mShellController.addExternalInterface(IPip.DESCRIPTOR,
                 this::createExternalInterface, this);
         mShellController.addConfigurationChangeListener(this);
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index 441f967..b922cd0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -24,7 +24,6 @@
 import static com.android.wm.shell.Flags.enableShellTopTaskTracking;
 import static com.android.wm.shell.desktopmode.DesktopWallpaperActivity.isWallpaperTask;
 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_OBSERVER;
-import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_RECENT_TASKS;
 
 import android.Manifest;
 import android.annotation.RequiresPermission;
@@ -181,7 +180,7 @@
 
     @RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
     void onInit() {
-        mShellController.addExternalInterface(KEY_EXTRA_SHELL_RECENT_TASKS,
+        mShellController.addExternalInterface(IRecentTasks.DESCRIPTOR,
                 this::createExternalInterface, this);
         mShellCommandHandler.addDumpCallback(this::dump, this);
         mUserId = ActivityManager.getCurrentUser();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
index 032dac9..37d5878 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
@@ -1317,9 +1317,6 @@
                 // otherwise a new transition will notify the relevant observers
                 if (returningToApp && allAppsAreTranslucent(mPausingTasks)) {
                     mHomeTransitionObserver.notifyHomeVisibilityChanged(true);
-                } else if (!toHome && mState == STATE_NEW_TASK
-                        && allAppsAreTranslucent(mOpeningTasks)) {
-                    // We are opening a translucent app. Launcher is still visible so we do nothing.
                 } else if (!toHome) {
                     // For some transitions, we may have notified home activity that it became
                     // visible. We need to notify the observer that we are no longer going home.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index fc757ef..a368245 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -32,7 +32,6 @@
 import static com.android.wm.shell.common.split.SplitScreenUtils.reverseSplitPosition;
 import static com.android.wm.shell.common.split.SplitScreenUtils.splitFailureMessage;
 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN;
-import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_SPLIT_SCREEN;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.KEY_EXTRA_WIDGET_INTENT;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_0;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_INDEX_1;
@@ -282,7 +281,7 @@
         mShellCommandHandler.addCommandCallback("splitscreen", mSplitScreenShellCommandHandler,
                 this);
         mShellController.addKeyguardChangeListener(this);
-        mShellController.addExternalInterface(KEY_EXTRA_SHELL_SPLIT_SCREEN,
+        mShellController.addExternalInterface(ISplitScreen.DESCRIPTOR,
                 this::createExternalInterface, this);
         if (mStageCoordinator == null) {
             // TODO: Multi-display
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
index 7cb8e8a..72bad41 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
@@ -23,8 +23,6 @@
 import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN;
 import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_WINDOWLESS;
 
-import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_STARTING_WINDOW;
-
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.TaskInfo;
 import android.content.Context;
@@ -119,7 +117,7 @@
 
     private void onInit() {
         mShellTaskOrganizer.initStartingWindow(this);
-        mShellController.addExternalInterface(KEY_EXTRA_SHELL_STARTING_WINDOW,
+        mShellController.addExternalInterface(IStartingWindow.DESCRIPTOR,
                 this::createExternalInterface, this);
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index 3f19149..611f3e0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -41,7 +41,6 @@
 import static com.android.systemui.shared.Flags.returnAnimationFrameworkLongLived;
 import static com.android.window.flags.Flags.ensureWallpaperInTransitions;
 import static com.android.window.flags.Flags.migratePredictiveBackTransition;
-import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_SHELL_TRANSITIONS;
 import static com.android.wm.shell.shared.TransitionUtil.isClosingType;
 import static com.android.wm.shell.shared.TransitionUtil.isOpeningType;
 
@@ -373,7 +372,7 @@
         if (Transitions.ENABLE_SHELL_TRANSITIONS) {
             mOrganizer.shareTransactionQueue();
         }
-        mShellController.addExternalInterface(KEY_EXTRA_SHELL_SHELL_TRANSITIONS,
+        mShellController.addExternalInterface(IShellTransitions.DESCRIPTOR,
                 this::createExternalInterface, this);
 
         ContentResolver resolver = mContext.getContentResolver();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index bd84ccc..e7985de 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -543,9 +543,9 @@
 
         final boolean inFullImmersive = mDesktopUserRepositories.getProfile(taskInfo.userId)
                 .isTaskInFullImmersiveState(taskInfo.taskId);
-        updateRelayoutParams(mRelayoutParams, mContext, taskInfo, applyStartTransactionOnDraw,
-                shouldSetTaskVisibilityPositionAndCrop, mIsStatusBarVisible,
-                mIsKeyguardVisibleAndOccluded, inFullImmersive,
+        updateRelayoutParams(mRelayoutParams, mContext, taskInfo, mSplitScreenController,
+                applyStartTransactionOnDraw, shouldSetTaskVisibilityPositionAndCrop,
+                mIsStatusBarVisible, mIsKeyguardVisibleAndOccluded, inFullImmersive,
                 mDisplayController.getInsetsState(taskInfo.displayId), hasGlobalFocus,
                 displayExclusionRegion);
 
@@ -877,6 +877,7 @@
             RelayoutParams relayoutParams,
             Context context,
             ActivityManager.RunningTaskInfo taskInfo,
+            SplitScreenController splitScreenController,
             boolean applyStartTransactionOnDraw,
             boolean shouldSetTaskVisibilityPositionAndCrop,
             boolean isStatusBarVisible,
@@ -918,7 +919,10 @@
                     || (isStatusBarVisible && !isKeyguardVisibleAndOccluded);
         }
         relayoutParams.mIsCaptionVisible = showCaption;
-        relayoutParams.mIsInsetSource = isAppHeader && !inFullImmersiveMode;
+        final boolean isBottomSplit = !splitScreenController.isLeftRightSplit()
+                && splitScreenController.getSplitPosition(taskInfo.taskId)
+                == SPLIT_POSITION_BOTTOM_OR_RIGHT;
+        relayoutParams.mIsInsetSource = (isAppHeader && !inFullImmersiveMode) || isBottomSplit;
         if (isAppHeader) {
             if (TaskInfoKt.isTransparentCaptionBarAppearance(taskInfo)) {
                 // The app is requesting to customize the caption bar, which means input on
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt
index f6d2cc0..f4f60d7 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt
@@ -272,9 +272,11 @@
                         TaggedCujTransitionMatcher(associatedTransitionRequired = false)
                     )
                     .build(),
-                assertions = AssertionTemplates.DESKTOP_MODE_APP_VISIBILITY_ASSERTIONS +
-                        listOf(AppWindowCoversLeftHalfScreenAtEnd(DESKTOP_MODE_APP))
-                            .associateBy({ it }, { AssertionInvocationGroup.BLOCKING }),
+                assertions = AssertionTemplates.DESKTOP_MODE_APP_VISIBILITY_ASSERTIONS + listOf(
+                    AppWindowCoversLeftHalfScreenAtEnd(
+                        DESKTOP_MODE_APP, SNAP_WINDOW_MAX_DIFF_THRESHOLD_RATIO
+                    )
+                ).associateBy({ it }, { AssertionInvocationGroup.BLOCKING }),
             )
 
         val SNAP_RESIZE_RIGHT_WITH_DRAG =
@@ -287,9 +289,11 @@
                         TaggedCujTransitionMatcher(associatedTransitionRequired = false)
                     )
                     .build(),
-                assertions = AssertionTemplates.DESKTOP_MODE_APP_VISIBILITY_ASSERTIONS +
-                        listOf(AppWindowCoversRightHalfScreenAtEnd(DESKTOP_MODE_APP))
-                            .associateBy({ it }, { AssertionInvocationGroup.BLOCKING }),
+                assertions = AssertionTemplates.DESKTOP_MODE_APP_VISIBILITY_ASSERTIONS + listOf(
+                    AppWindowCoversRightHalfScreenAtEnd(
+                        DESKTOP_MODE_APP, SNAP_WINDOW_MAX_DIFF_THRESHOLD_RATIO
+                    )
+                ).associateBy({ it }, { AssertionInvocationGroup.BLOCKING }),
             )
 
         val SNAP_RESIZE_WITH_DRAG_NON_RESIZABLE =
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 c3e3965..f22e2a5 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
@@ -86,7 +86,6 @@
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
 import com.android.wm.shell.ShellTestCase;
 import com.android.wm.shell.TestShellExecutor;
-import com.android.wm.shell.shared.ShellSharedConstants;
 import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellController;
 import com.android.wm.shell.sysui.ShellInit;
@@ -254,7 +253,7 @@
     @Test
     public void instantiateController_addExternalInterface() {
         verify(mShellController, times(1)).addExternalInterface(
-                eq(ShellSharedConstants.KEY_EXTRA_SHELL_BACK_ANIMATION), any(), any());
+                eq(IBackAnimation.DESCRIPTOR), any(), any());
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt
index 0bc1fb9..e57ae2a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt
@@ -183,6 +183,7 @@
             .setModifierState(KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON)
             .build()
         val result = keyGestureEventHandler.handleKeyGestureEvent(event, null)
+        testExecutor.flushAll()
 
         assertThat(result).isTrue()
         verify(desktopTasksController).moveToNextDisplay(task.taskId)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt
index 9059d7d..344140d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt
@@ -149,6 +149,14 @@
     }
 
     @Test
+    fun addTask_multipleDisplays_moveToAnotherDisplay() {
+        repo.addTask(DEFAULT_DISPLAY, taskId = 1, isVisible = true)
+        repo.addTask(SECOND_DISPLAY, taskId = 1, isVisible = true)
+        assertThat(repo.getFreeformTasksInZOrder(DEFAULT_DISPLAY)).isEmpty()
+        assertThat(repo.getFreeformTasksInZOrder(SECOND_DISPLAY)).containsExactly(1)
+    }
+
+    @Test
     fun removeActiveTask_notifiesActiveTaskListener() {
         val listener = TestListener()
         repo.addActiveTaskListener(listener)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopUserRepositoriesTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopUserRepositoriesTest.kt
new file mode 100644
index 0000000..5767df4
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopUserRepositoriesTest.kt
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.desktopmode
+
+import android.app.ActivityManager
+import android.content.pm.UserInfo
+import android.os.UserManager
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
+import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
+import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_HSUM
+import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.common.ShellExecutor
+import com.android.wm.shell.desktopmode.persistence.DesktopPersistentRepository
+import com.android.wm.shell.desktopmode.persistence.DesktopRepositoryInitializer
+import com.android.wm.shell.sysui.ShellInit
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.setMain
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.spy
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
+import org.mockito.quality.Strictness
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@ExperimentalCoroutinesApi
+class DesktopUserRepositoriesTest : ShellTestCase() {
+    @get:Rule val setFlagsRule = SetFlagsRule()
+
+    private lateinit var userRepositories: DesktopUserRepositories
+    private lateinit var shellInit: ShellInit
+    private lateinit var datastoreScope: CoroutineScope
+    private lateinit var mockitoSession: StaticMockitoSession
+
+    private val testExecutor = mock<ShellExecutor>()
+    private val persistentRepository = mock<DesktopPersistentRepository>()
+    private val repositoryInitializer = mock<DesktopRepositoryInitializer>()
+    private val userManager = mock<UserManager>()
+
+    @Before
+    fun setUp() {
+        Dispatchers.setMain(StandardTestDispatcher())
+        mockitoSession =
+            mockitoSession()
+                .strictness(Strictness.LENIENT)
+                .spyStatic(ActivityManager::class.java)
+                .startMocking()
+        doReturn(USER_ID_1).`when` { ActivityManager.getCurrentUser() }
+
+        datastoreScope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob())
+        shellInit = spy(ShellInit(testExecutor))
+
+        val profiles: MutableList<UserInfo> = mutableListOf(
+            UserInfo(USER_ID_1, "User 1", 0),
+            UserInfo(PROFILE_ID_2, "Profile 2", 0))
+        whenever(userManager.getProfiles(USER_ID_1)).thenReturn(profiles)
+
+        userRepositories = DesktopUserRepositories(
+            context, shellInit, persistentRepository, repositoryInitializer, datastoreScope,
+                userManager)
+    }
+
+    @After
+    fun tearDown() {
+        mockitoSession.finishMocking()
+        datastoreScope.cancel()
+    }
+
+    @Test
+    fun getCurrent_returnsUserId() {
+        val desktopRepository: DesktopRepository = userRepositories.current
+
+        assertThat(desktopRepository.userId).isEqualTo(USER_ID_1)
+    }
+
+    @Test
+    @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_HSUM)
+    fun getProfile_flagEnabled_returnsProfileGroupId() {
+        val desktopRepository: DesktopRepository = userRepositories.getProfile(PROFILE_ID_2)
+
+        assertThat(desktopRepository.userId).isEqualTo(USER_ID_1)
+    }
+
+    @Test
+    @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_HSUM)
+    fun getProfile_flagDisabled_returnsProfileId() {
+        val desktopRepository: DesktopRepository = userRepositories.getProfile(PROFILE_ID_2)
+
+        assertThat(desktopRepository.userId).isEqualTo(PROFILE_ID_2)
+    }
+
+    private companion object {
+        const val USER_ID_1 = 7
+        const val PROFILE_ID_2 = 5
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
index 7d063a0..256ed41 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
@@ -48,7 +48,6 @@
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.TaskStackListenerImpl;
-import com.android.wm.shell.shared.ShellSharedConstants;
 import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellController;
 import com.android.wm.shell.sysui.ShellInit;
@@ -179,7 +178,7 @@
     @Test
     public void testControllerRegisteresExternalInterface() {
         verify(mMockShellController, times(1)).addExternalInterface(
-                eq(ShellSharedConstants.KEY_EXTRA_SHELL_ONE_HANDED), any(), any());
+                eq(IOneHanded.DESCRIPTOR), any(), any());
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index b123f4d..5ef934c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -58,6 +58,7 @@
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.TabletopModeController;
 import com.android.wm.shell.common.TaskStackListenerImpl;
+import com.android.wm.shell.common.pip.IPip;
 import com.android.wm.shell.common.pip.PhonePipKeepClearAlgorithm;
 import com.android.wm.shell.common.pip.PipAppOpsListener;
 import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
@@ -71,7 +72,6 @@
 import com.android.wm.shell.pip.PipTaskOrganizer;
 import com.android.wm.shell.pip.PipTransitionController;
 import com.android.wm.shell.pip.PipTransitionState;
-import com.android.wm.shell.shared.ShellSharedConstants;
 import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellController;
 import com.android.wm.shell.sysui.ShellInit;
@@ -178,7 +178,7 @@
     @Test
     public void instantiatePipController_registerExternalInterface() {
         verify(mShellController, times(1)).addExternalInterface(
-                eq(ShellSharedConstants.KEY_EXTRA_SHELL_PIP), any(), eq(mPipController));
+                eq(IPip.DESCRIPTOR), any(), eq(mPipController));
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
index 95f371f..c6835b7 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
@@ -26,8 +26,6 @@
 import static com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_PERSISTENCE;
 import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_50_50;
 
-import static com.google.common.truth.Truth.assertThat;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -59,7 +57,6 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Bundle;
-import android.os.UserManager;
 import android.platform.test.annotations.DisableFlags;
 import android.platform.test.annotations.EnableFlags;
 import android.platform.test.flag.junit.SetFlagsRule;
@@ -80,7 +77,6 @@
 import com.android.wm.shell.desktopmode.DesktopUserRepositories;
 import com.android.wm.shell.desktopmode.DesktopWallpaperActivity;
 import com.android.wm.shell.shared.GroupedTaskInfo;
-import com.android.wm.shell.shared.ShellSharedConstants;
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
 import com.android.wm.shell.shared.split.SplitBounds;
 import com.android.wm.shell.sysui.ShellCommandHandler;
@@ -186,7 +182,7 @@
     @Test
     public void instantiateController_addExternalInterface() {
         verify(mShellController, times(1)).addExternalInterface(
-                eq(ShellSharedConstants.KEY_EXTRA_SHELL_RECENT_TASKS), any(), any());
+                eq(IRecentTasks.DESCRIPTOR), any(), any());
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
index 7726c97..bb9703f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
@@ -75,7 +75,6 @@
 import com.android.wm.shell.desktopmode.DesktopTasksController;
 import com.android.wm.shell.draganddrop.DragAndDropController;
 import com.android.wm.shell.recents.RecentTasksController;
-import com.android.wm.shell.shared.ShellSharedConstants;
 import com.android.wm.shell.shared.TransactionPool;
 import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellController;
@@ -180,7 +179,7 @@
         when(mDisplayController.getDisplayLayout(anyInt())).thenReturn(new DisplayLayout());
         mSplitScreenController.onInit();
         verify(mShellController, times(1)).addExternalInterface(
-                eq(ShellSharedConstants.KEY_EXTRA_SHELL_SPLIT_SCREEN), any(), any());
+                eq(ISplitScreen.DESCRIPTOR), any(), any());
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingWindowControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingWindowControllerTests.java
index 7fd1c11..17a5f5c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingWindowControllerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingWindowControllerTests.java
@@ -42,7 +42,6 @@
 import com.android.wm.shell.ShellTestCase;
 import com.android.wm.shell.common.DisplayInsetsController;
 import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.shared.ShellSharedConstants;
 import com.android.wm.shell.shared.TransactionPool;
 import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellController;
@@ -99,7 +98,7 @@
     @Test
     public void instantiateController_addExternalInterface() {
         verify(mShellController, times(1)).addExternalInterface(
-                eq(ShellSharedConstants.KEY_EXTRA_SHELL_STARTING_WINDOW), any(), any());
+                eq(IStartingWindow.DESCRIPTOR), any(), any());
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
index 2442a55..dd645fd 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
@@ -110,7 +110,7 @@
 import com.android.wm.shell.recents.IRecentsAnimationRunner;
 import com.android.wm.shell.recents.RecentTasksController;
 import com.android.wm.shell.recents.RecentsTransitionHandler;
-import com.android.wm.shell.shared.ShellSharedConstants;
+import com.android.wm.shell.shared.IShellTransitions;
 import com.android.wm.shell.shared.TransactionPool;
 import com.android.wm.shell.sysui.ShellController;
 import com.android.wm.shell.sysui.ShellInit;
@@ -176,7 +176,7 @@
                 mock(FocusTransitionObserver.class));
         shellInit.init();
         verify(shellController, times(1)).addExternalInterface(
-                eq(ShellSharedConstants.KEY_EXTRA_SHELL_SHELL_TRANSITIONS), any(), any());
+                eq(IShellTransitions.DESCRIPTOR), any(), any());
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenuTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenuTest.kt
index 4403558..e871711 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenuTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenuTest.kt
@@ -35,7 +35,6 @@
 import com.google.common.truth.Truth.assertThat
 import org.junit.After
 import org.junit.Before
-import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -77,7 +76,6 @@
     }
 
     @Test
-    @Ignore("Test is failing internally")
     @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
     fun testShow_forImmersiveTask_usesSystemViewContainer() {
         val task = createFreeformTask()
@@ -110,6 +108,7 @@
         .setToken(MockToken().token())
         .setActivityType(ACTIVITY_TYPE_STANDARD)
         .setWindowingMode(WINDOWING_MODE_FREEFORM)
+        .setUserId(DEFAULT_USER_ID)
         .build()
 
     private companion object {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
index 61f3755..0bef4191 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
@@ -29,6 +29,7 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
 import static com.android.wm.shell.MockSurfaceControlHelper.createMockSurfaceControlTransaction;
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.wm.shell.windowdecor.DesktopModeWindowDecoration.CLOSE_MAXIMIZE_MENU_DELAY_MS;
 import static com.android.wm.shell.windowdecor.WindowDecoration.INVALID_CORNER_RADIUS;
 
@@ -305,7 +306,8 @@
         RelayoutParams relayoutParams = new RelayoutParams();
 
         DesktopModeWindowDecoration.updateRelayoutParams(
-                relayoutParams, mContext, taskInfo, /* applyStartTransactionOnDraw= */ true,
+                relayoutParams, mContext, taskInfo, mMockSplitScreenController,
+                /* applyStartTransactionOnDraw= */ true,
                 /* shouldSetTaskPositionAndCrop */ false,
                 /* isStatusBarVisible */ true,
                 /* isKeyguardVisibleAndOccluded */ false,
@@ -325,7 +327,8 @@
         RelayoutParams relayoutParams = new RelayoutParams();
 
         DesktopModeWindowDecoration.updateRelayoutParams(
-                relayoutParams, mContext, taskInfo, /* applyStartTransactionOnDraw= */ true,
+                relayoutParams, mContext, taskInfo, mMockSplitScreenController,
+                /* applyStartTransactionOnDraw= */ true,
                 /* shouldSetTaskPositionAndCrop */ false,
                 /* isStatusBarVisible */ true,
                 /* isKeyguardVisibleAndOccluded */ false,
@@ -344,7 +347,8 @@
         RelayoutParams relayoutParams = new RelayoutParams();
 
         DesktopModeWindowDecoration.updateRelayoutParams(
-                relayoutParams, mContext, taskInfo, /* applyStartTransactionOnDraw= */ true,
+                relayoutParams, mContext, taskInfo, mMockSplitScreenController,
+                /* applyStartTransactionOnDraw= */ true,
                 /* shouldSetTaskPositionAndCrop */ false,
                 /* isStatusBarVisible */ true,
                 /* isKeyguardVisibleAndOccluded */ false,
@@ -367,6 +371,7 @@
                 relayoutParams,
                 mTestableContext,
                 taskInfo,
+                mMockSplitScreenController,
                 /* applyStartTransactionOnDraw= */ true,
                 /* shouldSetTaskPositionAndCrop */ false,
                 /* isStatusBarVisible */ true,
@@ -390,6 +395,7 @@
                 relayoutParams,
                 mTestableContext,
                 taskInfo,
+                mMockSplitScreenController,
                 /* applyStartTransactionOnDraw= */ true,
                 /* shouldSetTaskPositionAndCrop */ false,
                 /* isStatusBarVisible */ true,
@@ -413,6 +419,7 @@
                 relayoutParams,
                 mTestableContext,
                 taskInfo,
+                mMockSplitScreenController,
                 /* applyStartTransactionOnDraw= */ true,
                 /* shouldSetTaskPositionAndCrop */ false,
                 /* isStatusBarVisible */ true,
@@ -440,6 +447,7 @@
                 relayoutParams,
                 mTestableContext,
                 taskInfo,
+                mMockSplitScreenController,
                 /* applyStartTransactionOnDraw= */ true,
                 /* shouldSetTaskPositionAndCrop */ false,
                 /* isStatusBarVisible */ true,
@@ -468,6 +476,7 @@
                 relayoutParams,
                 mTestableContext,
                 taskInfo,
+                mMockSplitScreenController,
                 /* applyStartTransactionOnDraw= */ true,
                 /* shouldSetTaskPositionAndCrop */ false,
                 /* isStatusBarVisible */ true,
@@ -493,6 +502,7 @@
                 relayoutParams,
                 mTestableContext,
                 taskInfo,
+                mMockSplitScreenController,
                 /* applyStartTransactionOnDraw= */ true,
                 /* shouldSetTaskPositionAndCrop */ false,
                 /* isStatusBarVisible */ true,
@@ -518,6 +528,7 @@
                 relayoutParams,
                 mTestableContext,
                 taskInfo,
+                mMockSplitScreenController,
                 /* applyStartTransactionOnDraw= */ true,
                 /* shouldSetTaskPositionAndCrop */ false,
                 /* isStatusBarVisible */ true,
@@ -542,6 +553,7 @@
                 relayoutParams,
                 mTestableContext,
                 taskInfo,
+                mMockSplitScreenController,
                 /* applyStartTransactionOnDraw= */ true,
                 /* shouldSetTaskPositionAndCrop */ false,
                 /* isStatusBarVisible */ true,
@@ -566,6 +578,7 @@
                 relayoutParams,
                 mTestableContext,
                 taskInfo,
+                mMockSplitScreenController,
                 /* applyStartTransactionOnDraw= */ true,
                 /* shouldSetTaskPositionAndCrop */ false,
                 /* isStatusBarVisible */ true,
@@ -589,6 +602,7 @@
                 relayoutParams,
                 mTestableContext,
                 taskInfo,
+                mMockSplitScreenController,
                 /* applyStartTransactionOnDraw= */ true,
                 /* shouldSetTaskPositionAndCrop */ false,
                 /* isStatusBarVisible */ true,
@@ -612,6 +626,7 @@
                 relayoutParams,
                 mTestableContext,
                 taskInfo,
+                mMockSplitScreenController,
                 /* applyStartTransactionOnDraw= */ true,
                 /* shouldSetTaskPositionAndCrop */ false,
                 /* isStatusBarVisible */ true,
@@ -634,6 +649,7 @@
                 relayoutParams,
                 mTestableContext,
                 taskInfo,
+                mMockSplitScreenController,
                 /* applyStartTransactionOnDraw= */ true,
                 /* shouldSetTaskPositionAndCrop */ false,
                 /* isStatusBarVisible */ true,
@@ -657,6 +673,7 @@
                 relayoutParams,
                 mTestableContext,
                 taskInfo,
+                mMockSplitScreenController,
                 /* applyStartTransactionOnDraw= */ true,
                 /* shouldSetTaskPositionAndCrop */ false,
                 /* isStatusBarVisible */ true,
@@ -680,6 +697,7 @@
                 relayoutParams,
                 mTestableContext,
                 taskInfo,
+                mMockSplitScreenController,
                 /* applyStartTransactionOnDraw= */ true,
                 /* shouldSetTaskPositionAndCrop */ false,
                 /* isStatusBarVisible */ true,
@@ -704,6 +722,7 @@
                 relayoutParams,
                 mTestableContext,
                 taskInfo,
+                mMockSplitScreenController,
                 /* applyStartTransactionOnDraw= */ true,
                 /* shouldSetTaskPositionAndCrop */ false,
                 /* isStatusBarVisible */ true,
@@ -729,6 +748,7 @@
                 relayoutParams,
                 mTestableContext,
                 taskInfo,
+                mMockSplitScreenController,
                 /* applyStartTransactionOnDraw= */ true,
                 /* shouldSetTaskPositionAndCrop */ false,
                 /* isStatusBarVisible */ true,
@@ -752,6 +772,7 @@
                 relayoutParams,
                 mTestableContext,
                 taskInfo,
+                mMockSplitScreenController,
                 /* applyStartTransactionOnDraw= */ true,
                 /* shouldSetTaskPositionAndCrop */ false,
                 /* isStatusBarVisible */ true,
@@ -777,6 +798,7 @@
                 relayoutParams,
                 mTestableContext,
                 taskInfo,
+                mMockSplitScreenController,
                 /* applyStartTransactionOnDraw= */ true,
                 /* shouldSetTaskPositionAndCrop */ false,
                 /* isStatusBarVisible */ true,
@@ -792,6 +814,31 @@
     }
 
     @Test
+    public void updateRelayoutParams_handle_bottomSplitIsInsetSource() {
+        final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
+        final RelayoutParams relayoutParams = new RelayoutParams();
+        when(mMockSplitScreenController.isLeftRightSplit()).thenReturn(false);
+        when(mMockSplitScreenController.getSplitPosition(taskInfo.taskId))
+                .thenReturn(SPLIT_POSITION_BOTTOM_OR_RIGHT);
+
+        DesktopModeWindowDecoration.updateRelayoutParams(
+                relayoutParams,
+                mTestableContext,
+                taskInfo,
+                mMockSplitScreenController,
+                /* applyStartTransactionOnDraw= */ true,
+                /* shouldSetTaskPositionAndCrop */ false,
+                /* isStatusBarVisible */ true,
+                /* isKeyguardVisibleAndOccluded */ false,
+                /* inFullImmersiveMode */ true,
+                new InsetsState(),
+                /* hasGlobalFocus= */ true,
+                mExclusionRegion);
+
+        assertThat(relayoutParams.mIsInsetSource).isTrue();
+    }
+
+    @Test
     @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP)
     public void updateRelayoutParams_header_addsPaddingInFullImmersive() {
         final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true);
@@ -808,6 +855,7 @@
                 relayoutParams,
                 mTestableContext,
                 taskInfo,
+                mMockSplitScreenController,
                 /* applyStartTransactionOnDraw= */ true,
                 /* shouldSetTaskPositionAndCrop */ false,
                 /* isStatusBarVisible */ true,
@@ -832,6 +880,7 @@
                 relayoutParams,
                 mTestableContext,
                 taskInfo,
+                mMockSplitScreenController,
                 /* applyStartTransactionOnDraw= */ true,
                 /* shouldSetTaskPositionAndCrop */ false,
                 /* isStatusBarVisible */ true,
@@ -855,6 +904,7 @@
                 relayoutParams,
                 mTestableContext,
                 taskInfo,
+                mMockSplitScreenController,
                 /* applyStartTransactionOnDraw= */ true,
                 /* shouldSetTaskPositionAndCrop */ false,
                 /* isStatusBarVisible */ false,
@@ -878,6 +928,7 @@
                 relayoutParams,
                 mTestableContext,
                 taskInfo,
+                mMockSplitScreenController,
                 /* applyStartTransactionOnDraw= */ true,
                 /* shouldSetTaskPositionAndCrop */ false,
                 /* isStatusBarVisible */ true,
@@ -900,6 +951,7 @@
                 relayoutParams,
                 mTestableContext,
                 taskInfo,
+                mMockSplitScreenController,
                 /* applyStartTransactionOnDraw= */ true,
                 /* shouldSetTaskPositionAndCrop */ false,
                 /* isStatusBarVisible */ false,
@@ -922,6 +974,7 @@
                 relayoutParams,
                 mTestableContext,
                 taskInfo,
+                mMockSplitScreenController,
                 /* applyStartTransactionOnDraw= */ true,
                 /* shouldSetTaskPositionAndCrop */ false,
                 /* isStatusBarVisible */ true,
@@ -945,6 +998,7 @@
                 relayoutParams,
                 mTestableContext,
                 taskInfo,
+                mMockSplitScreenController,
                 /* applyStartTransactionOnDraw= */ true,
                 /* shouldSetTaskPositionAndCrop */ false,
                 /* isStatusBarVisible */ true,
@@ -960,6 +1014,7 @@
                 relayoutParams,
                 mTestableContext,
                 taskInfo,
+                mMockSplitScreenController,
                 /* applyStartTransactionOnDraw= */ true,
                 /* shouldSetTaskPositionAndCrop */ false,
                 /* isStatusBarVisible */ false,
@@ -983,6 +1038,7 @@
                 relayoutParams,
                 mTestableContext,
                 taskInfo,
+                mMockSplitScreenController,
                 /* applyStartTransactionOnDraw= */ true,
                 /* shouldSetTaskPositionAndCrop */ false,
                 /* isStatusBarVisible */ true,
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
index 49254d1..dbb8914 100644
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -40,20 +40,21 @@
 }
 
 ApkAssetsPtr ApkAssets::Load(const std::string& path, package_property_t flags) {
-  return Load(ZipAssetsProvider::Create(path, flags), flags);
+  return LoadImpl(ZipAssetsProvider::Create(path, flags), flags);
 }
 
 ApkAssetsPtr ApkAssets::LoadFromFd(base::unique_fd fd, const std::string& debug_name,
                                    package_property_t flags, off64_t offset, off64_t len) {
-  return Load(ZipAssetsProvider::Create(std::move(fd), debug_name, offset, len), flags);
+  return LoadImpl(ZipAssetsProvider::Create(std::move(fd), debug_name, offset, len), flags);
 }
 
-ApkAssetsPtr ApkAssets::Load(std::unique_ptr<AssetsProvider> assets, package_property_t flags) {
+ApkAssetsPtr ApkAssets::LoadImpl(std::unique_ptr<AssetsProvider>&& assets,
+                                 package_property_t flags) {
   return LoadImpl(std::move(assets), flags, nullptr /* idmap_asset */, nullptr /* loaded_idmap */);
 }
 
-ApkAssetsPtr ApkAssets::LoadTable(std::unique_ptr<Asset> resources_asset,
-                                  std::unique_ptr<AssetsProvider> assets,
+ApkAssetsPtr ApkAssets::LoadTable(std::unique_ptr<Asset>&& resources_asset,
+                                  std::unique_ptr<AssetsProvider>&& assets,
                                   package_property_t flags) {
   if (resources_asset == nullptr) {
     return {};
@@ -97,10 +98,10 @@
                   std::move(loaded_idmap));
 }
 
-ApkAssetsPtr ApkAssets::LoadImpl(std::unique_ptr<AssetsProvider> assets,
+ApkAssetsPtr ApkAssets::LoadImpl(std::unique_ptr<AssetsProvider>&& assets,
                                  package_property_t property_flags,
-                                 std::unique_ptr<Asset> idmap_asset,
-                                 std::unique_ptr<LoadedIdmap> loaded_idmap) {
+                                 std::unique_ptr<Asset>&& idmap_asset,
+                                 std::unique_ptr<LoadedIdmap>&& loaded_idmap) {
   if (assets == nullptr) {
     return {};
   }
@@ -119,11 +120,11 @@
                   std::move(idmap_asset), std::move(loaded_idmap));
 }
 
-ApkAssetsPtr ApkAssets::LoadImpl(std::unique_ptr<Asset> resources_asset,
-                                 std::unique_ptr<AssetsProvider> assets,
+ApkAssetsPtr ApkAssets::LoadImpl(std::unique_ptr<Asset>&& resources_asset,
+                                 std::unique_ptr<AssetsProvider>&& assets,
                                  package_property_t property_flags,
-                                 std::unique_ptr<Asset> idmap_asset,
-                                 std::unique_ptr<LoadedIdmap> loaded_idmap) {
+                                 std::unique_ptr<Asset>&& idmap_asset,
+                                 std::unique_ptr<LoadedIdmap>&& loaded_idmap) {
   if (assets == nullptr ) {
     return {};
   }
diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h
index 1fa6752..231808b 100644
--- a/libs/androidfw/include/androidfw/ApkAssets.h
+++ b/libs/androidfw/include/androidfw/ApkAssets.h
@@ -47,13 +47,37 @@
                                  package_property_t flags = 0U, off64_t offset = 0,
                                  off64_t len = AssetsProvider::kUnknownLength);
 
+  //
   // Creates an ApkAssets from an AssetProvider.
-  // The ApkAssets will take care of destroying the AssetsProvider when it is destroyed.
-  static ApkAssetsPtr Load(std::unique_ptr<AssetsProvider> assets, package_property_t flags = 0U);
+  // The ApkAssets will take care of destroying the AssetsProvider when it is destroyed;
+  // the original argument is not moved from if loading fails.
+  //
+  // Note: this function takes care of the case when you pass a move(unique_ptr<Derived>)
+  //    that would create a temporary unique_ptr<AssetsProvider> by moving your pointer into
+  //    it before the function call, making it impossible to not move from the parameter
+  //    on loading failure. The two overloads take care of moving the pointer back if needed.
+  //
+
+  template <class T>
+  static ApkAssetsPtr Load(std::unique_ptr<T>&& assets, package_property_t flags = 0U)
+      requires(std::is_same_v<T, AssetsProvider>) {
+    return LoadImpl(std::move(assets), flags);
+  }
+
+  template <class T>
+  static ApkAssetsPtr Load(std::unique_ptr<T>&& assets, package_property_t flags = 0U)
+      requires(!std::is_same_v<T, AssetsProvider> && std::is_base_of_v<AssetsProvider, T>) {
+    std::unique_ptr<AssetsProvider> base_assets(std::move(assets));
+    auto res = LoadImpl(std::move(base_assets), flags);
+    if (!res) {
+      assets.reset(static_cast<T*>(base_assets.release()));
+    }
+    return res;
+  }
 
   // Creates an ApkAssets from the given asset file representing a resources.arsc.
-  static ApkAssetsPtr LoadTable(std::unique_ptr<Asset> resources_asset,
-                                std::unique_ptr<AssetsProvider> assets,
+  static ApkAssetsPtr LoadTable(std::unique_ptr<Asset>&& resources_asset,
+                                std::unique_ptr<AssetsProvider>&& assets,
                                 package_property_t flags = 0U);
 
   // Creates an ApkAssets from an IDMAP, which contains the original APK path, and the overlay
@@ -94,17 +118,29 @@
 
   bool IsUpToDate() const;
 
- private:
-  static ApkAssetsPtr LoadImpl(std::unique_ptr<AssetsProvider> assets,
-                               package_property_t property_flags,
-                               std::unique_ptr<Asset> idmap_asset,
-                               std::unique_ptr<LoadedIdmap> loaded_idmap);
+  // DANGER!
+  // This is a destructive method that rips the assets provider out of ApkAssets object.
+  // It is only useful when one knows this assets object can't be used anymore, and they
+  // need the underlying assets provider back (e.g. when initialization fails for some
+  // reason).
+  std::unique_ptr<AssetsProvider> TakeAssetsProvider() && {
+    return std::move(assets_provider_);
+  }
 
-  static ApkAssetsPtr LoadImpl(std::unique_ptr<Asset> resources_asset,
-                               std::unique_ptr<AssetsProvider> assets,
+ private:
+  static ApkAssetsPtr LoadImpl(std::unique_ptr<AssetsProvider>&& assets,
                                package_property_t property_flags,
-                               std::unique_ptr<Asset> idmap_asset,
-                               std::unique_ptr<LoadedIdmap> loaded_idmap);
+                               std::unique_ptr<Asset>&& idmap_asset,
+                               std::unique_ptr<LoadedIdmap>&& loaded_idmap);
+
+  static ApkAssetsPtr LoadImpl(std::unique_ptr<Asset>&& resources_asset,
+                               std::unique_ptr<AssetsProvider>&& assets,
+                               package_property_t property_flags,
+                               std::unique_ptr<Asset>&& idmap_asset,
+                               std::unique_ptr<LoadedIdmap>&& loaded_idmap);
+
+  static ApkAssetsPtr LoadImpl(std::unique_ptr<AssetsProvider>&& assets,
+                               package_property_t flags = 0U);
 
   // Allows us to make it possible to call make_shared from inside the class but still keeps the
   // ctor 'private' for all means and purposes.
diff --git a/libs/androidfw/tests/ApkAssets_test.cpp b/libs/androidfw/tests/ApkAssets_test.cpp
index 70326b7..c36d990 100644
--- a/libs/androidfw/tests/ApkAssets_test.cpp
+++ b/libs/androidfw/tests/ApkAssets_test.cpp
@@ -28,6 +28,7 @@
 using ::com::android::basic::R;
 using ::testing::Eq;
 using ::testing::Ge;
+using ::testing::IsNull;
 using ::testing::NotNull;
 using ::testing::SizeIs;
 using ::testing::StrEq;
@@ -108,4 +109,26 @@
   EXPECT_THAT(buffer, StrEq("This should be uncompressed.\n\n"));
 }
 
+TEST(ApkAssetsTest, TakeAssetsProviderNotCrashing) {
+  // Make sure the apk assets object can survive taking its assets provider and doesn't crash
+  // the process.
+  {
+    auto loaded_apk = ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
+    ASSERT_THAT(loaded_apk, NotNull());
+
+    auto provider = std::move(*loaded_apk).TakeAssetsProvider();
+    ASSERT_THAT(provider, NotNull());
+  }
+  // If this test doesn't crash by this point we're all good.
+}
+
+TEST(ApkAssetsTest, AssetsProviderNotMovedOnError) {
+  auto assets_provider
+      = ZipAssetsProvider::Create(GetTestDataPath() + "/bad/bad.apk", 0);
+  ASSERT_THAT(assets_provider, NotNull());
+  auto loaded_apk = ApkAssets::Load(std::move(assets_provider));
+  ASSERT_THAT(loaded_apk, IsNull());
+  ASSERT_THAT(assets_provider, NotNull());
+}
+
 }  // namespace android
diff --git a/libs/androidfw/tests/data/bad/bad.apk b/libs/androidfw/tests/data/bad/bad.apk
new file mode 100644
index 0000000..3226bcd5
--- /dev/null
+++ b/libs/androidfw/tests/data/bad/bad.apk
Binary files differ
diff --git a/location/api/system-current.txt b/location/api/system-current.txt
index 8cd08d3..9478e35 100644
--- a/location/api/system-current.txt
+++ b/location/api/system-current.txt
@@ -645,7 +645,7 @@
   @FlaggedApi("android.location.flags.population_density_provider") public abstract class PopulationDensityProviderBase {
     ctor public PopulationDensityProviderBase(@NonNull android.content.Context, @NonNull String);
     method @Nullable public final android.os.IBinder getBinder();
-    method public abstract void onGetCoarsenedS2Cell(double, double, @NonNull android.os.OutcomeReceiver<long[],java.lang.Throwable>);
+    method public abstract void onGetCoarsenedS2Cells(double, double, @IntRange(from=0) int, @NonNull android.os.OutcomeReceiver<long[],java.lang.Throwable>);
     method public abstract void onGetDefaultCoarseningLevel(@NonNull android.os.OutcomeReceiver<java.lang.Integer,java.lang.Throwable>);
     field public static final String ACTION_POPULATION_DENSITY_PROVIDER = "com.android.location.service.PopulationDensityProvider";
   }
diff --git a/location/java/android/location/provider/IPopulationDensityProvider.aidl b/location/java/android/location/provider/IPopulationDensityProvider.aidl
index 9b5cb5a..41fe500 100644
--- a/location/java/android/location/provider/IPopulationDensityProvider.aidl
+++ b/location/java/android/location/provider/IPopulationDensityProvider.aidl
@@ -35,11 +35,11 @@
     void getDefaultCoarseningLevel(in IS2LevelCallback callback);
 
     /**
-     * Returns a list of IDs of the S2 cells to be used to coarsen a location. The answer should
+     * Requests a list of IDs of the S2 cells to be used to coarsen a location. The answer should
      * contain at least one S2 cell, which should contain the requested location. Its level
-     * represents the population density. Optionally, additional nearby cells can be also returned,
-     * to assist in coarsening nearby locations.
+     * represents the population density. Optionally, if numAdditionalCells is greater than 0,
+     * additional nearby cells can be also returned, to assist in coarsening nearby locations.
      */
-    void getCoarsenedS2Cell(double latitudeDegrees, double longitudeDegrees, in IS2CellIdsCallback
-        callback);
+    void getCoarsenedS2Cells(double latitudeDegrees, double longitudeDegrees,
+        int numAdditionalCells, in IS2CellIdsCallback callback);
 }
diff --git a/location/java/android/location/provider/PopulationDensityProviderBase.java b/location/java/android/location/provider/PopulationDensityProviderBase.java
index 3907516..0177cf8 100644
--- a/location/java/android/location/provider/PopulationDensityProviderBase.java
+++ b/location/java/android/location/provider/PopulationDensityProviderBase.java
@@ -17,6 +17,7 @@
 package android.location.provider;
 
 import android.annotation.FlaggedApi;
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SuppressLint;
@@ -89,17 +90,18 @@
      * Called upon receiving a new request for population density at a specific latitude/longitude,
      * expressed in degrees.
      * The answer is at least one S2CellId corresponding to the coarsening level at the specified
-     * location. This must be the first element of the result array. Optionally, additional nearby
-     * S2CellIds can be returned. One use for the optional nearby cells is when the client has a
-     * local cache that needs to be filled with the local area around a certain latitude/longitude.
-     * The callback {@link OutcomeReceiver#onResult} should be called with the result; or, in case
-     * an error occurs, {@link OutcomeReceiver#onError} should be called.
-     * The callback is single-use, calling more than any one of these two methods throws an
-     * AssertionException.
+     * location. This must be the first element of the result array. Optionally, if
+     * numAdditionalCells is greater than zero, additional nearby S2CellIds can be returned. One use
+     * for the optional nearby cells is when the client has a local cache that needs to be filled
+     * with the local area around a certain latitude/longitude. The callback
+     * {@link OutcomeReceiver#onResult} should be called with the result; or, in case an error
+     * occurs, {@link OutcomeReceiver#onError} should be called. The callback is single-use, calling
+     * more than any one of these two methods throws an AssertionException.
      *
      * @param callback A single-use callback that either returns S2CellIds, or an error.
      */
-    public abstract void onGetCoarsenedS2Cell(double latitudeDegrees, double longitudeDegrees,
+    public abstract void onGetCoarsenedS2Cells(double latitudeDegrees, double longitudeDegrees,
+            @IntRange(from = 0) int numAdditionalCells,
             @NonNull OutcomeReceiver<long[], Throwable> callback);
 
     private final class Service extends IPopulationDensityProvider.Stub {
@@ -119,10 +121,10 @@
         }
 
         @Override
-        public void getCoarsenedS2Cell(double latitudeDegrees, double longitudeDegrees,
-                @NonNull IS2CellIdsCallback callback) {
+        public void getCoarsenedS2Cells(double latitudeDegrees, double longitudeDegrees,
+                int numAdditionalCells, @NonNull IS2CellIdsCallback callback) {
             try {
-                onGetCoarsenedS2Cell(latitudeDegrees, longitudeDegrees,
+                onGetCoarsenedS2Cells(latitudeDegrees, longitudeDegrees, numAdditionalCells,
                         new SingleUseS2CellIdsCallback(callback));
             } catch (RuntimeException e) {
                 // exceptions on one-way binder threads are dropped - move to a different thread
diff --git a/media/java/android/media/quality/AmbientBacklightMetadata.java b/media/java/android/media/quality/AmbientBacklightMetadata.java
index ad19d04..c295946 100644
--- a/media/java/android/media/quality/AmbientBacklightMetadata.java
+++ b/media/java/android/media/quality/AmbientBacklightMetadata.java
@@ -110,9 +110,10 @@
     /**
      * Gets the number of horizontal color zones.
      *
-     * <p>A color zone is a group of lights that always display the same color.
+     * <p>A color zone is represented by one single aggregated color. The number should not be
+     * larger than 128.
      */
-    @IntRange(from = 0)
+    @IntRange(from = 0, to = 128)
     public int getHorizontalZonesNumber() {
         return mHorizontalZonesNumber;
     }
@@ -120,9 +121,10 @@
     /**
      * Gets the number of vertical color zones.
      *
-     * <p>A color zone is a group of lights that always display the same color.
+     * <p>A color zone is represented by one single aggregated color. The number should not be
+     * larger than 80.
      */
-    @IntRange(from = 0)
+    @IntRange(from = 0, to = 80)
     public int getVerticalZonesNumber() {
         return mVerticalZonesNumber;
     }
diff --git a/media/java/android/media/quality/IMediaQualityManager.aidl b/media/java/android/media/quality/IMediaQualityManager.aidl
index dc3fbf6..70211ca 100644
--- a/media/java/android/media/quality/IMediaQualityManager.aidl
+++ b/media/java/android/media/quality/IMediaQualityManager.aidl
@@ -36,6 +36,7 @@
     PictureProfile getPictureProfile(in int type, in String name, int userId);
     List<PictureProfile> getPictureProfilesByPackage(in String packageName, int userId);
     List<PictureProfile> getAvailablePictureProfiles(int userId);
+    boolean setDefaultPictureProfile(in String id, int userId);
     List<String> getPictureProfilePackageNames(int userId);
     List<String> getPictureProfileAllowList(int userId);
     void setPictureProfileAllowList(in List<String> packages, int userId);
@@ -47,6 +48,7 @@
     SoundProfile getSoundProfile(in int type, in String name, int userId);
     List<SoundProfile> getSoundProfilesByPackage(in String packageName, int userId);
     List<SoundProfile> getAvailableSoundProfiles(int userId);
+    boolean setDefaultSoundProfile(in String id, int userId);
     List<String> getSoundProfilePackageNames(int userId);
     List<String> getSoundProfileAllowList(int userId);
     void setSoundProfileAllowList(in List<String> packages, int userId);
diff --git a/media/java/android/media/quality/MediaQualityManager.java b/media/java/android/media/quality/MediaQualityManager.java
index d4de99a..9d66086 100644
--- a/media/java/android/media/quality/MediaQualityManager.java
+++ b/media/java/android/media/quality/MediaQualityManager.java
@@ -257,6 +257,24 @@
     }
 
     /**
+     * Sets preferred default picture profile.
+     *
+     * @param id the ID of the default profile. {@code null} to unset the default profile.
+     * @return {@code true} if it's set successfully; {@code false} otherwise.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE)
+    public boolean setDefaultPictureProfile(@Nullable String id) {
+        try {
+            return mService.setDefaultPictureProfile(id, mUserId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Gets all package names whose picture profiles are available.
      *
      * @see #getPictureProfilesByPackage(String)
@@ -400,6 +418,24 @@
     }
 
     /**
+     * Sets preferred default sound profile.
+     *
+     * @param id the ID of the default profile. {@code null} to unset the default profile.
+     * @return {@code true} if it's set successfully; {@code false} otherwise.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE)
+    public boolean setDefaultSoundProfile(@Nullable String id) {
+        try {
+            return mService.setDefaultSoundProfile(id, mUserId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Gets all package names whose sound profiles are available.
      *
      * @see #getSoundProfilesByPackage(String)
@@ -633,6 +669,7 @@
     /**
      * Registers a {@link AmbientBacklightCallback}.
      */
+    @RequiresPermission(android.Manifest.permission.READ_COLOR_ZONES)
     public void registerAmbientBacklightCallback(
             @NonNull @CallbackExecutor Executor executor,
             @NonNull AmbientBacklightCallback callback) {
@@ -646,6 +683,7 @@
     /**
      * Unregisters the existing {@link AmbientBacklightCallback}.
      */
+    @RequiresPermission(android.Manifest.permission.READ_COLOR_ZONES)
     public void unregisterAmbientBacklightCallback(
             @NonNull final AmbientBacklightCallback callback) {
         Preconditions.checkNotNull(callback);
@@ -666,6 +704,7 @@
      *
      * @param settings The settings to use for the backlight detector.
      */
+    @RequiresPermission(android.Manifest.permission.READ_COLOR_ZONES)
     public void setAmbientBacklightSettings(
             @NonNull AmbientBacklightSettings settings) {
         Preconditions.checkNotNull(settings);
@@ -692,6 +731,7 @@
      *
      * @param enabled {@code true} to enable, {@code false} to disable.
      */
+    @RequiresPermission(android.Manifest.permission.READ_COLOR_ZONES)
     public void setAmbientBacklightEnabled(boolean enabled) {
         try {
             mService.setAmbientBacklightEnabled(enabled, mUserId);
diff --git a/native/android/display_luts.cpp b/native/android/display_luts.cpp
index 179a32b..b03a718 100644
--- a/native/android/display_luts.cpp
+++ b/native/android/display_luts.cpp
@@ -26,8 +26,9 @@
 #define CHECK_NOT_NULL(name) \
     LOG_ALWAYS_FATAL_IF(name == nullptr, "nullptr passed as " #name " argument");
 
-ADisplayLutsEntry* ADisplayLutsEntry_createEntry(float* buffer, int32_t length, int32_t dimension,
-                                                 int32_t key) {
+ADisplayLutsEntry* ADisplayLutsEntry_createEntry(float* buffer, int32_t length,
+                                                 ADisplayLuts_Dimension dimension,
+                                                 ADisplayLuts_SamplingKey key) {
     CHECK_NOT_NULL(buffer);
     LOG_ALWAYS_FATAL_IF(length >= ADISPLAYLUTS_BUFFER_LENGTH_LIMIT,
                         "the lut raw buffer length is too big to handle");
@@ -64,7 +65,7 @@
 
 ADisplayLuts_Dimension ADisplayLutsEntry_getDimension(const ADisplayLutsEntry* entry) {
     CHECK_NOT_NULL(entry);
-    return static_cast<ADisplayLuts_Dimension>(entry->properties.dimension);
+    return entry->properties.dimension;
 }
 
 int32_t ADisplayLutsEntry_getSize(const ADisplayLutsEntry* entry) {
@@ -74,7 +75,7 @@
 
 ADisplayLuts_SamplingKey ADisplayLutsEntry_getSamplingKey(const ADisplayLutsEntry* entry) {
     CHECK_NOT_NULL(entry);
-    return static_cast<ADisplayLuts_SamplingKey>(entry->properties.samplingKey);
+    return entry->properties.samplingKey;
 }
 
 const float* ADisplayLutsEntry_getBuffer(const ADisplayLutsEntry* _Nonnull entry) {
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index e8644ee..78a7ddb 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -361,6 +361,8 @@
     AThermal_unregisterThermalStatusListener; # introduced=30
     AThermal_getThermalHeadroom; # introduced=31
     AThermal_getThermalHeadroomThresholds; # introduced=VanillaIceCream
+    AThermal_registerThermalHeadroomListener; # introduced=36
+    AThermal_unregisterThermalHeadroomListener; # introduced=36
     APerformanceHint_getManager; # introduced=Tiramisu
     APerformanceHint_createSession; # introduced=Tiramisu
     APerformanceHint_getPreferredUpdateRateNanos; # introduced=Tiramisu
diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp
index 6bca145..4fe0b80 100644
--- a/native/android/surface_control.cpp
+++ b/native/android/surface_control.cpp
@@ -64,6 +64,8 @@
               static_cast<int>(android::gui::LutProperties::SamplingKey::RGB));
 static_assert(static_cast<int>(ADISPLAYLUTS_SAMPLINGKEY_MAX_RGB) ==
               static_cast<int>(android::gui::LutProperties::SamplingKey::MAX_RGB));
+static_assert(static_cast<int>(ADISPLAYLUTS_SAMPLINGKEY_CIE_Y) ==
+              static_cast<int>(android::gui::LutProperties::SamplingKey::CIE_Y));
 
 Transaction* ASurfaceTransaction_to_Transaction(ASurfaceTransaction* aSurfaceTransaction) {
     return reinterpret_cast<Transaction*>(aSurfaceTransaction);
diff --git a/native/android/tests/thermal/NativeThermalUnitTest.cpp b/native/android/tests/thermal/NativeThermalUnitTest.cpp
index 4e319fc..923ad01 100644
--- a/native/android/tests/thermal/NativeThermalUnitTest.cpp
+++ b/native/android/tests/thermal/NativeThermalUnitTest.cpp
@@ -77,12 +77,62 @@
                 (override));
 };
 
+struct HeadroomCallbackData {
+    void* data;
+    float headroom;
+    float forecast;
+    int32_t forecastSeconds;
+    const std::vector<float> thresholds;
+};
+
+struct StatusCallbackData {
+    void* data;
+    AThermalStatus status;
+};
+
+static std::optional<HeadroomCallbackData> headroomCalled1;
+static std::optional<HeadroomCallbackData> headroomCalled2;
+static std::optional<StatusCallbackData> statusCalled1;
+static std::optional<StatusCallbackData> statusCalled2;
+
+static std::vector<float> convertThresholds(const AThermalHeadroomThreshold* thresholds,
+                                            size_t size) {
+    std::vector<float> ret;
+    for (int i = 0; i < (int)size; i++) {
+        ret.emplace_back(thresholds[i].headroom);
+    }
+    return ret;
+};
+
+static void onHeadroomChange1(void* data, float headroom, float forecast, int32_t forecastSeconds,
+                              const AThermalHeadroomThreshold* thresholds, size_t size) {
+    headroomCalled1.emplace(data, headroom, forecast, forecastSeconds,
+                            convertThresholds(thresholds, size));
+}
+
+static void onHeadroomChange2(void* data, float headroom, float forecast, int32_t forecastSeconds,
+                              const AThermalHeadroomThreshold* thresholds, size_t size) {
+    headroomCalled2.emplace(data, headroom, forecast, forecastSeconds,
+                            convertThresholds(thresholds, size));
+}
+
+static void onStatusChange1(void* data, AThermalStatus status) {
+    statusCalled1.emplace(data, status);
+}
+static void onStatusChange2(void* data, AThermalStatus status) {
+    statusCalled2.emplace(data, status);
+}
+
 class NativeThermalUnitTest : public Test {
 public:
     void SetUp() override {
         mMockIThermalService = new StrictMock<MockIThermalService>();
         AThermal_setIThermalServiceForTesting(mMockIThermalService);
         mThermalManager = AThermal_acquireManager();
+        headroomCalled1.reset();
+        headroomCalled2.reset();
+        statusCalled1.reset();
+        statusCalled2.reset();
     }
 
     void TearDown() override {
@@ -117,9 +167,11 @@
     size_t size1;
     ASSERT_EQ(OK, AThermal_getThermalHeadroomThresholds(mThermalManager, &thresholds1, &size1));
     checkThermalHeadroomThresholds(expected, thresholds1, size1);
-    // following calls should be cached
-    EXPECT_CALL(*mMockIThermalService, getThermalHeadroomThresholds(_)).Times(0);
-
+    // following calls should not be cached
+    expected = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
+    EXPECT_CALL(*mMockIThermalService, getThermalHeadroomThresholds(_))
+            .Times(Exactly(1))
+            .WillRepeatedly(DoAll(SetArgPointee<0>(expected), Return(Status())));
     const AThermalHeadroomThreshold* thresholds2 = nullptr;
     size_t size2;
     ASSERT_EQ(OK, AThermal_getThermalHeadroomThresholds(mThermalManager, &thresholds2, &size2));
@@ -164,3 +216,248 @@
     ASSERT_EQ(EINVAL, AThermal_getThermalHeadroomThresholds(mThermalManager, &initialized, &size));
     delete[] initialized;
 }
+
+TEST_F(NativeThermalUnitTest, TestRegisterThermalHeadroomListener) {
+    EXPECT_CALL(*mMockIThermalService, registerThermalHeadroomListener(_, _))
+            .Times(Exactly(2))
+            .WillOnce(Return(
+                    Status::fromExceptionCode(binder::Status::Exception::EX_TRANSACTION_FAILED)));
+    float data1 = 1.0f;
+    float data2 = 2.0f;
+    ASSERT_EQ(EPIPE,
+              AThermal_registerThermalHeadroomListener(mThermalManager, onHeadroomChange1, &data1));
+    ASSERT_EQ(EPIPE,
+              AThermal_registerThermalHeadroomListener(mThermalManager, onHeadroomChange2, &data2));
+
+    // verify only 1 service call to register a global listener
+    sp<IThermalHeadroomListener> capturedServiceListener;
+    Mock::VerifyAndClearExpectations(mMockIThermalService);
+    EXPECT_CALL(*mMockIThermalService, registerThermalHeadroomListener(_, _))
+            .Times(Exactly(1))
+            .WillOnce(DoAll(testing::SaveArg<0>(&capturedServiceListener),
+                            testing::Invoke([](const sp<IThermalHeadroomListener>&,
+                                               bool* aidl_return) { *aidl_return = true; }),
+                            Return(Status::ok())));
+    ASSERT_EQ(0,
+              AThermal_registerThermalHeadroomListener(mThermalManager, onHeadroomChange1, &data1));
+    ASSERT_EQ(EINVAL,
+              AThermal_registerThermalHeadroomListener(mThermalManager, onHeadroomChange1, &data1));
+    ASSERT_EQ(0,
+              AThermal_registerThermalHeadroomListener(mThermalManager, onHeadroomChange2, &data2));
+    const ::std::vector<float> thresholds = {0.1f, 0.2f};
+    capturedServiceListener->onHeadroomChange(0.1f, 0.3f, 20, thresholds);
+    ASSERT_TRUE(headroomCalled1.has_value());
+    EXPECT_EQ(headroomCalled1->data, &data1);
+    EXPECT_EQ(headroomCalled1->headroom, 0.1f);
+    EXPECT_EQ(headroomCalled1->forecast, 0.3f);
+    EXPECT_EQ(headroomCalled1->forecastSeconds, 20);
+    EXPECT_EQ(headroomCalled1->thresholds, thresholds);
+    ASSERT_TRUE(headroomCalled2.has_value());
+    EXPECT_EQ(headroomCalled2->data, &data2);
+    EXPECT_EQ(headroomCalled2->headroom, 0.1f);
+    EXPECT_EQ(headroomCalled2->forecast, 0.3f);
+    EXPECT_EQ(headroomCalled2->forecastSeconds, 20);
+    EXPECT_EQ(headroomCalled2->thresholds, thresholds);
+
+    // after test finished the global service listener should be unregistered
+    EXPECT_CALL(*mMockIThermalService, unregisterThermalHeadroomListener(_, _))
+            .Times(Exactly(1))
+            .WillOnce(Return(binder::Status::ok()));
+}
+
+TEST_F(NativeThermalUnitTest, TestUnregisterThermalHeadroomListener) {
+    sp<IThermalHeadroomListener> capturedServiceListener;
+    EXPECT_CALL(*mMockIThermalService, registerThermalHeadroomListener(_, _))
+            .Times(Exactly(1))
+            .WillOnce(DoAll(testing::SaveArg<0>(&capturedServiceListener),
+                            testing::Invoke([](const sp<IThermalHeadroomListener>&,
+                                               bool* aidl_return) { *aidl_return = true; }),
+                            Return(Status::ok())));
+    float data1 = 1.0f;
+    float data2 = 2.0f;
+    ASSERT_EQ(0,
+              AThermal_registerThermalHeadroomListener(mThermalManager, onHeadroomChange1, &data1));
+    ASSERT_EQ(0,
+              AThermal_registerThermalHeadroomListener(mThermalManager, onHeadroomChange2, &data2));
+    capturedServiceListener->onHeadroomChange(0.1f, 0.3f, 20, {});
+    ASSERT_TRUE(headroomCalled1.has_value());
+    ASSERT_TRUE(headroomCalled2.has_value());
+
+    EXPECT_CALL(*mMockIThermalService, unregisterThermalHeadroomListener(_, _))
+            .Times(Exactly(1))
+            .WillRepeatedly(Return(
+                    Status::fromExceptionCode(binder::Status::Exception::EX_TRANSACTION_FAILED)));
+
+    // callback 1 should be unregistered and callback 2 unregistration should fail due to service
+    // listener unregistration call failure
+    ASSERT_EQ(0,
+              AThermal_unregisterThermalHeadroomListener(mThermalManager, onHeadroomChange1,
+                                                         &data1));
+    ASSERT_EQ(EPIPE,
+              AThermal_unregisterThermalHeadroomListener(mThermalManager, onHeadroomChange2,
+                                                         &data2));
+    // verify only callback 2 is called after callback 1 is unregistered
+    std::vector<float> thresholds = {0.1f, 0.2f};
+    headroomCalled1.reset();
+    headroomCalled2.reset();
+    capturedServiceListener->onHeadroomChange(0.1f, 0.3f, 20, thresholds);
+    ASSERT_TRUE(!headroomCalled1.has_value());
+    ASSERT_TRUE(headroomCalled2.has_value());
+
+    // verify only 1 service call to unregister global service listener
+    Mock::VerifyAndClearExpectations(mMockIThermalService);
+    EXPECT_CALL(*mMockIThermalService, unregisterThermalHeadroomListener(_, _))
+            .Times(Exactly(1))
+            .WillOnce(DoAll(testing::Invoke([](const sp<IThermalHeadroomListener>&,
+                                               bool* aidl_return) { *aidl_return = true; }),
+                            Return(Status::ok())));
+    ASSERT_EQ(EINVAL,
+              AThermal_unregisterThermalHeadroomListener(mThermalManager, onHeadroomChange1,
+                                                         &data1));
+    ASSERT_EQ(0,
+              AThermal_unregisterThermalHeadroomListener(mThermalManager, onHeadroomChange2,
+                                                         &data2));
+    // verify neither callback is called after global service listener is unregistered
+    headroomCalled1.reset();
+    headroomCalled2.reset();
+    capturedServiceListener->onHeadroomChange(0.1f, 0.3f, 20, thresholds);
+    ASSERT_TRUE(!headroomCalled1.has_value());
+    ASSERT_TRUE(!headroomCalled2.has_value());
+
+    // verify adding a new callback will still work
+    Mock::VerifyAndClearExpectations(mMockIThermalService);
+    EXPECT_CALL(*mMockIThermalService, registerThermalHeadroomListener(_, _))
+            .Times(Exactly(1))
+            .WillOnce(DoAll(testing::SaveArg<0>(&capturedServiceListener),
+                            testing::Invoke([](const sp<IThermalHeadroomListener>&,
+                                               bool* aidl_return) { *aidl_return = true; }),
+                            Return(Status::ok())));
+    ASSERT_EQ(0,
+              AThermal_registerThermalHeadroomListener(mThermalManager, onHeadroomChange1, &data1));
+    headroomCalled1.reset();
+    capturedServiceListener->onHeadroomChange(0.1f, 0.3f, 20, thresholds);
+    ASSERT_TRUE(headroomCalled1.has_value());
+    EXPECT_EQ(headroomCalled1->data, &data1);
+    EXPECT_EQ(headroomCalled1->headroom, 0.1f);
+    EXPECT_EQ(headroomCalled1->forecast, 0.3f);
+    EXPECT_EQ(headroomCalled1->forecastSeconds, 20);
+    EXPECT_EQ(headroomCalled1->thresholds, thresholds);
+
+    // after test finished the global service listener should be unregistered
+    EXPECT_CALL(*mMockIThermalService, unregisterThermalHeadroomListener(_, _))
+            .Times(Exactly(1))
+            .WillOnce(Return(binder::Status::ok()));
+}
+
+TEST_F(NativeThermalUnitTest, TestRegisterThermalStatusListener) {
+    EXPECT_CALL(*mMockIThermalService, registerThermalStatusListener(_, _))
+            .Times(Exactly(2))
+            .WillOnce(Return(
+                    Status::fromExceptionCode(binder::Status::Exception::EX_TRANSACTION_FAILED)));
+    int data1 = 1;
+    int data2 = 2;
+    ASSERT_EQ(EPIPE,
+              AThermal_registerThermalStatusListener(mThermalManager, onStatusChange1, &data1));
+    ASSERT_EQ(EPIPE,
+              AThermal_registerThermalStatusListener(mThermalManager, onStatusChange2, &data2));
+
+    // verify only 1 service call to register a global listener
+    sp<IThermalStatusListener> capturedServiceListener;
+    Mock::VerifyAndClearExpectations(mMockIThermalService);
+    EXPECT_CALL(*mMockIThermalService, registerThermalStatusListener(_, _))
+            .Times(Exactly(1))
+            .WillOnce(DoAll(testing::SaveArg<0>(&capturedServiceListener),
+                            testing::Invoke([](const sp<IThermalStatusListener>&,
+                                               bool* aidl_return) { *aidl_return = true; }),
+                            Return(Status::ok())));
+    ASSERT_EQ(0, AThermal_registerThermalStatusListener(mThermalManager, onStatusChange1, &data1));
+    ASSERT_EQ(EINVAL,
+              AThermal_registerThermalStatusListener(mThermalManager, onStatusChange1, &data1));
+    ASSERT_EQ(0, AThermal_registerThermalStatusListener(mThermalManager, onStatusChange2, &data2));
+
+    capturedServiceListener->onStatusChange(AThermalStatus::ATHERMAL_STATUS_LIGHT);
+    ASSERT_TRUE(statusCalled1.has_value());
+    EXPECT_EQ(statusCalled1->data, &data1);
+    EXPECT_EQ(statusCalled1->status, AThermalStatus::ATHERMAL_STATUS_LIGHT);
+    ASSERT_TRUE(statusCalled2.has_value());
+    EXPECT_EQ(statusCalled2->data, &data2);
+    EXPECT_EQ(statusCalled2->status, AThermalStatus::ATHERMAL_STATUS_LIGHT);
+
+    // after test finished the callback should be unregistered
+    EXPECT_CALL(*mMockIThermalService, unregisterThermalStatusListener(_, _))
+            .Times(Exactly(1))
+            .WillOnce(Return(binder::Status::ok()));
+}
+
+TEST_F(NativeThermalUnitTest, TestUnregisterThermalStatusListener) {
+    sp<IThermalStatusListener> capturedServiceListener;
+    EXPECT_CALL(*mMockIThermalService, registerThermalStatusListener(_, _))
+            .Times(Exactly(1))
+            .WillOnce(DoAll(testing::SaveArg<0>(&capturedServiceListener),
+                            testing::Invoke([](const sp<IThermalStatusListener>&,
+                                               bool* aidl_return) { *aidl_return = true; }),
+                            Return(Status::ok())));
+    int data1 = 1;
+    int data2 = 2;
+    ASSERT_EQ(0, AThermal_registerThermalStatusListener(mThermalManager, onStatusChange1, &data1));
+    ASSERT_EQ(0, AThermal_registerThermalStatusListener(mThermalManager, onStatusChange2, &data2));
+    capturedServiceListener->onStatusChange(AThermalStatus::ATHERMAL_STATUS_LIGHT);
+    ASSERT_TRUE(statusCalled1.has_value());
+    ASSERT_TRUE(statusCalled2.has_value());
+
+    EXPECT_CALL(*mMockIThermalService, unregisterThermalStatusListener(_, _))
+            .Times(Exactly(1))
+            .WillOnce(Return(
+                    Status::fromExceptionCode(binder::Status::Exception::EX_TRANSACTION_FAILED)));
+    // callback 1 should be unregistered and callback 2 unregistration should fail due to service
+    // listener unregistration call failure
+    ASSERT_EQ(0,
+              AThermal_unregisterThermalStatusListener(mThermalManager, onStatusChange1, &data1));
+    ASSERT_EQ(EPIPE,
+              AThermal_unregisterThermalStatusListener(mThermalManager, onStatusChange2, &data2));
+
+    // verify only callback 2 is called after callback 1 is unregistered
+    statusCalled1.reset();
+    statusCalled2.reset();
+    capturedServiceListener->onStatusChange(AThermalStatus::ATHERMAL_STATUS_LIGHT);
+    ASSERT_TRUE(!statusCalled1.has_value());
+    ASSERT_TRUE(statusCalled2.has_value());
+
+    // verify only 1 service call to unregister global service listener
+    Mock::VerifyAndClearExpectations(mMockIThermalService);
+    EXPECT_CALL(*mMockIThermalService, unregisterThermalStatusListener(_, _))
+            .Times(Exactly(1))
+            .WillOnce(DoAll(testing::Invoke([](const sp<IThermalStatusListener>&,
+                                               bool* aidl_return) { *aidl_return = true; }),
+                            Return(Status::ok())));
+    ASSERT_EQ(EINVAL,
+              AThermal_unregisterThermalStatusListener(mThermalManager, onStatusChange1, &data1));
+    ASSERT_EQ(0,
+              AThermal_unregisterThermalStatusListener(mThermalManager, onStatusChange2, &data2));
+    // verify neither callback is called after global service listener is unregistered
+    statusCalled1.reset();
+    statusCalled2.reset();
+    capturedServiceListener->onStatusChange(AThermalStatus::ATHERMAL_STATUS_LIGHT);
+    ASSERT_TRUE(!statusCalled1.has_value());
+    ASSERT_TRUE(!statusCalled2.has_value());
+
+    // verify adding a new callback will still work
+    Mock::VerifyAndClearExpectations(mMockIThermalService);
+    EXPECT_CALL(*mMockIThermalService, registerThermalStatusListener(_, _))
+            .Times(Exactly(1))
+            .WillOnce(DoAll(testing::SaveArg<0>(&capturedServiceListener),
+                            testing::Invoke([](const sp<IThermalStatusListener>&,
+                                               bool* aidl_return) { *aidl_return = true; }),
+                            Return(Status::ok())));
+    ASSERT_EQ(0, AThermal_registerThermalStatusListener(mThermalManager, onStatusChange1, &data1));
+    statusCalled1.reset();
+    capturedServiceListener->onStatusChange(AThermalStatus::ATHERMAL_STATUS_LIGHT);
+    ASSERT_TRUE(statusCalled1.has_value());
+    EXPECT_EQ(statusCalled1->data, &data1);
+    EXPECT_EQ(statusCalled1->status, AThermalStatus::ATHERMAL_STATUS_LIGHT);
+
+    // after test finished the global service listener should be unregistered
+    EXPECT_CALL(*mMockIThermalService, unregisterThermalStatusListener(_, _))
+            .Times(Exactly(1))
+            .WillOnce(Return(binder::Status::ok()));
+}
diff --git a/native/android/thermal.cpp b/native/android/thermal.cpp
index f7a3537..cefcaf7 100644
--- a/native/android/thermal.cpp
+++ b/native/android/thermal.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "thermal"
 
 #include <android-base/thread_annotations.h>
+#include <android/os/BnThermalHeadroomListener.h>
 #include <android/os/BnThermalStatusListener.h>
 #include <android/os/IThermalService.h>
 #include <android/thermal.h>
@@ -33,10 +34,10 @@
 using namespace android;
 using namespace android::os;
 
-struct ThermalServiceListener : public BnThermalStatusListener {
+struct ThermalServiceStatusListener : public BnThermalStatusListener {
 public:
     virtual binder::Status onStatusChange(int32_t status) override;
-    ThermalServiceListener(AThermalManager *manager) {
+    ThermalServiceStatusListener(AThermalManager *manager) {
         mMgr = manager;
     }
 
@@ -44,11 +45,29 @@
     AThermalManager *mMgr;
 };
 
-struct ListenerCallback {
+struct ThermalServiceHeadroomListener : public BnThermalHeadroomListener {
+public:
+    virtual binder::Status onHeadroomChange(float headroom, float forecastHeadroom,
+                                            int32_t forecastSeconds,
+                                            const ::std::vector<float> &thresholds) override;
+    ThermalServiceHeadroomListener(AThermalManager *manager) {
+        mMgr = manager;
+    }
+
+private:
+    AThermalManager *mMgr;
+};
+
+struct StatusListenerCallback {
     AThermal_StatusCallback callback;
     void* data;
 };
 
+struct HeadroomListenerCallback {
+    AThermal_HeadroomCallback callback;
+    void *data;
+};
+
 static IThermalService *gIThermalServiceForTesting = nullptr;
 
 struct AThermalManager {
@@ -57,30 +76,44 @@
     AThermalManager() = delete;
     ~AThermalManager();
     status_t notifyStateChange(int32_t status);
+    status_t notifyHeadroomChange(float headroom, float forecastHeadroom, int32_t forecastSeconds,
+                                  const ::std::vector<float> &thresholds);
     status_t getCurrentThermalStatus(int32_t *status);
-    status_t addListener(AThermal_StatusCallback, void *data);
-    status_t removeListener(AThermal_StatusCallback, void *data);
+    status_t addStatusListener(AThermal_StatusCallback, void *data);
+    status_t removeStatusListener(AThermal_StatusCallback, void *data);
     status_t getThermalHeadroom(int32_t forecastSeconds, float *result);
     status_t getThermalHeadroomThresholds(const AThermalHeadroomThreshold **, size_t *size);
+    status_t addHeadroomListener(AThermal_HeadroomCallback, void *data);
+    status_t removeHeadroomListener(AThermal_HeadroomCallback, void *data);
 
 private:
     AThermalManager(sp<IThermalService> service);
     sp<IThermalService> mThermalSvc;
-    std::mutex mListenerMutex;
-    sp<ThermalServiceListener> mServiceListener GUARDED_BY(mListenerMutex);
-    std::vector<ListenerCallback> mListeners GUARDED_BY(mListenerMutex);
-    std::mutex mThresholdsMutex;
-    const AThermalHeadroomThreshold *mThresholds = nullptr; // GUARDED_BY(mThresholdsMutex)
-    size_t mThresholdsCount GUARDED_BY(mThresholdsMutex);
+    std::mutex mStatusListenerMutex;
+    sp<ThermalServiceStatusListener> mServiceStatusListener GUARDED_BY(mStatusListenerMutex);
+    std::vector<StatusListenerCallback> mStatusListeners GUARDED_BY(mStatusListenerMutex);
+
+    std::mutex mHeadroomListenerMutex;
+    sp<ThermalServiceHeadroomListener> mServiceHeadroomListener GUARDED_BY(mHeadroomListenerMutex);
+    std::vector<HeadroomListenerCallback> mHeadroomListeners GUARDED_BY(mHeadroomListenerMutex);
 };
 
-binder::Status ThermalServiceListener::onStatusChange(int32_t status) {
+binder::Status ThermalServiceStatusListener::onStatusChange(int32_t status) {
     if (mMgr != nullptr) {
         mMgr->notifyStateChange(status);
     }
     return binder::Status::ok();
 }
 
+binder::Status ThermalServiceHeadroomListener::onHeadroomChange(
+        float headroom, float forecastHeadroom, int32_t forecastSeconds,
+        const ::std::vector<float> &thresholds) {
+    if (mMgr != nullptr) {
+        mMgr->notifyHeadroomChange(headroom, forecastHeadroom, forecastSeconds, thresholds);
+    }
+    return binder::Status::ok();
+}
+
 AThermalManager* AThermalManager::createAThermalManager() {
     if (gIThermalServiceForTesting) {
         return new AThermalManager(gIThermalServiceForTesting);
@@ -96,89 +129,113 @@
 }
 
 AThermalManager::AThermalManager(sp<IThermalService> service)
-      : mThermalSvc(std::move(service)), mServiceListener(nullptr) {}
+      : mThermalSvc(std::move(service)),
+        mServiceStatusListener(nullptr),
+        mServiceHeadroomListener(nullptr) {}
 
 AThermalManager::~AThermalManager() {
     {
-        std::scoped_lock<std::mutex> listenerLock(mListenerMutex);
-        mListeners.clear();
-        if (mServiceListener != nullptr) {
+        std::scoped_lock<std::mutex> listenerLock(mStatusListenerMutex);
+        mStatusListeners.clear();
+        if (mServiceStatusListener != nullptr) {
             bool success = false;
-            mThermalSvc->unregisterThermalStatusListener(mServiceListener, &success);
-            mServiceListener = nullptr;
+            mThermalSvc->unregisterThermalStatusListener(mServiceStatusListener, &success);
+            mServiceStatusListener = nullptr;
         }
     }
-    std::scoped_lock<std::mutex> lock(mThresholdsMutex);
-    delete[] mThresholds;
+    {
+        std::scoped_lock<std::mutex> headroomListenerLock(mHeadroomListenerMutex);
+        mHeadroomListeners.clear();
+        if (mServiceHeadroomListener != nullptr) {
+            bool success = false;
+            mThermalSvc->unregisterThermalHeadroomListener(mServiceHeadroomListener, &success);
+            mServiceHeadroomListener = nullptr;
+        }
+    }
 }
 
 status_t AThermalManager::notifyStateChange(int32_t status) {
-    std::scoped_lock<std::mutex> lock(mListenerMutex);
+    std::scoped_lock<std::mutex> lock(mStatusListenerMutex);
     AThermalStatus thermalStatus = static_cast<AThermalStatus>(status);
 
-    for (auto listener : mListeners) {
+    for (auto listener : mStatusListeners) {
         listener.callback(listener.data, thermalStatus);
     }
     return OK;
 }
 
-status_t AThermalManager::addListener(AThermal_StatusCallback callback, void *data) {
-    std::scoped_lock<std::mutex> lock(mListenerMutex);
+status_t AThermalManager::notifyHeadroomChange(float headroom, float forecastHeadroom,
+                                               int32_t forecastSeconds,
+                                               const ::std::vector<float> &thresholds) {
+    std::scoped_lock<std::mutex> lock(mHeadroomListenerMutex);
+    size_t thresholdsCount = thresholds.size();
+    auto t = new AThermalHeadroomThreshold[thresholdsCount];
+    for (int i = 0; i < (int)thresholdsCount; i++) {
+        t[i].headroom = thresholds[i];
+        t[i].thermalStatus = static_cast<AThermalStatus>(i);
+    }
+    for (auto listener : mHeadroomListeners) {
+        listener.callback(listener.data, headroom, forecastHeadroom, forecastSeconds, t,
+                          thresholdsCount);
+    }
+    delete[] t;
+    return OK;
+}
+
+status_t AThermalManager::addStatusListener(AThermal_StatusCallback callback, void *data) {
+    std::scoped_lock<std::mutex> lock(mStatusListenerMutex);
 
     if (callback == nullptr) {
         // Callback can not be nullptr
         return EINVAL;
     }
-    for (const auto& cb : mListeners) {
+    for (const auto &cb : mStatusListeners) {
         // Don't re-add callbacks.
         if (callback == cb.callback && data == cb.data) {
             return EINVAL;
         }
     }
-    mListeners.emplace_back(ListenerCallback{callback, data});
 
-    if (mServiceListener != nullptr) {
+    if (mServiceStatusListener != nullptr) {
+        mStatusListeners.emplace_back(StatusListenerCallback{callback, data});
         return OK;
     }
     bool success = false;
-    mServiceListener = new ThermalServiceListener(this);
-    if (mServiceListener == nullptr) {
+    mServiceStatusListener = new ThermalServiceStatusListener(this);
+    if (mServiceStatusListener == nullptr) {
         return ENOMEM;
     }
-    auto ret = mThermalSvc->registerThermalStatusListener(mServiceListener, &success);
+    auto ret = mThermalSvc->registerThermalStatusListener(mServiceStatusListener, &success);
     if (!success || !ret.isOk()) {
+        mServiceStatusListener = nullptr;
         ALOGE("Failed in registerThermalStatusListener %d", success);
         if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
             return EPERM;
         }
         return EPIPE;
     }
+    mStatusListeners.emplace_back(StatusListenerCallback{callback, data});
     return OK;
 }
 
-status_t AThermalManager::removeListener(AThermal_StatusCallback callback, void *data) {
-    std::scoped_lock<std::mutex> lock(mListenerMutex);
+status_t AThermalManager::removeStatusListener(AThermal_StatusCallback callback, void *data) {
+    std::scoped_lock<std::mutex> lock(mStatusListenerMutex);
 
-    auto it = std::remove_if(mListeners.begin(),
-                             mListeners.end(),
-                             [&](const ListenerCallback& cb) {
-                                    return callback == cb.callback &&
-                                           data == cb.data;
+    auto it = std::remove_if(mStatusListeners.begin(), mStatusListeners.end(),
+                             [&](const StatusListenerCallback &cb) {
+                                 return callback == cb.callback && data == cb.data;
                              });
-    if (it == mListeners.end()) {
+    if (it == mStatusListeners.end()) {
         // If the listener and data pointer were not previously added.
         return EINVAL;
     }
-    mListeners.erase(it, mListeners.end());
+    if (mServiceStatusListener == nullptr || mStatusListeners.size() > 1) {
+        mStatusListeners.erase(it, mStatusListeners.end());
+        return OK;
+    }
 
-    if (!mListeners.empty()) {
-        return OK;
-    }
-    if (mServiceListener == nullptr) {
-        return OK;
-    }
     bool success = false;
-    auto ret = mThermalSvc->unregisterThermalStatusListener(mServiceListener, &success);
+    auto ret = mThermalSvc->unregisterThermalStatusListener(mServiceStatusListener, &success);
     if (!success || !ret.isOk()) {
         ALOGE("Failed in unregisterThermalStatusListener %d", success);
         if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
@@ -186,7 +243,69 @@
         }
         return EPIPE;
     }
-    mServiceListener = nullptr;
+    mServiceStatusListener = nullptr;
+    mStatusListeners.erase(it, mStatusListeners.end());
+    return OK;
+}
+
+status_t AThermalManager::addHeadroomListener(AThermal_HeadroomCallback callback, void *data) {
+    std::scoped_lock<std::mutex> lock(mHeadroomListenerMutex);
+    if (callback == nullptr) {
+        return EINVAL;
+    }
+    for (const auto &cb : mHeadroomListeners) {
+        if (callback == cb.callback && data == cb.data) {
+            return EINVAL;
+        }
+    }
+
+    if (mServiceHeadroomListener != nullptr) {
+        mHeadroomListeners.emplace_back(HeadroomListenerCallback{callback, data});
+        return OK;
+    }
+    bool success = false;
+    mServiceHeadroomListener = new ThermalServiceHeadroomListener(this);
+    if (mServiceHeadroomListener == nullptr) {
+        return ENOMEM;
+    }
+    auto ret = mThermalSvc->registerThermalHeadroomListener(mServiceHeadroomListener, &success);
+    if (!success || !ret.isOk()) {
+        ALOGE("Failed in registerThermalHeadroomListener %d", success);
+        mServiceHeadroomListener = nullptr;
+        if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
+            return EPERM;
+        }
+        return EPIPE;
+    }
+    mHeadroomListeners.emplace_back(HeadroomListenerCallback{callback, data});
+    return OK;
+}
+
+status_t AThermalManager::removeHeadroomListener(AThermal_HeadroomCallback callback, void *data) {
+    std::scoped_lock<std::mutex> lock(mHeadroomListenerMutex);
+
+    auto it = std::remove_if(mHeadroomListeners.begin(), mHeadroomListeners.end(),
+                             [&](const HeadroomListenerCallback &cb) {
+                                 return callback == cb.callback && data == cb.data;
+                             });
+    if (it == mHeadroomListeners.end()) {
+        return EINVAL;
+    }
+    if (mServiceHeadroomListener == nullptr || mHeadroomListeners.size() > 1) {
+        mHeadroomListeners.erase(it, mHeadroomListeners.end());
+        return OK;
+    }
+    bool success = false;
+    auto ret = mThermalSvc->unregisterThermalHeadroomListener(mServiceHeadroomListener, &success);
+    if (!success || !ret.isOk()) {
+        ALOGE("Failed in unregisterThermalHeadroomListener %d", success);
+        if (ret.exceptionCode() == binder::Status::EX_SECURITY) {
+            return EPERM;
+        }
+        return EPIPE;
+    }
+    mServiceHeadroomListener = nullptr;
+    mHeadroomListeners.erase(it, mHeadroomListeners.end());
     return OK;
 }
 
@@ -216,61 +335,36 @@
 
 status_t AThermalManager::getThermalHeadroomThresholds(const AThermalHeadroomThreshold **result,
                                                        size_t *size) {
-    std::scoped_lock<std::mutex> lock(mThresholdsMutex);
-    if (mThresholds == nullptr) {
-        auto thresholds = std::make_unique<std::vector<float>>();
-        binder::Status ret = mThermalSvc->getThermalHeadroomThresholds(thresholds.get());
-        if (!ret.isOk()) {
-            if (ret.exceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) {
-                // feature is not enabled
-                return ENOSYS;
-            }
-            return EPIPE;
+    auto thresholds = std::make_unique<std::vector<float>>();
+    binder::Status ret = mThermalSvc->getThermalHeadroomThresholds(thresholds.get());
+    if (!ret.isOk()) {
+        if (ret.exceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) {
+            // feature is not enabled
+            return ENOSYS;
         }
-        mThresholdsCount = thresholds->size();
-        auto t = new AThermalHeadroomThreshold[mThresholdsCount];
-        for (int i = 0; i < (int)mThresholdsCount; i++) {
-            t[i].headroom = (*thresholds)[i];
-            t[i].thermalStatus = static_cast<AThermalStatus>(i);
-        }
-        mThresholds = t;
+        return EPIPE;
     }
-    *size = mThresholdsCount;
-    *result = mThresholds;
+    size_t thresholdsCount = thresholds->size();
+    auto t = new AThermalHeadroomThreshold[thresholdsCount];
+    for (int i = 0; i < (int)thresholdsCount; i++) {
+        t[i].headroom = (*thresholds)[i];
+        t[i].thermalStatus = static_cast<AThermalStatus>(i);
+    }
+    *size = thresholdsCount;
+    *result = t;
     return OK;
 }
 
-/**
-  * Acquire an instance of the thermal manager. This must be freed using
-  * {@link AThermal_releaseManager}.
-  *
-  * @return manager instance on success, nullptr on failure.
- */
 AThermalManager* AThermal_acquireManager() {
     auto manager = AThermalManager::createAThermalManager();
 
     return manager;
 }
 
-/**
- * Release the thermal manager pointer acquired by
- * {@link AThermal_acquireManager}.
- *
- * @param manager The manager to be released.
- *
- */
 void AThermal_releaseManager(AThermalManager *manager) {
     delete manager;
 }
 
-/**
-  * Gets the current thermal status.
-  *
-  * @param manager The manager instance to use to query the thermal status,
-  * acquired by {@link AThermal_acquireManager}.
-  *
-  * @return current thermal status, ATHERMAL_STATUS_ERROR on failure.
-*/
 AThermalStatus AThermal_getCurrentThermalStatus(AThermalManager *manager) {
     int32_t status = 0;
     status_t ret = manager->getCurrentThermalStatus(&status);
@@ -280,59 +374,16 @@
     return static_cast<AThermalStatus>(status);
 }
 
-/**
- * Register the thermal status listener for thermal status change.
- *
- * @param manager The manager instance to use to register.
- * acquired by {@link AThermal_acquireManager}.
- * @param callback The callback function to be called when thermal status updated.
- * @param data The data pointer to be passed when callback is called.
- *
- * @return 0 on success
- *         EINVAL if the listener and data pointer were previously added and not removed.
- *         EPERM if the required permission is not held.
- *         EPIPE if communication with the system service has failed.
- */
 int AThermal_registerThermalStatusListener(AThermalManager *manager,
-        AThermal_StatusCallback callback, void *data) {
-    return manager->addListener(callback, data);
+                                           AThermal_StatusCallback callback, void *data) {
+    return manager->addStatusListener(callback, data);
 }
 
-/**
- * Unregister the thermal status listener previously resgistered.
- *
- * @param manager The manager instance to use to unregister.
- * acquired by {@link AThermal_acquireManager}.
- * @param callback The callback function to be called when thermal status updated.
- * @param data The data pointer to be passed when callback is called.
- *
- * @return 0 on success
- *         EINVAL if the listener and data pointer were not previously added.
- *         EPERM if the required permission is not held.
- *         EPIPE if communication with the system service has failed.
- */
 int AThermal_unregisterThermalStatusListener(AThermalManager *manager,
-        AThermal_StatusCallback callback, void *data) {
-    return manager->removeListener(callback, data);
+                                             AThermal_StatusCallback callback, void *data) {
+    return manager->removeStatusListener(callback, data);
 }
 
-/**
- * Provides an estimate of how much thermal headroom the device currently has
- * before hitting severe throttling.
- *
- * Note that this only attempts to track the headroom of slow-moving sensors,
- * such as the skin temperature sensor. This means that there is no benefit to
- * calling this function more frequently than about once per second, and attempts
- * to call significantly more frequently may result in the function returning {@code NaN}.
- *
- * See also PowerManager#getThermalHeadroom.
- *
- * @param manager The manager instance to use
- * @param forecastSeconds how many seconds in the future to forecast
- * @return a value greater than or equal to 0.0 where 1.0 indicates the SEVERE throttling
- *  	   threshold. Returns NaN if the device does not support this functionality or if
- * 	       this function is called significantly faster than once per second.
- */
 float AThermal_getThermalHeadroom(AThermalManager *manager, int forecastSeconds) {
     float result = 0.0f;
     status_t ret = manager->getThermalHeadroom(forecastSeconds, &result);
@@ -354,3 +405,13 @@
 void AThermal_setIThermalServiceForTesting(void *iThermalService) {
     gIThermalServiceForTesting = static_cast<IThermalService *>(iThermalService);
 }
+
+int AThermal_registerThermalHeadroomListener(AThermalManager *manager,
+                                             AThermal_HeadroomCallback callback, void *data) {
+    return manager->addHeadroomListener(callback, data);
+}
+
+int AThermal_unregisterThermalHeadroomListener(AThermalManager *manager,
+                                               AThermal_HeadroomCallback callback, void *data) {
+    return manager->removeHeadroomListener(callback, data);
+}
diff --git a/nfc/api/system-current.txt b/nfc/api/system-current.txt
index 3ed9b76..e97b15d 100644
--- a/nfc/api/system-current.txt
+++ b/nfc/api/system-current.txt
@@ -124,6 +124,7 @@
 
   @FlaggedApi("android.nfc.nfc_oem_extension") public abstract class NfcRoutingTableEntry {
     method public int getNfceeId();
+    method public int getRouteType();
     method public int getType();
     field public static final int TYPE_AID = 0; // 0x0
     field public static final int TYPE_PROTOCOL = 1; // 0x1
diff --git a/nfc/java/android/nfc/Entry.java b/nfc/java/android/nfc/Entry.java
index 49d0f10..aa5ba58 100644
--- a/nfc/java/android/nfc/Entry.java
+++ b/nfc/java/android/nfc/Entry.java
@@ -25,11 +25,13 @@
     private final byte mType;
     private final byte mNfceeId;
     private final String mEntry;
+    private final String mRoutingType;
 
-    public Entry(String entry, byte type, byte nfceeId) {
+    public Entry(String entry, byte type, byte nfceeId, String routingType) {
         mEntry = entry;
         mType = type;
         mNfceeId = nfceeId;
+        mRoutingType = routingType;
     }
 
     public byte getType() {
@@ -44,6 +46,10 @@
         return mEntry;
     }
 
+    public String getRoutingType() {
+        return mRoutingType;
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -53,6 +59,7 @@
         this.mEntry = in.readString();
         this.mNfceeId = in.readByte();
         this.mType = in.readByte();
+        this.mRoutingType = in.readString();
     }
 
     public static final @NonNull Parcelable.Creator<Entry> CREATOR =
@@ -73,5 +80,6 @@
         dest.writeString(mEntry);
         dest.writeByte(mNfceeId);
         dest.writeByte(mType);
+        dest.writeString(mRoutingType);
     }
 }
diff --git a/nfc/java/android/nfc/NfcOemExtension.java b/nfc/java/android/nfc/NfcOemExtension.java
index f78161e..fb11875 100644
--- a/nfc/java/android/nfc/NfcOemExtension.java
+++ b/nfc/java/android/nfc/NfcOemExtension.java
@@ -887,18 +887,22 @@
             switch (entry.getType()) {
                 case TYPE_TECHNOLOGY -> result.add(
                         new RoutingTableTechnologyEntry(entry.getNfceeId(),
-                                RoutingTableTechnologyEntry.techStringToInt(entry.getEntry()))
+                                RoutingTableTechnologyEntry.techStringToInt(entry.getEntry()),
+                                routeStringToInt(entry.getRoutingType()))
                 );
                 case TYPE_PROTOCOL -> result.add(
                         new RoutingTableProtocolEntry(entry.getNfceeId(),
-                                RoutingTableProtocolEntry.protocolStringToInt(entry.getEntry()))
+                                RoutingTableProtocolEntry.protocolStringToInt(entry.getEntry()),
+                                routeStringToInt(entry.getRoutingType()))
                 );
                 case TYPE_AID -> result.add(
-                        new RoutingTableAidEntry(entry.getNfceeId(), entry.getEntry())
+                        new RoutingTableAidEntry(entry.getNfceeId(), entry.getEntry(),
+                                routeStringToInt(entry.getRoutingType()))
                 );
                 case TYPE_SYSTEMCODE -> result.add(
                         new RoutingTableSystemCodeEntry(entry.getNfceeId(),
-                                entry.getEntry().getBytes(StandardCharsets.UTF_8))
+                                entry.getEntry().getBytes(StandardCharsets.UTF_8),
+                                routeStringToInt(entry.getRoutingType()))
                 );
             }
         }
diff --git a/nfc/java/android/nfc/NfcRoutingTableEntry.java b/nfc/java/android/nfc/NfcRoutingTableEntry.java
index c2cbbed..4153779 100644
--- a/nfc/java/android/nfc/NfcRoutingTableEntry.java
+++ b/nfc/java/android/nfc/NfcRoutingTableEntry.java
@@ -19,6 +19,7 @@
 import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.SystemApi;
+import android.nfc.cardemulation.CardEmulation;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -35,6 +36,7 @@
 public abstract class NfcRoutingTableEntry {
     private final int mNfceeId;
     private final int mType;
+    private final int mRouteType;
 
     /**
      * AID routing table type.
@@ -67,9 +69,11 @@
     public @interface RoutingTableType {}
 
     /** @hide */
-    protected NfcRoutingTableEntry(int nfceeId, @RoutingTableType int type) {
+    protected NfcRoutingTableEntry(int nfceeId, @RoutingTableType int type,
+            @CardEmulation.ProtocolAndTechnologyRoute int routeType) {
         mNfceeId = nfceeId;
         mType = type;
+        mRouteType = routeType;
     }
 
     /**
@@ -88,4 +92,14 @@
     public int getType() {
         return mType;
     }
+
+    /**
+     * Get the route type of this entry.
+     * @return an integer defined in
+     * {@link android.nfc.cardemulation.CardEmulation.ProtocolAndTechnologyRoute}
+     */
+    @CardEmulation.ProtocolAndTechnologyRoute
+    public int getRouteType() {
+        return mRouteType;
+    }
 }
diff --git a/nfc/java/android/nfc/RoutingTableAidEntry.java b/nfc/java/android/nfc/RoutingTableAidEntry.java
index bf697d6..be94f9f 100644
--- a/nfc/java/android/nfc/RoutingTableAidEntry.java
+++ b/nfc/java/android/nfc/RoutingTableAidEntry.java
@@ -18,6 +18,7 @@
 import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.nfc.cardemulation.CardEmulation;
 
 /**
  * Represents an Application ID (AID) entry in current routing table.
@@ -29,8 +30,9 @@
     private final String mValue;
 
     /** @hide */
-    public RoutingTableAidEntry(int nfceeId, String value) {
-        super(nfceeId, TYPE_AID);
+    public RoutingTableAidEntry(int nfceeId, String value,
+            @CardEmulation.ProtocolAndTechnologyRoute int routeType) {
+        super(nfceeId, TYPE_AID, routeType);
         this.mValue = value;
     }
 
diff --git a/nfc/java/android/nfc/RoutingTableProtocolEntry.java b/nfc/java/android/nfc/RoutingTableProtocolEntry.java
index 536de4d..a68d8c1 100644
--- a/nfc/java/android/nfc/RoutingTableProtocolEntry.java
+++ b/nfc/java/android/nfc/RoutingTableProtocolEntry.java
@@ -18,6 +18,7 @@
 import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.SystemApi;
+import android.nfc.cardemulation.CardEmulation;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -96,8 +97,9 @@
     private final @ProtocolValue int mValue;
 
     /** @hide */
-    public RoutingTableProtocolEntry(int nfceeId, @ProtocolValue int value) {
-        super(nfceeId, TYPE_PROTOCOL);
+    public RoutingTableProtocolEntry(int nfceeId, @ProtocolValue int value,
+            @CardEmulation.ProtocolAndTechnologyRoute int routeType) {
+        super(nfceeId, TYPE_PROTOCOL, routeType);
         this.mValue = value;
     }
 
diff --git a/nfc/java/android/nfc/RoutingTableSystemCodeEntry.java b/nfc/java/android/nfc/RoutingTableSystemCodeEntry.java
index f61892d..06cc0a5 100644
--- a/nfc/java/android/nfc/RoutingTableSystemCodeEntry.java
+++ b/nfc/java/android/nfc/RoutingTableSystemCodeEntry.java
@@ -18,6 +18,7 @@
 import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.nfc.cardemulation.CardEmulation;
 
 /**
  * Represents a system code entry in current routing table, where system codes are two-byte values
@@ -31,8 +32,9 @@
     private final byte[] mValue;
 
     /** @hide */
-    public RoutingTableSystemCodeEntry(int nfceeId, byte[] value) {
-        super(nfceeId, TYPE_SYSTEM_CODE);
+    public RoutingTableSystemCodeEntry(int nfceeId, byte[] value,
+            @CardEmulation.ProtocolAndTechnologyRoute int routeType) {
+        super(nfceeId, TYPE_SYSTEM_CODE, routeType);
         this.mValue = value;
     }
 
diff --git a/nfc/java/android/nfc/RoutingTableTechnologyEntry.java b/nfc/java/android/nfc/RoutingTableTechnologyEntry.java
index 2dbc942..86239ce 100644
--- a/nfc/java/android/nfc/RoutingTableTechnologyEntry.java
+++ b/nfc/java/android/nfc/RoutingTableTechnologyEntry.java
@@ -18,6 +18,7 @@
 import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.SystemApi;
+import android.nfc.cardemulation.CardEmulation;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -77,8 +78,9 @@
     private final @TechnologyValue int mValue;
 
     /** @hide */
-    public RoutingTableTechnologyEntry(int nfceeId, @TechnologyValue int value) {
-        super(nfceeId, TYPE_TECHNOLOGY);
+    public RoutingTableTechnologyEntry(int nfceeId, @TechnologyValue int value,
+            @CardEmulation.ProtocolAndTechnologyRoute int routeType) {
+        super(nfceeId, TYPE_TECHNOLOGY, routeType);
         this.mValue = value;
     }
 
diff --git a/nfc/tests/src/android/nfc/NdefRecordTest.java b/nfc/tests/src/android/nfc/NdefRecordTest.java
index 231e939..044c674 100644
--- a/nfc/tests/src/android/nfc/NdefRecordTest.java
+++ b/nfc/tests/src/android/nfc/NdefRecordTest.java
@@ -24,6 +24,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Locale;
+
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class NdefRecordTest {
@@ -56,4 +58,20 @@
         assertThat(ndefRecord.getType()).isEqualTo(NdefRecord.RTD_URI);
     }
 
+    @Test
+    public void testCreateMime() {
+        NdefRecord ndefRecord = NdefRecord.createMime("text/plain", "example".getBytes());
+        assertThat(ndefRecord).isNotNull();
+        assertThat(ndefRecord.getTnf()).isEqualTo(NdefRecord.TNF_MIME_MEDIA);
+    }
+
+    @Test
+    public void testCreateTextRecord() {
+        String languageCode = Locale.getDefault().getLanguage();
+        NdefRecord ndefRecord = NdefRecord.createTextRecord(languageCode, "testdata");
+        assertThat(ndefRecord).isNotNull();
+        assertThat(ndefRecord.getTnf()).isEqualTo(NdefRecord.TNF_WELL_KNOWN);
+        assertThat(ndefRecord.getType()).isEqualTo(NdefRecord.RTD_TEXT);
+    }
+
 }
diff --git a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
index 6a4bb21..a3b06e8 100644
--- a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
+++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
@@ -16,8 +16,10 @@
 
 package com.android.localtransport;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.backup.BackupAgent;
+import android.app.backup.BackupAnnotations;
 import android.app.backup.BackupDataInput;
 import android.app.backup.BackupDataOutput;
 import android.app.backup.BackupManagerMonitor;
@@ -52,6 +54,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.List;
 
 /**
  * Backup transport for stashing stuff into a known location on disk, and
@@ -939,4 +942,15 @@
             }
         }
     }
+
+    @NonNull
+    @Override
+    public List<String> getPackagesThatShouldNotUseRestrictedMode(
+            @NonNull List<String> packageNames,
+            @BackupAnnotations.OperationType int operationType) {
+        if (DEBUG) {
+            Log.d(TAG, "No restricted mode packages: " + mParameters.noRestrictedModePackages());
+        }
+        return mParameters.noRestrictedModePackages();
+    }
 }
diff --git a/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java
index aaa18bf..c980913 100644
--- a/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java
+++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java
@@ -16,26 +16,33 @@
 
 package com.android.localtransport;
 
-import android.util.KeyValueSettingObserver;
 import android.content.ContentResolver;
 import android.os.Handler;
 import android.provider.Settings;
 import android.util.KeyValueListParser;
+import android.util.KeyValueSettingObserver;
+
+import java.util.Arrays;
+import java.util.List;
 
 public class LocalTransportParameters extends KeyValueSettingObserver {
-    private static final String TAG = "LocalTransportParams";
     private static final String SETTING = Settings.Secure.BACKUP_LOCAL_TRANSPORT_PARAMETERS;
     private static final String KEY_FAKE_ENCRYPTION_FLAG = "fake_encryption_flag";
     private static final String KEY_NON_INCREMENTAL_ONLY = "non_incremental_only";
     private static final String KEY_IS_DEVICE_TRANSFER = "is_device_transfer";
     private static final String KEY_IS_ENCRYPTED = "is_encrypted";
     private static final String KEY_LOG_AGENT_RESULTS = "log_agent_results";
+    // This needs to be a list of package names separated by semicolons. For example:
+    // "com.package1;com.package2;com.package3". We can't use commas because the base class uses
+    // commas to split Key/Value pairs.
+    private static final String KEY_NO_RESTRICTED_MODE_PACKAGES = "no_restricted_mode_packages";
 
     private boolean mFakeEncryptionFlag;
     private boolean mIsNonIncrementalOnly;
     private boolean mIsDeviceTransfer;
     private boolean mIsEncrypted;
     private boolean mLogAgentResults;
+    private String mNoRestrictedModePackages;
 
     public LocalTransportParameters(Handler handler, ContentResolver resolver) {
         super(handler, resolver, Settings.Secure.getUriFor(SETTING));
@@ -61,6 +68,13 @@
         return mLogAgentResults;
     }
 
+    List<String> noRestrictedModePackages() {
+        if (mNoRestrictedModePackages == null) {
+            return List.of();
+        }
+        return Arrays.stream(mNoRestrictedModePackages.split(";")).toList();
+    }
+
     public String getSettingValue(ContentResolver resolver) {
         return Settings.Secure.getString(resolver, SETTING);
     }
@@ -71,5 +85,6 @@
         mIsDeviceTransfer = parser.getBoolean(KEY_IS_DEVICE_TRANSFER, false);
         mIsEncrypted = parser.getBoolean(KEY_IS_ENCRYPTED, false);
         mLogAgentResults = parser.getBoolean(KEY_LOG_AGENT_RESULTS, /* def */ false);
+        mNoRestrictedModePackages = parser.getString(KEY_NO_RESTRICTED_MODE_PACKAGES, /* def */ "");
     }
 }
diff --git a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceStateProviders.kt b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceStateProviders.kt
index 7436ac1..6704ecc 100644
--- a/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceStateProviders.kt
+++ b/packages/SettingsLib/Metadata/src/com/android/settingslib/metadata/PreferenceStateProviders.kt
@@ -20,6 +20,8 @@
 import android.content.ContextWrapper
 import android.content.Intent
 import android.os.Bundle
+import androidx.lifecycle.LifecycleCoroutineScope
+import kotlinx.coroutines.CoroutineScope
 
 /**
  * Interface to provide dynamic preference title.
@@ -138,6 +140,13 @@
  */
 abstract class PreferenceLifecycleContext(context: Context) : ContextWrapper(context) {
 
+    /**
+     * [CoroutineScope] tied to the lifecycle, which is cancelled when the lifecycle is destroyed.
+     *
+     * @see [androidx.lifecycle.lifecycleScope]
+     */
+    abstract val lifecycleScope: LifecycleCoroutineScope
+
     /** Returns the preference widget object associated with given key. */
     abstract fun <T> findPreference(key: String): T?
 
diff --git a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenBindingHelper.kt b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenBindingHelper.kt
index 03b225e..6fc9357 100644
--- a/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenBindingHelper.kt
+++ b/packages/SettingsLib/Preference/src/com/android/settingslib/preference/PreferenceScreenBindingHelper.kt
@@ -19,6 +19,8 @@
 import android.content.Context
 import android.content.Intent
 import android.os.Bundle
+import androidx.lifecycle.LifecycleCoroutineScope
+import androidx.lifecycle.lifecycleScope
 import androidx.preference.Preference
 import androidx.preference.PreferenceDataStore
 import androidx.preference.PreferenceGroup
@@ -57,6 +59,9 @@
 
     private val preferenceLifecycleContext =
         object : PreferenceLifecycleContext(context) {
+            override val lifecycleScope: LifecycleCoroutineScope
+                get() = fragment.lifecycleScope
+
             override fun <T> findPreference(key: String) =
                 preferenceScreen.findPreference(key) as T?
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index ebeee85..ea8ae7b 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -242,8 +242,7 @@
                 // Don't write it to setting. Let the broadcast receiver in
                 // AccessibilityManagerService handle restore/merging logic.
                 return;
-            } else if (android.view.accessibility.Flags.restoreA11yShortcutTargetService()
-                    && Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE.equals(name)) {
+            } else if (Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE.equals(name)) {
                 // Don't write it to setting. Let the broadcast receiver in
                 // AccessibilityManagerService handle restore/merging logic.
                 return;
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperRestoreTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperRestoreTest.java
index f64f72a..048d93b 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperRestoreTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperRestoreTest.java
@@ -26,8 +26,6 @@
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Build;
-import android.platform.test.annotations.EnableFlags;
-import android.platform.test.flag.junit.SetFlagsRule;
 import android.provider.Settings;
 import android.provider.SettingsStringUtil;
 
@@ -37,7 +35,6 @@
 import com.android.internal.util.test.BroadcastInterceptingContext;
 
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mockito;
@@ -52,9 +49,6 @@
 @RunWith(AndroidJUnit4.class)
 public class SettingsHelperRestoreTest {
 
-    @Rule
-    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
-
     private static final float FLOAT_TOLERANCE = 0.01f;
 
     private Context mContext;
@@ -211,7 +205,6 @@
     }
 
     @Test
-    @EnableFlags(android.view.accessibility.Flags.FLAG_RESTORE_A11Y_SHORTCUT_TARGET_SERVICE)
     public void restoreAccessibilityShortcutTargetService_broadcastSent()
             throws ExecutionException, InterruptedException {
         BroadcastInterceptingContext interceptingContext = new BroadcastInterceptingContext(
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 0ec5571..fa6e2db 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -65,7 +65,6 @@
     <uses-permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL" />
     <uses-permission android:name="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS" />
     <uses-permission android:name="android.permission.GET_PROCESS_STATE_AND_OOM_SCORE" />
-    <uses-permission android:name="android.permission.READ_DROPBOX_DATA" />
     <uses-permission android:name="android.permission.READ_LOGS" />
     <uses-permission android:name="android.permission.BRIGHTNESS_SLIDER_USAGE" />
     <uses-permission android:name="android.permission.ACCESS_AMBIENT_LIGHT_STATS" />
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuOverlayLayout.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuOverlayLayout.java
index 6bc0f42..a607786 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuOverlayLayout.java
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/view/A11yMenuOverlayLayout.java
@@ -57,7 +57,6 @@
 
 import com.android.app.viewcapture.ViewCaptureAwareWindowManager;
 import com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService;
-import com.android.systemui.accessibility.accessibilitymenu.Flags;
 import com.android.systemui.accessibility.accessibilitymenu.R;
 import com.android.systemui.accessibility.accessibilitymenu.activity.A11yMenuSettingsActivity.A11yMenuPreferenceFragment;
 import com.android.systemui.accessibility.accessibilitymenu.model.A11yMenuShortcut;
@@ -383,9 +382,7 @@
             return;
         }
         snackbar.setText(text);
-        if (Flags.a11yMenuSnackbarLiveRegion()) {
-            snackbar.setAccessibilityLiveRegion(ACCESSIBILITY_LIVE_REGION_POLITE);
-        }
+        snackbar.setAccessibilityLiveRegion(ACCESSIBILITY_LIVE_REGION_POLITE);
 
         // Remove any existing fade-out animation before starting any new animations.
         mHandler.removeCallbacksAndMessages(null);
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 02e7b5f..c1f7868 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -427,6 +427,18 @@
     }
 }
 
+
+flag {
+    name: "status_bar_chips_modernization"
+    namespace: "systemui"
+    description: "Deprecate OngoingCallController and implement OngoingActivityChips"
+    "in compose"
+    bug: "372657935"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
+
 flag {
     name: "status_bar_use_repos_for_call_chip"
     namespace: "systemui"
@@ -1204,6 +1216,13 @@
 }
 
 flag {
+  name: "communal_responsive_grid"
+  namespace: "systemui"
+  description: "Enables responsive grid on glanceable hub"
+  bug: "378171351"
+}
+
+flag {
   name: "communal_standalone_support"
   namespace: "systemui"
   description: "Support communal features without a dock"
@@ -1782,16 +1801,6 @@
 }
 
 flag {
-  name: "ensure_enr_views_visibility"
-  namespace: "systemui"
-  description: "Ensures public and private visibilities"
-  bug: "361552380"
-  metadata {
-    purpose: PURPOSE_BUGFIX
-  }
-}
-
-flag {
   name: "shade_expands_on_status_bar_long_press"
   namespace: "systemui"
   description: "Expands the shade on long press of any status bar"
@@ -1863,3 +1872,17 @@
     description: "Implement the depth push scaling effect on Launcher when users pull down shade."
     bug: "370562309"
 }
+
+flag {
+    name: "spatial_model_app_pushback"
+    namespace: "systemui"
+    description: "Implement the depth push scaling effect on the current app when users pull down shade."
+    bug: "370560660"
+}
+
+flag {
+    name: "expanded_privacy_indicators_on_large_screen"
+    namespace: "systemui"
+    description: "Larger privacy indicators on large screen"
+    bug: "381864715"
+}
diff --git a/packages/SystemUI/animation/lib/src/com/android/systemui/animation/server/IOriginTransitionsImpl.java b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/server/IOriginTransitionsImpl.java
index 6b26ac5..3b66460 100644
--- a/packages/SystemUI/animation/lib/src/com/android/systemui/animation/server/IOriginTransitionsImpl.java
+++ b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/server/IOriginTransitionsImpl.java
@@ -438,7 +438,8 @@
             if (forPredictiveBackTakeover) {
                 filter.mTypeSet = new int[] {TRANSIT_PREPARE_BACK_NAVIGATION};
             } else {
-                filter.mTypeSet = new int[] {TRANSIT_CLOSE, TRANSIT_TO_BACK};
+                filter.mTypeSet =
+                        new int[] {TRANSIT_CLOSE, TRANSIT_TO_BACK, TRANSIT_OPEN, TRANSIT_TO_FRONT};
             }
 
             // The opening activity of the return transition must match the activity we just closed.
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/ShadeDisplayAwareDetector.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/ShadeDisplayAwareDetector.kt
new file mode 100644
index 0000000..2f83d82
--- /dev/null
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/ShadeDisplayAwareDetector.kt
@@ -0,0 +1,136 @@
+/*
+ * 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.internal.systemui.lint
+
+import com.android.tools.lint.client.api.UElementHandler
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import com.android.tools.lint.detector.api.SourceCodeScanner
+import org.jetbrains.uast.UClass
+import org.jetbrains.uast.getContainingUFile
+
+class ShadeDisplayAwareDetector : Detector(), SourceCodeScanner {
+    override fun getApplicableUastTypes() = listOf(UClass::class.java)
+
+    override fun createUastHandler(context: JavaContext) =
+        object : UElementHandler() {
+            override fun visitClass(node: UClass) {
+                for (constructor in node.constructors) {
+                    // Visit all injected constructors in shade-relevant packages
+                    if (!constructor.hasAnnotation(INJECT_ANNOTATION)) continue
+                    if (!isInRelevantShadePackage(node)) continue
+                    if (IGNORED_PACKAGES.contains(node.qualifiedName)) continue
+
+                    // Check the any context-dependent parameter to see if it has @ShadeDisplayAware
+                    // annotation
+                    for (parameter in constructor.parameterList.parameters) {
+                        val shouldReport =
+                            CONTEXT_DEPENDENT_SHADE_CLASSES.contains(
+                                parameter.type.canonicalText
+                            ) && !parameter.hasAnnotation(SHADE_DISPLAY_AWARE_ANNOTATION)
+                        if (shouldReport) {
+                            context.report(
+                                issue = ISSUE,
+                                scope = parameter.declarationScope,
+                                location = context.getNameLocation(parameter),
+                                message = reportMsg(className = parameter.type.presentableText),
+                            )
+                        }
+                    }
+                }
+            }
+        }
+
+    companion object {
+        private const val INJECT_ANNOTATION = "javax.inject.Inject"
+        private const val SHADE_DISPLAY_AWARE_ANNOTATION =
+            "com.android.systemui.shade.ShadeDisplayAware"
+
+        private val CONTEXT_DEPENDENT_SHADE_CLASSES =
+            setOf(
+                "android.content.Context",
+                "android.view.WindowManager",
+                "android.view.LayoutInflater",
+                "android.content.res.Resources",
+                "com.android.systemui.common.ui.ConfigurationState",
+                "com.android.systemui.statusbar.policy.ConfigurationController",
+                "com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor",
+            )
+
+        private val SHADE_WINDOW_PACKAGES =
+            listOf(
+                "com.android.systemui.biometrics",
+                "com.android.systemui.bouncer",
+                "com.android.systemui.keyboard.docking.ui.viewmodel",
+                "com.android.systemui.qs",
+                "com.android.systemui.shade",
+                "com.android.systemui.statusbar.notification",
+                "com.android.systemui.unfold.domain.interactor",
+            )
+
+        private val IGNORED_PACKAGES =
+            setOf(
+                "com.android.systemui.biometrics.UdfpsController",
+                "com.android.systemui.qs.customize.TileAdapter",
+            )
+
+        private fun isInRelevantShadePackage(node: UClass): Boolean {
+            val packageName = node.getContainingUFile()?.packageName
+            if (packageName.isNullOrBlank()) return false
+            return SHADE_WINDOW_PACKAGES.any { relevantPackage ->
+                packageName.startsWith(relevantPackage)
+            }
+        }
+
+        private fun reportMsg(className: String) =
+            """UI elements of the shade window
+              |should use ShadeDisplayAware-annotated $className, as the shade might move between windows, and only
+              |@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so
+              |might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).
+              |If the usage of $className is not related to display specific configuration or UI, then there is
+              |technically no need to use the annotation, and you can annotate the class with
+              |@SuppressLint("ShadeDisplayAwareContextChecker")/@Suppress("ShadeDisplayAwareContextChecker")
+              |"""
+                .trimMargin()
+
+        @JvmField
+        val ISSUE: Issue =
+            Issue.create(
+                id = "ShadeDisplayAwareContextChecker",
+                briefDescription = "Using non-ShadeDisplayAware component within shade",
+                explanation =
+                    """
+                Any context-dependent components (Resources, LayoutInflater, ConfigurationState,
+                etc.) being injected into Shade-relevant classes must have the @ShadeDisplayAware
+                annotation to ensure they work with when the shade is moved to a different display.
+                When the shade is moved, the configuration might change, and only @ShadeDisplayAware
+                components will update accordingly to reflect the new display.
+            """
+                        .trimIndent(),
+                category = Category.CORRECTNESS,
+                priority = 8,
+                severity = Severity.ERROR,
+                implementation =
+                    Implementation(ShadeDisplayAwareDetector::class.java, Scope.JAVA_FILE_SCOPE),
+            )
+    }
+}
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
index a1f4f55..6d18f93 100644
--- a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
@@ -46,8 +46,9 @@
                 DemotingTestWithoutBugDetector.ISSUE,
                 TestFunctionNameViolationDetector.ISSUE,
                 MissingApacheLicenseDetector.ISSUE,
+                ShadeDisplayAwareDetector.ISSUE,
                 RegisterContentObserverSyncViaSettingsProxyDetector.SYNC_WARNING,
-                RegisterContentObserverViaContentResolverDetector.CONTENT_RESOLVER_ERROR
+                RegisterContentObserverViaContentResolverDetector.CONTENT_RESOLVER_ERROR,
             )
 
     override val api: Int
@@ -60,6 +61,6 @@
         Vendor(
             vendorName = "Android",
             feedbackUrl = "http://b/issues/new?component=78010",
-            contact = "jernej@google.com"
+            contact = "jernej@google.com",
         )
 }
diff --git a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/ShadeDisplayAwareDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/ShadeDisplayAwareDetectorTest.kt
new file mode 100644
index 0000000..58ad363
--- /dev/null
+++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/ShadeDisplayAwareDetectorTest.kt
@@ -0,0 +1,375 @@
+/*
+ * 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.internal.systemui.lint
+
+import com.android.tools.lint.checks.infrastructure.TestFile
+import com.android.tools.lint.checks.infrastructure.TestFiles
+import com.android.tools.lint.checks.infrastructure.TestMode
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+import org.junit.Test
+
+class ShadeDisplayAwareDetectorTest : SystemUILintDetectorTest() {
+    override fun getDetector(): Detector = ShadeDisplayAwareDetector()
+
+    override fun getIssues(): List<Issue> = listOf(ShadeDisplayAwareDetector.ISSUE)
+
+    private val qsContext: TestFile =
+        java(
+                """
+            package com.android.systemui.qs.dagger;
+
+            import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+            import java.lang.annotation.Retention;
+
+            @Retention(RUNTIME) public @interface QSThemedContext {}
+            """
+            )
+            .indented()
+
+    private val injectStub: TestFile =
+        kotlin(
+                """
+                package javax.inject
+
+                @Retention(AnnotationRetention.RUNTIME) annotation class Inject
+                """
+            )
+            .indented()
+
+    private val shadeDisplayAwareStub: TestFile =
+        kotlin(
+                """
+                package com.android.systemui.shade
+
+                @Retention(AnnotationRetention.RUNTIME) annotation class ShadeDisplayAware
+                """
+            )
+            .indented()
+
+    private val configStateStub: TestFile =
+        kotlin(
+                """
+                package com.android.systemui.common.ui
+
+                class ConfigurationState
+                """
+            )
+            .indented()
+
+    private val configControllerStub: TestFile =
+        kotlin(
+                """
+                package com.android.systemui.statusbar.policy
+
+                class ConfigurationController
+                """
+            )
+            .indented()
+
+    private val configInteractorStub: TestFile =
+        kotlin(
+                """
+                package com.android.systemui.common.ui.domain.interactor
+
+                class ConfigurationInteractor
+                """
+            )
+            .indented()
+
+    private val otherStubs =
+        arrayOf(
+            injectStub,
+            qsContext,
+            shadeDisplayAwareStub,
+            configStateStub,
+            configControllerStub,
+            configInteractorStub,
+        )
+
+    @Test
+    fun injectedConstructor_inRelevantPackage_withRelevantParameter_withoutAnnotation() {
+        lint()
+            .files(
+                TestFiles.kotlin(
+                    """
+                        package com.android.systemui.shade.example
+
+                        import javax.inject.Inject
+                        import android.content.Context
+
+                        class ExampleClass
+                            @Inject
+                            constructor(private val context: Context)
+                    """
+                        .trimIndent()
+                ),
+                *androidStubs,
+                *otherStubs,
+            )
+            .issues(ShadeDisplayAwareDetector.ISSUE)
+            .testModes(TestMode.DEFAULT)
+            .run()
+            .expectErrorCount(1)
+            .expectContains(errorMsgString(8, "Context"))
+            .expectContains("[ShadeDisplayAwareContextChecker]")
+            .expectContains(
+                "constructor(private val context: Context)\n" +
+                    "                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
+            )
+            .expectContains("1 errors, 0 warnings")
+    }
+
+    @Test
+    fun injectedConstructor_inRelevantPackage_withMultipleRelevantParameters_withoutAnnotation() {
+        lint()
+            .files(
+                TestFiles.kotlin(
+                    """
+                        package com.android.systemui.shade.example
+
+                        import javax.inject.Inject
+                        import android.content.Context
+                        import android.content.res.Resources
+                        import android.view.LayoutInflater
+                        import android.view.WindowManager
+                        import com.android.systemui.common.ui.ConfigurationState
+                        import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
+                        import com.android.systemui.statusbar.policy.ConfigurationController
+
+                        class ExampleClass
+                            @Inject
+                            constructor(
+                                private val context: Context,
+                                private val inflater: LayoutInflater,
+                                private val windowManager: WindowManager,
+                                private val configState: ConfigurationState,
+                                private val configController: ConfigurationController,
+                                private val configInteractor: ConfigurationInteractor,
+                            )
+                    """
+                        .trimIndent()
+                ),
+                *androidStubs,
+                *otherStubs,
+            )
+            .issues(ShadeDisplayAwareDetector.ISSUE)
+            .testModes(TestMode.DEFAULT)
+            .run()
+            .expectErrorCount(6)
+            .expectContains(errorMsgString(lineNumber = 15, className = "Context"))
+            .expectContains(
+                "private val context: Context,\n" + "        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
+            )
+            .expectContains(errorMsgString(lineNumber = 16, className = "LayoutInflater"))
+            .expectContains(
+                "private val inflater: LayoutInflater,\n" +
+                    "        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
+            )
+            .expectContains(errorMsgString(lineNumber = 17, className = "WindowManager"))
+            .expectContains(
+                "private val windowManager: WindowManager,\n" +
+                    "        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
+            )
+            .expectContains(errorMsgString(lineNumber = 18, className = "ConfigurationState"))
+            .expectContains(
+                "private val configState: ConfigurationState,\n" +
+                    "        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
+            )
+            .expectContains(errorMsgString(lineNumber = 19, className = "ConfigurationController"))
+            .expectContains(
+                "private val configController: ConfigurationController,\n" +
+                    "        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
+            )
+            .expectContains(errorMsgString(lineNumber = 20, className = "ConfigurationInteractor"))
+            .expectContains(
+                "private val configInteractor: ConfigurationInteractor,\n" +
+                    "        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
+            )
+            .expectContains(" [ShadeDisplayAwareContextChecker]")
+    }
+
+    @Test
+    fun injectedConstructor_inRelevantPackage_withRelevantParameter_withAnnotation() {
+        lint()
+            .files(
+                TestFiles.kotlin(
+                    """
+                        package com.android.systemui.shade.example
+
+                        import javax.inject.Inject
+                        import android.content.Context
+                        import com.android.systemui.shade.ShadeDisplayAware
+
+                        class ExampleClass
+                            @Inject
+                            constructor(@ShadeDisplayAware private val context: Context)
+                    """
+                        .trimIndent()
+                ),
+                *androidStubs,
+                *otherStubs,
+            )
+            .issues(ShadeDisplayAwareDetector.ISSUE)
+            .testModes(TestMode.DEFAULT)
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun injectedConstructor_inRelevantPackage_withoutRelevantParameter_withoutAnnotation() {
+        lint()
+            .files(
+                TestFiles.kotlin(
+                    """
+                        package com.android.systemui.shade.example
+
+                        import javax.inject.Inject
+                        import android.content.ContextWrapper
+
+                        class ExampleClass
+                            @Inject
+                            constructor(private val contextWrapper: ContextWrapper)
+                    """
+                        .trimIndent()
+                ),
+                *androidStubs,
+                *otherStubs,
+            )
+            .issues(ShadeDisplayAwareDetector.ISSUE)
+            .testModes(TestMode.DEFAULT)
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun injectedConstructor_notInRelevantPackage_withRelevantParameter_withoutAnnotation() {
+        lint()
+            .files(
+                TestFiles.kotlin(
+                    """
+                        package com.android.systemui.keyboard
+
+                        import javax.inject.Inject
+                        import android.content.Context
+
+                        class ExampleClass @Inject constructor(private val context: Context)
+                    """
+                        .trimIndent()
+                ),
+                *androidStubs,
+                *otherStubs,
+            )
+            .issues(ShadeDisplayAwareDetector.ISSUE)
+            .testModes(TestMode.DEFAULT)
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun nonInjectedConstructor_inRelevantPackage_withRelevantParameter_withoutAnnotation() {
+        lint()
+            .files(
+                TestFiles.kotlin(
+                    """
+                        package com.android.systemui.shade.example
+
+                        import android.content.Context
+
+                        class ExampleClass(private val context: Context)
+                    """
+                        .trimIndent()
+                ),
+                *androidStubs,
+                *otherStubs,
+            )
+            .issues(ShadeDisplayAwareDetector.ISSUE)
+            .testModes(TestMode.DEFAULT)
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun injectedConstructor_inRelevantPackage_withRelevantParameter_withoutAnnotation_suppressed() {
+        lint()
+            .files(
+                TestFiles.kotlin(
+                    """
+                        package com.android.systemui.shade.example
+
+                        import javax.inject.Inject
+                        import android.content.Context
+
+                        @Suppress("ShadeDisplayAwareContextChecker")
+                        class ExampleClass
+                            @Inject
+                            constructor(
+                                private val context: Context
+                            )
+                    """
+                        .trimIndent()
+                ),
+                *androidStubs,
+                *otherStubs,
+            )
+            .issues(ShadeDisplayAwareDetector.ISSUE)
+            .testModes(TestMode.DEFAULT)
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun injectedConstructor_inExemptPackage_withRelevantParameter_withoutAnnotation() {
+        lint()
+            .files(
+                TestFiles.java(
+                    """
+                        package com.android.systemui.qs.customize;
+
+                        import javax.inject.Inject;
+                        import com.android.systemui.qs.dagger.QSThemedContext;
+                        import android.content.Context;
+
+                        public class TileAdapter {
+                            @Inject
+                            public TileAdapter(@QSThemedContext Context context) {}
+                        }
+                    """
+                        .trimIndent()
+                ),
+                *androidStubs,
+                *otherStubs,
+            )
+            .issues(ShadeDisplayAwareDetector.ISSUE)
+            .testModes(TestMode.DEFAULT)
+            .run()
+            .expectClean()
+    }
+
+    private fun errorMsgString(lineNumber: Int, className: String) =
+        """
+        src/com/android/systemui/shade/example/ExampleClass.kt:$lineNumber: Error: UI elements of the shade window
+        should use ShadeDisplayAware-annotated $className, as the shade might move between windows, and only
+        @ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so
+        might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).
+        If the usage of $className is not related to display specific configuration or UI, then there is
+        technically no need to use the annotation, and you can annotate the class with
+        @SuppressLint("ShadeDisplayAwareContextChecker")/@Suppress("ShadeDisplayAwareContextChecker")
+    """
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
index 787edfb..573e5ca 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
@@ -66,6 +66,7 @@
 import androidx.compose.foundation.layout.wrapContentHeight
 import androidx.compose.foundation.lazy.grid.GridCells
 import androidx.compose.foundation.lazy.grid.GridItemSpan
+import androidx.compose.foundation.lazy.grid.LazyGridScope
 import androidx.compose.foundation.lazy.grid.LazyGridState
 import androidx.compose.foundation.lazy.grid.LazyHorizontalGrid
 import androidx.compose.foundation.lazy.grid.itemsIndexed
@@ -169,6 +170,7 @@
 import com.android.compose.ui.graphics.painter.rememberDrawablePainter
 import com.android.internal.R.dimen.system_app_widget_background_radius
 import com.android.systemui.Flags
+import com.android.systemui.Flags.communalResponsiveGrid
 import com.android.systemui.Flags.communalTimerFlickerFix
 import com.android.systemui.Flags.communalWidgetResizing
 import com.android.systemui.communal.domain.model.CommunalContentModel
@@ -194,7 +196,6 @@
 import com.android.systemui.statusbar.phone.SystemUIDialogFactory
 import kotlin.math.max
 import kotlin.math.min
-import kotlin.math.roundToInt
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.launch
 
@@ -693,7 +694,12 @@
             onResize = onResize,
             minHeightPx = minHeightPx,
             maxHeightPx = maxHeightPx,
-            resizeMultiple = CommunalContentSize.HALF.span,
+            resizeMultiple =
+                if (communalResponsiveGrid()) {
+                    1
+                } else {
+                    CommunalContentSize.FixedSize.HALF.span
+                },
         ) {
             content(Modifier)
         }
@@ -701,14 +707,22 @@
 }
 
 @Composable
-fun calculateWidgetSize(item: CommunalContentModel, isResizable: Boolean): WidgetSizeInfo {
+fun calculateWidgetSize(
+    cellHeight: Dp?,
+    availableHeight: Dp?,
+    item: CommunalContentModel,
+    isResizable: Boolean,
+): WidgetSizeInfo {
     val density = LocalDensity.current
 
+    val minHeight = cellHeight ?: CommunalContentSize.FixedSize.HALF.dp()
+    val maxHeight = availableHeight ?: CommunalContentSize.FixedSize.FULL.dp()
+
     return if (isResizable && item is CommunalContentModel.WidgetContent.Widget) {
         with(density) {
             val minHeightPx =
                 (min(item.providerInfo.minResizeHeight, item.providerInfo.minHeight)
-                    .coerceAtLeast(CommunalContentSize.HALF.dp().toPx().roundToInt()))
+                    .coerceAtLeast(minHeight.roundToPx()))
 
             val maxHeightPx =
                 (if (item.providerInfo.maxResizeHeight > 0) {
@@ -716,7 +730,7 @@
                     } else {
                         Int.MAX_VALUE
                     })
-                    .coerceIn(minHeightPx, CommunalContentSize.FULL.dp().toPx().roundToInt())
+                    .coerceIn(minHeightPx, maxHeight.roundToPx())
 
             WidgetSizeInfo(minHeightPx, maxHeightPx)
         }
@@ -725,6 +739,37 @@
     }
 }
 
+@Composable
+private fun HorizontalGridWrapper(
+    contentPadding: PaddingValues,
+    gridState: LazyGridState,
+    modifier: Modifier = Modifier,
+    content: LazyGridScope.(sizeInfo: SizeInfo?) -> Unit,
+) {
+    if (communalResponsiveGrid()) {
+        ResponsiveLazyHorizontalGrid(
+            cellAspectRatio = 1.5f,
+            modifier = modifier,
+            state = gridState,
+            minContentPadding = contentPadding,
+            minHorizontalArrangement = Dimensions.ItemSpacing,
+            minVerticalArrangement = Dimensions.ItemSpacing,
+            content = content,
+        )
+    } else {
+        LazyHorizontalGrid(
+            modifier = modifier,
+            state = gridState,
+            rows = GridCells.Fixed(CommunalContentSize.FixedSize.FULL.span),
+            contentPadding = contentPadding,
+            horizontalArrangement = Arrangement.spacedBy(Dimensions.ItemSpacing),
+            verticalArrangement = Arrangement.spacedBy(Dimensions.ItemSpacing),
+        ) {
+            content(null)
+        }
+    }
+}
+
 @OptIn(ExperimentalFoundationApi::class)
 @Composable
 private fun BoxScope.CommunalHubLazyGrid(
@@ -778,28 +823,32 @@
         // Since the grid has its own listener for in-grid drag events, we use a separate element
         // for android drag events.
         Box(Modifier.fillMaxSize().dragAndDropTarget(dragAndDropTargetState)) {}
+    } else if (communalResponsiveGrid()) {
+        gridModifier = gridModifier.fillMaxSize()
     } else {
         gridModifier = gridModifier.height(hubDimensions.GridHeight)
     }
 
-    val itemArrangement = Arrangement.spacedBy(Dimensions.ItemSpacing)
-    LazyHorizontalGrid(
+    HorizontalGridWrapper(
         modifier = gridModifier,
-        state = gridState,
-        rows = GridCells.Fixed(CommunalContentSize.FULL.span),
+        gridState = gridState,
         contentPadding = contentPadding,
-        horizontalArrangement = itemArrangement,
-        verticalArrangement = itemArrangement,
-    ) {
+    ) { sizeInfo ->
         itemsIndexed(
             items = list,
             key = { _, item -> item.key },
             contentType = { _, item -> item.key },
-            span = { _, item -> GridItemSpan(item.size.span) },
+            span = { _, item -> GridItemSpan(item.getSpanOrMax(sizeInfo?.gridSize?.height)) },
         ) { index, item ->
-            val size = SizeF(Dimensions.CardWidth.value, item.size.dp().value)
+            val currentItemSpan = item.getSpanOrMax(sizeInfo?.gridSize?.height)
+            val dpSize =
+                if (sizeInfo != null) {
+                    DpSize(sizeInfo.cellSize.width, sizeInfo.calculateHeight(currentItemSpan))
+                } else {
+                    DpSize(Dimensions.CardWidth, (item.size as CommunalContentSize.FixedSize).dp())
+                }
+            val size = SizeF(dpSize.width.value, dpSize.height.value)
             val selected = item.key == selectedKey.value
-            val dpSize = DpSize(size.width.dp, size.height.dp)
             val isResizable =
                 if (item is CommunalContentModel.WidgetContent.Widget) {
                     item.providerInfo.resizeMode and AppWidgetProviderInfo.RESIZE_VERTICAL != 0
@@ -809,7 +858,7 @@
 
             val resizeableItemFrameViewModel =
                 rememberViewModel(
-                    key = item.size.span,
+                    key = currentItemSpan,
                     traceName = "ResizeableItemFrame.viewModel.$index",
                 ) {
                     ResizeableItemFrameViewModel()
@@ -822,13 +871,23 @@
                         animationSpec = spring(stiffness = Spring.StiffnessMediumLow),
                         label = "Widget resizing outline alpha",
                     )
-                val widgetSizeInfo = calculateWidgetSize(item, isResizable)
+
+                val widgetSizeInfo =
+                    calculateWidgetSize(
+                        cellHeight = sizeInfo?.cellSize?.height,
+                        availableHeight = sizeInfo?.availableHeight,
+                        item = item,
+                        isResizable = isResizable,
+                    )
                 ResizableItemFrameWrapper(
                     key = item.key,
-                    currentSpan = GridItemSpan(item.size.span),
+                    currentSpan = GridItemSpan(currentItemSpan),
                     gridState = gridState,
                     gridContentPadding = contentPadding,
-                    verticalArrangement = itemArrangement,
+                    verticalArrangement =
+                        Arrangement.spacedBy(
+                            sizeInfo?.verticalArrangement ?: Dimensions.ItemSpacing
+                        ),
                     enabled = selected,
                     alpha = { outlineAlpha },
                     modifier =
@@ -908,7 +967,7 @@
                 text = titleForEmptyStateCTA,
                 style = MaterialTheme.typography.displaySmall,
                 textAlign = TextAlign.Center,
-                color = colors.secondary,
+                color = colors.primary,
                 modifier =
                     Modifier.focusable().semantics(mergeDescendants = true) {
                         contentDescription = titleForEmptyStateCTA
@@ -1686,11 +1745,11 @@
     }
 }
 
-private fun CommunalContentSize.dp(): Dp {
+private fun CommunalContentSize.FixedSize.dp(): Dp {
     return when (this) {
-        CommunalContentSize.FULL -> Dimensions.CardHeightFull
-        CommunalContentSize.HALF -> Dimensions.CardHeightHalf
-        CommunalContentSize.THIRD -> Dimensions.CardHeightThird
+        CommunalContentSize.FixedSize.FULL -> Dimensions.CardHeightFull
+        CommunalContentSize.FixedSize.HALF -> Dimensions.CardHeightHalf
+        CommunalContentSize.FixedSize.THIRD -> Dimensions.CardHeightThird
     }
 }
 
@@ -1709,7 +1768,10 @@
     val GridTopSpacing: Dp
         get() {
             val result =
-                if (config.orientation == Configuration.ORIENTATION_LANDSCAPE) {
+                if (
+                    communalResponsiveGrid() ||
+                        config.orientation == Configuration.ORIENTATION_LANDSCAPE
+                ) {
                     114.dp
                 } else {
                     val windowMetrics =
@@ -1729,7 +1791,7 @@
             get() = 530.adjustedDp
 
         val ItemSpacing
-            get() = 50.adjustedDp
+            get() = if (communalResponsiveGrid()) 32.adjustedDp else 50.adjustedDp
 
         val CardHeightHalf
             get() = (CardHeightFull - ItemSpacing) / 2
@@ -1771,6 +1833,13 @@
 
 data class WidgetSizeInfo(val minHeightPx: Int, val maxHeightPx: Int)
 
+private fun CommunalContentModel.getSpanOrMax(maxSpan: Int?) =
+    if (maxSpan != null) {
+        size.span.coerceAtMost(maxSpan)
+    } else {
+        size.span
+    }
+
 private object Colors {
     val DisabledColorFilter by lazy { disabledColorMatrix() }
 
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ResponsiveLazyHorizontalGrid.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ResponsiveLazyHorizontalGrid.kt
index e331078..3642127 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ResponsiveLazyHorizontalGrid.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ResponsiveLazyHorizontalGrid.kt
@@ -147,9 +147,9 @@
                 SizeInfo(
                     cellSize = finalSize,
                     contentPadding = finalContentPadding,
-                    horizontalArrangement = minHorizontalArrangement,
                     verticalArrangement = minVerticalArrangement,
                     maxHeight = maxHeight,
+                    gridSize = gridSize,
                 )
             )
         }
@@ -176,16 +176,15 @@
  * Provides size info of the responsive grid, since the size is dynamic.
  *
  * @property cellSize The size of each cell in the grid.
- * @property contentPadding The final content padding of the grid.
- * @property horizontalArrangement The space between columns in the grid.
  * @property verticalArrangement The space between rows in the grid.
+ * @property gridSize The size of the grid, in cell units.
  * @property availableHeight The maximum height an item in the grid may occupy.
  */
 data class SizeInfo(
     val cellSize: DpSize,
-    val contentPadding: PaddingValues,
-    val horizontalArrangement: Dp,
     val verticalArrangement: Dp,
+    val gridSize: IntSize,
+    private val contentPadding: PaddingValues,
     private val maxHeight: Dp,
 ) {
     val availableHeight: Dp
@@ -193,6 +192,11 @@
             maxHeight -
                 contentPadding.calculateBottomPadding() -
                 contentPadding.calculateTopPadding()
+
+    /** Calculates the height in dp of a certain number of rows. */
+    fun calculateHeight(numRows: Int): Dp {
+        return numRows * cellSize.height + (numRows - 1) * verticalArrangement
+    }
 }
 
 @Composable
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
index 7a8d20a..caf5e41 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
@@ -124,7 +124,7 @@
         return newDragController
     }
 
-    internal fun createSwipeAnimation(swipes: Swipes, result: UserActionResult): SwipeAnimation<*> {
+    private fun createSwipeAnimation(swipes: Swipes, result: UserActionResult): SwipeAnimation<*> {
         val upOrLeftResult = swipes.upOrLeftResult
         val downOrRightResult = swipes.downOrRightResult
         val isUpOrLeft =
@@ -248,38 +248,8 @@
                 else -> desiredOffset.fastCoerceIn(distance, 0f)
             }
 
-        val consumedDelta = newOffset - previousOffset
-
         swipeAnimation.dragOffset = newOffset
-        val result = swipes.findUserActionResult(directionOffset = newOffset)
-
-        if (result == null) {
-            onCancel(canChangeContent = true)
-            return 0f
-        }
-
-        val currentTransitionIrreversible =
-            if (swipeAnimation.isUpOrLeft) {
-                swipes.upOrLeftResult?.isIrreversible ?: false
-            } else {
-                swipes.downOrRightResult?.isIrreversible ?: false
-            }
-
-        val needNewTransition =
-            !currentTransitionIrreversible &&
-                (result.toContent(layoutState.currentScene) != swipeAnimation.toContent ||
-                    result.transitionKey != swipeAnimation.contentTransition.key)
-
-        if (needNewTransition) {
-            // Make sure the current transition will finish to the right current scene.
-            swipeAnimation.currentContent = swipeAnimation.fromContent
-
-            val newSwipeAnimation = draggableHandler.createSwipeAnimation(swipes, result)
-            newSwipeAnimation.dragOffset = newOffset
-            updateTransition(newSwipeAnimation)
-        }
-
-        return consumedDelta
+        return newOffset - previousOffset
     }
 
     override suspend fun onStop(velocity: Float, canChangeContent: Boolean): Float {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
index 759100b..a14b2b3 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
@@ -554,12 +554,6 @@
      * bigger than 100% when the user released their finger. `
      */
     open val requiresFullDistanceSwipe: Boolean,
-
-    /**
-     * Whether swiping back in the opposite direction past the origin point of the swipe can replace
-     * the action with the action for the opposite direction.
-     */
-    open val isIrreversible: Boolean = false,
 ) {
     internal abstract fun toContent(currentScene: SceneKey): ContentKey
 
@@ -569,7 +563,6 @@
         val toScene: SceneKey,
         override val transitionKey: TransitionKey? = null,
         override val requiresFullDistanceSwipe: Boolean = false,
-        override val isIrreversible: Boolean = false,
     ) : UserActionResult(transitionKey, requiresFullDistanceSwipe) {
         override fun toContent(currentScene: SceneKey): ContentKey = toScene
     }
@@ -579,7 +572,6 @@
         val overlay: OverlayKey,
         override val transitionKey: TransitionKey? = null,
         override val requiresFullDistanceSwipe: Boolean = false,
-        override val isIrreversible: Boolean = false,
     ) : UserActionResult(transitionKey, requiresFullDistanceSwipe) {
         override fun toContent(currentScene: SceneKey): ContentKey = overlay
     }
@@ -622,14 +614,7 @@
              * the user released their finger.
              */
             requiresFullDistanceSwipe: Boolean = false,
-
-            /**
-             * Whether swiping back in the opposite direction past the origin point of the swipe can
-             * replace the action with the action for the opposite direction.
-             */
-            isIrreversible: Boolean = false,
-        ): UserActionResult =
-            ChangeScene(toScene, transitionKey, requiresFullDistanceSwipe, isIrreversible)
+        ): UserActionResult = ChangeScene(toScene, transitionKey, requiresFullDistanceSwipe)
 
         /** A [UserActionResult] that shows [toOverlay]. */
         operator fun invoke(
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
index 394568d..2c8dc32 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
@@ -418,37 +418,6 @@
     }
 
     @Test
-    fun onDragReversedDirection_changeToScene() = runGestureTest {
-        // Drag A -> B with progress 0.6
-        val dragController = onDragStarted(overSlop = -60f)
-        assertTransition(
-            currentScene = SceneA,
-            fromScene = SceneA,
-            toScene = SceneB,
-            progress = 0.6f,
-        )
-
-        // Reverse direction such that A -> C now with 0.4
-        dragController.onDragDelta(pixels = 100f)
-        assertTransition(
-            currentScene = SceneA,
-            fromScene = SceneA,
-            toScene = SceneC,
-            progress = 0.4f,
-        )
-
-        // After the drag stopped scene C should be committed
-        dragController.onDragStoppedAnimateNow(
-            velocity = velocityThreshold,
-            onAnimationStart = {
-                assertTransition(currentScene = SceneC, fromScene = SceneA, toScene = SceneC)
-            },
-            expectedConsumedVelocity = velocityThreshold,
-        )
-        assertIdle(currentScene = SceneC)
-    }
-
-    @Test
     fun onDragStartedWithoutActionsInBothDirections_stayIdle() = runGestureTest {
         onDragStarted(
             horizontalDraggableHandler,
@@ -498,31 +467,9 @@
     }
 
     @Test
-    fun onDragWithActionsInBothDirections_dragToOppositeDirectionReplacesAction() = runGestureTest {
-        // We are on SceneA. UP -> B, DOWN-> C.
-        val dragController = onDragStarted(overSlop = up(fractionOfScreen = 0.2f))
-        assertTransition(
-            currentScene = SceneA,
-            fromScene = SceneA,
-            toScene = SceneB,
-            progress = 0.2f,
-        )
-
-        // Reverse drag direction, it will replace the previous transition
-        dragController.onDragDelta(pixels = down(fractionOfScreen = 0.5f))
-        assertTransition(
-            currentScene = SceneA,
-            fromScene = SceneA,
-            toScene = SceneC,
-            progress = 0.3f,
-        )
-    }
-
-    @Test
     fun onDragWithActionsInBothDirections_dragToOppositeDirectionNotReplaceable() = runGestureTest {
         // We are on SceneA. UP -> B, DOWN-> C. The up swipe is not replaceable though.
-        mutableUserActionsA =
-            mapOf(Swipe.Up to UserActionResult(SceneB, isIrreversible = true), Swipe.Down to SceneC)
+        mutableUserActionsA = mapOf(Swipe.Up to UserActionResult(SceneB), Swipe.Down to SceneC)
         val dragController =
             onDragStarted(
                 pointersInfo =
@@ -536,7 +483,7 @@
             progress = 0.2f,
         )
 
-        // Reverse drag direction, it cannot replace the previous transition
+        // Reverse drag direction, it does not replace the previous transition.
         dragController.onDragDelta(pixels = down(fractionOfScreen = 0.5f))
         assertTransition(
             currentScene = SceneA,
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
index b3a3261..fe7b5b6 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
@@ -664,17 +664,11 @@
             }
         }
 
-        // Swipe down for the default transition from A to B.
-        rule.onRoot().performTouchInput {
-            down(middle)
-            moveBy(Offset(0f, touchSlop), delayMillis = 1_000)
-        }
-
-        assertThat(state.isTransitioning(from = SceneA, to = SceneB)).isTrue()
-        assertThat(state.currentTransition?.transformationSpec?.transformationMatchers).hasSize(1)
-
         // Move the pointer up to swipe to scene B using the new transition.
-        rule.onRoot().performTouchInput { moveBy(Offset(0f, -1.dp.toPx()), delayMillis = 1_000) }
+        rule.onRoot().performTouchInput {
+            down(center)
+            moveBy(Offset(0f, -touchSlop - 1.dp.toPx()), delayMillis = 1_000)
+        }
         assertThat(state.isTransitioning(from = SceneA, to = SceneB)).isTrue()
         assertThat(state.currentTransition?.transformationSpec?.transformationMatchers).hasSize(2)
     }
diff --git a/packages/SystemUI/lint-baseline.xml b/packages/SystemUI/lint-baseline.xml
index 7577147..00b0c44 100644
--- a/packages/SystemUI/lint-baseline.xml
+++ b/packages/SystemUI/lint-baseline.xml
@@ -32784,4 +32784,984 @@
             column="23"/>
     </issue>
 
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="constructor(@Main private val resources: Resources, val theme: Theme) :"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/airplane/domain/AirplaneModeMapper.kt"
+            line="33"
+            column="13"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Main private val resources: Resources,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/AlarmTileMapper.kt"
+            line="39"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="            @NonNull Context context,"
+        errorLine2="                             ~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java"
+            line="300"
+            column="30"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="            Context context, DeviceConfigProxy proxy) {"
+        errorLine2="                    ~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/notification/AssistantFeedbackController.java"
+            line="75"
+            column="21"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    public AuthController(Context context,"
+        errorLine2="                                  ~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java"
+            line="716"
+            column="35"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated WindowManager, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of WindowManager is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="            @NonNull WindowManager windowManager,"
+        errorLine2="                                   ~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java"
+            line="721"
+            column="36"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    private val sysuiContext: Context,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt"
+            line="72"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated ConfigurationController, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of ConfigurationController is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    private val configurationController: ConfigurationController,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt"
+            line="74"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="constructor(@Main protected val resources: Resources, private val theme: Resources.Theme) :"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/battery/ui/BatterySaverTileMapper.kt"
+            line="32"
+            column="13"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="            Context context,"
+        errorLine2="                    ~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationBroadcastReceiver.java"
+            line="46"
+            column="21"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="            @Main Resources resources,"
+        errorLine2="                            ~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationDialogFactory.java"
+            line="52"
+            column="29"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    public BiometricNotificationService(@NonNull Context context,"
+        errorLine2="                                                         ~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationService.java"
+            line="148"
+            column="58"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Application private val applicationContext: Context,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractor.kt"
+            line="62"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Application private val applicationContext: Context,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/BouncerRepository.kt"
+            line="37"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    c: Context,"
+        errorLine2="    ~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt"
+            line="61"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="constructor(@Main private val resources: Resources, private val theme: Resources.Theme) :"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/ColorCorrectionTileMapper.kt"
+            line="32"
+            column="13"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="constructor(@Main private val resources: Resources, private val theme: Theme) :"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/inversion/domain/ColorInversionTileMapper.kt"
+            line="33"
+            column="13"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Application private val applicationContext: Context,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/CredentialInteractor.kt"
+            line="52"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Application private val applicationContext: Context,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialViewModel.kt"
+            line="30"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="class CustomTileStatePersisterImpl @Inject constructor(context: Context) :"
+        errorLine2="                                                       ~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/external/CustomTileStatePersister.kt"
+            line="74"
+            column="56"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="constructor(@Main private val resources: Resources, private val theme: Resources.Theme) :"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverTileMapper.kt"
+            line="32"
+            column="13"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Main private val resources: Resources,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/DefaultTilesRepository.kt"
+            line="18"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Application context: Context,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractor.kt"
+            line="77"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Application val context: Context,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/DisplayStateRepository.kt"
+            line="68"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Main private val resources: Resources,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/EmergencyServicesRepository.kt"
+            line="38"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Main private val resources: Resources,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/FaceAuthAccessibilityDelegate.kt"
+            line="37"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Main private val resources: Resources,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/FaceHelpMessageDeferral.kt"
+            line="42"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Application val applicationContext: Context,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FacePropertyRepository.kt"
+            line="95"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Main private val resources: Resources,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt"
+            line="142"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Application private val context: Context,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt"
+            line="44"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="constructor(@Main private val resources: Resources, private val theme: Theme) :"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/flashlight/domain/FlashlightMapper.kt"
+            line="33"
+            column="13"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="constructor(@Main private val resources: Resources, private val theme: Resources.Theme) :"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/fontscaling/domain/FontScalingTileMapper.kt"
+            line="32"
+            column="13"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="            @NonNull final Context context,"
+        errorLine2="                                   ~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java"
+            line="186"
+            column="36"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated ConfigurationController, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of ConfigurationController is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="            ConfigurationController configurationController,"
+        errorLine2="                                    ~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java"
+            line="192"
+            column="37"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="constructor(@Main private val resources: Resources, private val theme: Resources.Theme) :"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/hearingdevices/domain/HearingDevicesTileMapper.kt"
+            line="32"
+            column="13"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="class IconBuilder @Inject constructor(private val context: Context) {"
+        errorLine2="                                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconBuilder.kt"
+            line="27"
+            column="39"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="constructor(@Main private val resources: Resources, private val theme: Theme) :"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/irecording/IssueRecordingMapper.kt"
+            line="31"
+            column="13"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated WindowManager, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of WindowManager is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    private val windowManager: WindowManager,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/keyboard/docking/ui/viewmodel/KeyboardDockingIndicationViewModel.kt"
+            line="39"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    private val context: Context,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/keyboard/docking/ui/viewmodel/KeyboardDockingIndicationViewModel.kt"
+            line="40"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Main private val resources: Resources,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/LargeTileSpanRepository.kt"
+            line="41"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="constructor(@Main private val resources: Resources, private val theme: Theme) :"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/location/domain/LocationTileMapper.kt"
+            line="33"
+            column="13"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated LayoutInflater, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of LayoutInflater is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    private val layoutInflater: LayoutInflater"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/MediaContainerController.kt"
+            line="29"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="class MinimumTilesResourceRepository @Inject constructor(@Main resources: Resources) :"
+        errorLine2="                                                         ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/MinimumTilesRepository.kt"
+            line="38"
+            column="58"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="constructor(@Main private val resources: Resources, val theme: Resources.Theme) :"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/modes/ui/ModesTileMapper.kt"
+            line="33"
+            column="13"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Application private val context: Context,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/night/domain/interactor/NightDisplayTileDataInteractor.kt"
+            line="38"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Main private val resources: Resources,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/night/ui/NightDisplayTileMapper.kt"
+            line="42"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="constructor(@Main private val resources: Resources, private val theme: Resources.Theme) :"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/notes/domain/NotesTileMapper.kt"
+            line="32"
+            column="13"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    public NotificationGutsManager(Context context,"
+        errorLine2="                                           ~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java"
+            line="137"
+            column="44"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Main resources: Resources,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt"
+            line="47"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Main resources: Resources,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt"
+            line="53"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="constructor(val context: Context) {"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt"
+            line="27"
+            column="13"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated ConfigurationController, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of ConfigurationController is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="            ConfigurationController configurationController,"
+        errorLine2="                                    ~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java"
+            line="737"
+            column="37"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Main private val resources: Resources,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt"
+            line="63"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="        Builder(@Main Resources resources, ViewConfiguration viewConfiguration,"
+        errorLine2="                                ~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java"
+            line="563"
+            column="33"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="constructor(@Main private val resources: Resources, private val theme: Resources.Theme) :"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/onehanded/ui/OneHandedModeTileMapper.kt"
+            line="32"
+            column="13"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    public PackageManagerAdapter(Context context) {"
+        errorLine2="                                         ~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/external/PackageManagerAdapter.java"
+            line="45"
+            column="42"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Main private val resources: Resources,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/PaginatedGridRepository.kt"
+            line="36"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    private val context: Context,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt"
+            line="74"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    private val context: Context,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractor.kt"
+            line="41"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Application private val context: Context,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt"
+            line="82"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="constructor(@Main private val resources: Resources, private val theme: Resources.Theme) :"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/qr/ui/QRCodeScannerTileMapper.kt"
+            line="32"
+            column="13"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Main private val resources: Resources,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QSColumnsRepository.kt"
+            line="36"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="        Factory(Context context, QSCustomizerController qsCustomizerController) {"
+        errorLine2="                        ~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/QSTileRevealController.java"
+            line="99"
+            column="25"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Main private val resources: Resources,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QuickQuickSettingsRowRepository.kt"
+            line="32"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="constructor(@Main private val resources: Resources, private val theme: Resources.Theme) :"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/reducebrightness/ui/ReduceBrightColorsTileMapper.kt"
+            line="33"
+            column="13"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Main private val resources: Resources,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/reducebrightness/domain/interactor/ReduceBrightColorsTileUserActionInteractor.kt"
+            line="36"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Main private val resources: Resources,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/domain/interactor/RotationLockTileDataInteractor.kt"
+            line="47"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Main private val resources: Resources,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/rotation/ui/mapper/RotationLockTileMapper.kt"
+            line="36"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Main private val resources: Resources,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/autoaddable/SafetyCenterAutoAddable.kt"
+            line="51"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="constructor(@Main private val resources: Resources, private val theme: Resources.Theme) :"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/ui/ScreenRecordTileMapper.kt"
+            line="33"
+            column="13"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated LayoutInflater, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of LayoutInflater is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    private val layoutInflater: LayoutInflater,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/SectionHeaderController.kt"
+            line="43"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    context: Context"
+        errorLine2="    ~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/SectionHeaderVisibilityProvider.kt"
+            line="35"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Application private val applicationContext: Context,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt"
+            line="63"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Application private val applicationContext: Context,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt"
+            line="53"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    private val context: Context,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt"
+            line="51"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated WindowManager, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of WindowManager is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    windowManager: WindowManager,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt"
+            line="53"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Application private val applicationContext: Context,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/SimBouncerInteractor.kt"
+            line="60"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Main private val resources: Resources,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/SimBouncerInteractor.kt"
+            line="65"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Main resources: Resources,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/SimBouncerRepository.kt"
+            line="91"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="constructor(context: Context, val shadeViewController: ShadeViewController) {"
+        errorLine2="            ~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/shade/StatusBarLongPressGestureDetector.kt"
+            line="30"
+            column="13"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Main private val resources: Resources,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/StockTilesRepository.kt"
+            line="31"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    private val context: Context"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolver.kt"
+            line="33"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Main private val resources: Resources,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/TileSpecRepository.kt"
+            line="95"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Main private val resources: Resources,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardAccessibilityDelegate.kt"
+            line="33"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Context is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Application private val context: Context,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt"
+            line="49"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated ConfigurationController, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of ConfigurationController is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    private val configurationController: ConfigurationController,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/interactor/UiModeNightTileDataInteractor.kt"
+            line="43"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="constructor(@Main private val resources: Resources, private val theme: Theme) :"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileMapper.kt"
+            line="37"
+            column="13"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated Resources, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of Resources is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @Main private val resources: Resources,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/work/ui/WorkModeTileMapper.kt"
+            line="36"
+            column="5"/>
+    </issue>
+
+    <issue
+        id="ShadeDisplayAwareContextChecker"
+        message="UI elements of the shade window&#xA;should use ShadeDisplayAware-annotated ConfigurationInteractor, as the shade might move between windows, and only&#xA;@ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so&#xA;might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme).&#xA;If the usage of ConfigurationInteractor is not related to display specific configuration or UI, then there is&#xA;technically no need to use the annotation, and you can annotate the class with&#xA;@SuppressLint(&quot;ShadeDisplayAwareContextChecker&quot;)/@Suppress(&quot;ShadeDisplayAwareContextChecker&quot;)"
+        errorLine1="    @GlobalConfig configurationInteractor: ConfigurationInteractor,"
+        errorLine2="    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="frameworks/base/packages/SystemUI/src/com/android/systemui/keyboard/docking/ui/viewmodel/KeyboardDockingIndicationViewModel.kt"
+            line="43"
+            column="5"/>
+    </issue>
+
+
 </issues>
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/db/DefaultWidgetPopulationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/db/DefaultWidgetPopulationTest.kt
index 596db07..f1c58a2 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/db/DefaultWidgetPopulationTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/db/DefaultWidgetPopulationTest.kt
@@ -24,6 +24,7 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.communal.data.db.DefaultWidgetPopulation.SkipReason.RESTORED_FROM_BACKUP
+import com.android.systemui.communal.shared.model.SpanValue
 import com.android.systemui.communal.widgets.CommunalWidgetHost
 import com.android.systemui.kosmos.applicationCoroutineScope
 import com.android.systemui.kosmos.testScope
@@ -117,7 +118,7 @@
                     componentName = defaultWidgets[0],
                     rank = 0,
                     userSerialNumber = 0,
-                    spanY = 3,
+                    spanY = SpanValue.Fixed(3),
                 )
             verify(communalWidgetDao)
                 .addWidget(
@@ -125,7 +126,7 @@
                     componentName = defaultWidgets[1],
                     rank = 1,
                     userSerialNumber = 0,
-                    spanY = 3,
+                    spanY = SpanValue.Fixed(3),
                 )
             verify(communalWidgetDao)
                 .addWidget(
@@ -133,7 +134,7 @@
                     componentName = defaultWidgets[2],
                     rank = 2,
                     userSerialNumber = 0,
-                    spanY = 3,
+                    spanY = SpanValue.Fixed(3),
                 )
         }
 
@@ -155,7 +156,7 @@
                     componentName = any(),
                     rank = anyInt(),
                     userSerialNumber = anyInt(),
-                    spanY = anyInt(),
+                    spanY = any(),
                 )
         }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryLocalImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryLocalImplTest.kt
index 55d7d08..335e399 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryLocalImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryLocalImplTest.kt
@@ -24,11 +24,15 @@
 import android.content.applicationContext
 import android.graphics.Bitmap
 import android.os.UserHandle
+import android.os.UserManager
 import android.os.userManager
+import android.platform.test.annotations.DisableFlags
 import android.platform.test.annotations.EnableFlags
-import androidx.test.ext.junit.runners.AndroidJUnit4
+import android.platform.test.flag.junit.FlagsParameterization
 import androidx.test.filters.SmallTest
+import com.android.systemui.Flags.FLAG_COMMUNAL_RESPONSIVE_GRID
 import com.android.systemui.Flags.FLAG_COMMUNAL_WIDGET_RESIZING
+import com.android.systemui.Flags.communalResponsiveGrid
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.common.data.repository.fakePackageChangeRepository
 import com.android.systemui.common.shared.model.PackageInstallSession
@@ -40,11 +44,15 @@
 import com.android.systemui.communal.nano.CommunalHubState
 import com.android.systemui.communal.proto.toByteArray
 import com.android.systemui.communal.shared.model.CommunalWidgetContentModel
+import com.android.systemui.communal.shared.model.SpanValue
 import com.android.systemui.communal.widgets.CommunalAppWidgetHost
 import com.android.systemui.communal.widgets.CommunalWidgetHost
 import com.android.systemui.communal.widgets.widgetConfiguratorFail
 import com.android.systemui.communal.widgets.widgetConfiguratorSuccess
-import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runCurrent
+import com.android.systemui.kosmos.runTest
 import com.android.systemui.kosmos.testDispatcher
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.log.LogBuffer
@@ -52,48 +60,55 @@
 import com.android.systemui.res.R
 import com.android.systemui.testKosmos
 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.Test
 import org.junit.runner.RunWith
 import org.mockito.ArgumentMatchers.anyInt
-import org.mockito.Mock
 import org.mockito.Mockito.eq
 import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
 import org.mockito.kotlin.any
 import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.doReturn
 import org.mockito.kotlin.mock
 import org.mockito.kotlin.whenever
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
 
-@OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
-@RunWith(AndroidJUnit4::class)
-class CommunalWidgetRepositoryLocalImplTest : SysuiTestCase() {
-    @Mock private lateinit var appWidgetHost: CommunalAppWidgetHost
-    @Mock private lateinit var providerInfoA: AppWidgetProviderInfo
-    @Mock private lateinit var providerInfoB: AppWidgetProviderInfo
-    @Mock private lateinit var providerInfoC: AppWidgetProviderInfo
-    @Mock private lateinit var communalWidgetHost: CommunalWidgetHost
-    @Mock private lateinit var communalWidgetDao: CommunalWidgetDao
-    @Mock private lateinit var backupManager: BackupManager
+@RunWith(ParameterizedAndroidJunit4::class)
+class CommunalWidgetRepositoryLocalImplTest(flags: FlagsParameterization) : SysuiTestCase() {
+    private val kosmos = testKosmos()
+
+    private val appWidgetHost = mock<CommunalAppWidgetHost>()
+    private val providerInfoA = mock<AppWidgetProviderInfo>()
+    private val providerInfoB = mock<AppWidgetProviderInfo>()
+    private val providerInfoC = mock<AppWidgetProviderInfo>()
 
     private val communalHubStateCaptor = argumentCaptor<CommunalHubState>()
     private val componentNameCaptor = argumentCaptor<ComponentName>()
 
-    private lateinit var backupUtils: CommunalBackupUtils
-    private lateinit var logBuffer: LogBuffer
-    private lateinit var fakeWidgets: MutableStateFlow<Map<CommunalItemRank, CommunalWidgetItem>>
-    private lateinit var fakeProviders: MutableStateFlow<Map<Int, AppWidgetProviderInfo?>>
+    private val Kosmos.communalWidgetHost by
+        Kosmos.Fixture {
+            mock<CommunalWidgetHost> { on { appWidgetProviders } doReturn fakeProviders }
+        }
+    private val Kosmos.communalWidgetDao by
+        Kosmos.Fixture { mock<CommunalWidgetDao> { on { getWidgets() } doReturn fakeWidgets } }
 
-    private val kosmos = testKosmos()
-    private val testScope = kosmos.testScope
-    private val packageChangeRepository = kosmos.fakePackageChangeRepository
-    private val userManager = kosmos.userManager
+    private val Kosmos.backupManager by Kosmos.Fixture { mock<BackupManager>() }
+
+    private val Kosmos.backupUtils: CommunalBackupUtils by
+        Kosmos.Fixture { CommunalBackupUtils(applicationContext) }
+
+    private val Kosmos.logBuffer: LogBuffer by
+        Kosmos.Fixture { logcatLogBuffer(name = "CommunalWidgetRepoLocalImplTest") }
+
+    private val Kosmos.fakeWidgets: MutableStateFlow<Map<CommunalItemRank, CommunalWidgetItem>> by
+        Kosmos.Fixture { MutableStateFlow(emptyMap()) }
+
+    private val Kosmos.fakeProviders: MutableStateFlow<Map<Int, AppWidgetProviderInfo?>> by
+        Kosmos.Fixture { MutableStateFlow(emptyMap()) }
 
     private val mainUser = UserHandle(0)
     private val workProfile = UserHandle(10)
@@ -105,48 +120,49 @@
             "com.android.fake/WidgetProviderC",
         )
 
-    private lateinit var underTest: CommunalWidgetRepositoryLocalImpl
-
-    @Before
-    fun setUp() {
-        MockitoAnnotations.initMocks(this)
-        fakeWidgets = MutableStateFlow(emptyMap())
-        fakeProviders = MutableStateFlow(emptyMap())
-        logBuffer = logcatLogBuffer(name = "CommunalWidgetRepoLocalImplTest")
-        backupUtils = CommunalBackupUtils(kosmos.applicationContext)
-
-        setAppWidgetIds(emptyList())
-
-        overrideResource(R.array.config_communalWidgetAllowlist, fakeAllowlist.toTypedArray())
-
-        whenever(communalWidgetDao.getWidgets()).thenReturn(fakeWidgets)
-        whenever(communalWidgetHost.appWidgetProviders).thenReturn(fakeProviders)
-        whenever(userManager.mainUser).thenReturn(mainUser)
-
-        restoreUser(mainUser)
-
-        underTest =
+    private val Kosmos.underTest by
+        Kosmos.Fixture {
             CommunalWidgetRepositoryLocalImpl(
                 appWidgetHost,
                 testScope.backgroundScope,
-                kosmos.testDispatcher,
+                testDispatcher,
                 communalWidgetHost,
                 communalWidgetDao,
                 logBuffer,
                 backupManager,
                 backupUtils,
-                packageChangeRepository,
+                fakePackageChangeRepository,
                 userManager,
-                kosmos.defaultWidgetPopulation,
+                defaultWidgetPopulation,
             )
+        }
+
+    init {
+        mSetFlagsRule.setFlagsParameterization(flags)
+    }
+
+    @Before
+    fun setUp() {
+        kosmos.userManager = mock<UserManager> { on { mainUser } doReturn mainUser }
+        setAppWidgetIds(emptyList())
+        overrideResource(R.array.config_communalWidgetAllowlist, fakeAllowlist.toTypedArray())
+        restoreUser(mainUser)
     }
 
     @Test
     fun communalWidgets_queryWidgetsFromDb() =
-        testScope.runTest {
+        kosmos.runTest {
             val communalItemRankEntry = CommunalItemRank(uid = 1L, rank = 1)
             val communalWidgetItemEntry =
-                CommunalWidgetItem(uid = 1L, 1, "pk_name/cls_name", 1L, 0, 3)
+                CommunalWidgetItem(
+                    uid = 1L,
+                    widgetId = 1,
+                    componentName = "pk_name/cls_name",
+                    itemId = 1L,
+                    userSerialNumber = 0,
+                    spanY = 3,
+                    spanYNew = 1,
+                )
             fakeWidgets.value = mapOf(communalItemRankEntry to communalWidgetItemEntry)
             fakeProviders.value = mapOf(1 to providerInfoA)
 
@@ -158,7 +174,12 @@
                         appWidgetId = communalWidgetItemEntry.widgetId,
                         providerInfo = providerInfoA,
                         rank = communalItemRankEntry.rank,
-                        spanY = communalWidgetItemEntry.spanY,
+                        spanY =
+                            if (communalResponsiveGrid()) {
+                                communalWidgetItemEntry.spanYNew
+                            } else {
+                                communalWidgetItemEntry.spanY
+                            },
                     )
                 )
 
@@ -168,18 +189,50 @@
 
     @Test
     fun communalWidgets_widgetsWithoutMatchingProvidersAreSkipped() =
-        testScope.runTest {
+        kosmos.runTest {
             // Set up 4 widgets, but widget 3 and 4 don't have matching providers
             fakeWidgets.value =
                 mapOf(
                     CommunalItemRank(uid = 1L, rank = 1) to
-                        CommunalWidgetItem(uid = 1L, 1, "pk_1/cls_1", 1L, 0, 3),
+                        CommunalWidgetItem(
+                            uid = 1L,
+                            widgetId = 1,
+                            componentName = "pk_1/cls_1",
+                            itemId = 1L,
+                            userSerialNumber = 0,
+                            spanY = 3,
+                            spanYNew = 1,
+                        ),
                     CommunalItemRank(uid = 2L, rank = 2) to
-                        CommunalWidgetItem(uid = 2L, 2, "pk_2/cls_2", 2L, 0, 3),
+                        CommunalWidgetItem(
+                            uid = 2L,
+                            widgetId = 2,
+                            componentName = "pk_2/cls_2",
+                            itemId = 2L,
+                            userSerialNumber = 0,
+                            spanY = 3,
+                            spanYNew = 1,
+                        ),
                     CommunalItemRank(uid = 3L, rank = 3) to
-                        CommunalWidgetItem(uid = 3L, 3, "pk_3/cls_3", 3L, 0, 3),
+                        CommunalWidgetItem(
+                            uid = 3L,
+                            widgetId = 3,
+                            componentName = "pk_3/cls_3",
+                            itemId = 3L,
+                            userSerialNumber = 0,
+                            spanY = 3,
+                            spanYNew = 1,
+                        ),
                     CommunalItemRank(uid = 4L, rank = 4) to
-                        CommunalWidgetItem(uid = 4L, 4, "pk_4/cls_4", 4L, 0, 3),
+                        CommunalWidgetItem(
+                            uid = 4L,
+                            widgetId = 4,
+                            componentName = "pk_4/cls_4",
+                            itemId = 4L,
+                            userSerialNumber = 0,
+                            spanY = 3,
+                            spanYNew = 1,
+                        ),
                 )
             fakeProviders.value = mapOf(1 to providerInfoA, 2 to providerInfoB)
 
@@ -191,27 +244,43 @@
                         appWidgetId = 1,
                         providerInfo = providerInfoA,
                         rank = 1,
-                        spanY = 3,
+                        spanY = if (communalResponsiveGrid()) 1 else 3,
                     ),
                     CommunalWidgetContentModel.Available(
                         appWidgetId = 2,
                         providerInfo = providerInfoB,
                         rank = 2,
-                        spanY = 3,
+                        spanY = if (communalResponsiveGrid()) 1 else 3,
                     ),
                 )
         }
 
     @Test
     fun communalWidgets_updatedWhenProvidersUpdate() =
-        testScope.runTest {
+        kosmos.runTest {
             // Set up widgets and providers
             fakeWidgets.value =
                 mapOf(
                     CommunalItemRank(uid = 1L, rank = 1) to
-                        CommunalWidgetItem(uid = 1L, 1, "pk_1/cls_1", 1L, 0, 3),
+                        CommunalWidgetItem(
+                            uid = 1L,
+                            widgetId = 1,
+                            componentName = "pk_1/cls_1",
+                            itemId = 1L,
+                            userSerialNumber = 0,
+                            spanY = 3,
+                            spanYNew = 1,
+                        ),
                     CommunalItemRank(uid = 2L, rank = 2) to
-                        CommunalWidgetItem(uid = 2L, 2, "pk_2/cls_2", 2L, 0, 3),
+                        CommunalWidgetItem(
+                            uid = 2L,
+                            widgetId = 2,
+                            componentName = "pk_2/cls_2",
+                            itemId = 2L,
+                            userSerialNumber = 0,
+                            spanY = 6,
+                            spanYNew = 2,
+                        ),
                 )
             fakeProviders.value = mapOf(1 to providerInfoA, 2 to providerInfoB)
 
@@ -224,13 +293,13 @@
                         appWidgetId = 1,
                         providerInfo = providerInfoA,
                         rank = 1,
-                        spanY = 3,
+                        spanY = if (communalResponsiveGrid()) 1 else 3,
                     ),
                     CommunalWidgetContentModel.Available(
                         appWidgetId = 2,
                         providerInfo = providerInfoB,
                         rank = 2,
-                        spanY = 3,
+                        spanY = if (communalResponsiveGrid()) 2 else 6,
                     ),
                 )
 
@@ -245,20 +314,20 @@
                         // Verify that provider info updated
                         providerInfo = providerInfoC,
                         rank = 1,
-                        spanY = 3,
+                        spanY = if (communalResponsiveGrid()) 1 else 3,
                     ),
                     CommunalWidgetContentModel.Available(
                         appWidgetId = 2,
                         providerInfo = providerInfoB,
                         rank = 2,
-                        spanY = 3,
+                        spanY = if (communalResponsiveGrid()) 2 else 6,
                     ),
                 )
         }
 
     @Test
     fun addWidget_allocateId_bindWidget_andAddToDb() =
-        testScope.runTest {
+        kosmos.runTest {
             val provider = ComponentName("pkg_name", "cls_name")
             val id = 1
             val rank = 1
@@ -275,7 +344,8 @@
             runCurrent()
 
             verify(communalWidgetHost).allocateIdAndBindWidget(provider, mainUser)
-            verify(communalWidgetDao).addWidget(id, provider, rank, testUserSerialNumber(mainUser))
+            verify(communalWidgetDao)
+                .addWidget(id, provider, rank, testUserSerialNumber(mainUser), SpanValue.Fixed(3))
 
             // Verify backup requested
             verify(backupManager).dataChanged()
@@ -283,7 +353,7 @@
 
     @Test
     fun addWidget_configurationFails_doNotAddWidgetToDb() =
-        testScope.runTest {
+        kosmos.runTest {
             val provider = ComponentName("pkg_name", "cls_name")
             val id = 1
             val rank = 1
@@ -301,7 +371,7 @@
 
             verify(communalWidgetHost).allocateIdAndBindWidget(provider, mainUser)
             verify(communalWidgetDao, never())
-                .addWidget(anyInt(), any<ComponentName>(), anyInt(), anyInt(), anyInt())
+                .addWidget(anyInt(), any<ComponentName>(), anyInt(), anyInt(), any())
             verify(appWidgetHost).deleteAppWidgetId(id)
 
             // Verify backup not requested
@@ -310,7 +380,7 @@
 
     @Test
     fun addWidget_configurationThrowsError_doNotAddWidgetToDb() =
-        testScope.runTest {
+        kosmos.runTest {
             val provider = ComponentName("pkg_name", "cls_name")
             val id = 1
             val rank = 1
@@ -330,7 +400,7 @@
 
             verify(communalWidgetHost).allocateIdAndBindWidget(provider, mainUser)
             verify(communalWidgetDao, never())
-                .addWidget(anyInt(), any<ComponentName>(), anyInt(), anyInt(), anyInt())
+                .addWidget(anyInt(), any<ComponentName>(), anyInt(), anyInt(), any())
             verify(appWidgetHost).deleteAppWidgetId(id)
 
             // Verify backup not requested
@@ -339,7 +409,7 @@
 
     @Test
     fun addWidget_configurationNotRequired_doesNotConfigure_addWidgetToDb() =
-        testScope.runTest {
+        kosmos.runTest {
             val provider = ComponentName("pkg_name", "cls_name")
             val id = 1
             val rank = 1
@@ -356,7 +426,8 @@
             runCurrent()
 
             verify(communalWidgetHost).allocateIdAndBindWidget(provider, mainUser)
-            verify(communalWidgetDao).addWidget(id, provider, rank, testUserSerialNumber(mainUser))
+            verify(communalWidgetDao)
+                .addWidget(id, provider, rank, testUserSerialNumber(mainUser), SpanValue.Fixed(3))
 
             // Verify backup requested
             verify(backupManager).dataChanged()
@@ -364,7 +435,7 @@
 
     @Test
     fun deleteWidget_deleteFromDbTrue_alsoDeleteFromHost() =
-        testScope.runTest {
+        kosmos.runTest {
             val id = 1
             whenever(communalWidgetDao.deleteWidgetById(eq(id))).thenReturn(true)
             underTest.deleteWidget(id)
@@ -379,7 +450,7 @@
 
     @Test
     fun deleteWidget_deleteFromDbFalse_doesNotDeleteFromHost() =
-        testScope.runTest {
+        kosmos.runTest {
             val id = 1
             whenever(communalWidgetDao.deleteWidgetById(eq(id))).thenReturn(false)
             underTest.deleteWidget(id)
@@ -394,7 +465,7 @@
 
     @Test
     fun reorderWidgets_queryDb() =
-        testScope.runTest {
+        kosmos.runTest {
             val widgetIdToRankMap = mapOf(104 to 1, 103 to 2, 101 to 3)
             underTest.updateWidgetOrder(widgetIdToRankMap)
             runCurrent()
@@ -407,7 +478,7 @@
 
     @Test
     fun restoreWidgets_deleteStateFileIfRestoreFails() =
-        testScope.runTest {
+        kosmos.runTest {
             // Write a state file that is invalid, and verify it is written
             backupUtils.writeBytesToDisk(byteArrayOf(1, 2, 3, 4, 5, 6))
             assertThat(backupUtils.fileExists()).isTrue()
@@ -422,7 +493,7 @@
 
     @Test
     fun restoreWidgets_deleteStateFileAfterWidgetsRestored() =
-        testScope.runTest {
+        kosmos.runTest {
             // Write a state file, and verify it is written
             backupUtils.writeBytesToDisk(fakeState.toByteArray())
             assertThat(backupUtils.fileExists()).isTrue()
@@ -443,7 +514,7 @@
 
     @Test
     fun restoreWidgets_restoredWidgetsNotRegisteredWithHostAreSkipped() =
-        testScope.runTest {
+        kosmos.runTest {
             // Write fake state to file
             backupUtils.writeBytesToDisk(fakeState.toByteArray())
 
@@ -470,7 +541,7 @@
 
     @Test
     fun restoreWidgets_registeredWidgetsNotRestoredAreRemoved() =
-        testScope.runTest {
+        kosmos.runTest {
             // Write fake state to file
             backupUtils.writeBytesToDisk(fakeState.toByteArray())
 
@@ -504,7 +575,7 @@
 
     @Test
     fun restoreWidgets_onlySomeWidgetsGotNewIds() =
-        testScope.runTest {
+        kosmos.runTest {
             // Write fake state to file
             backupUtils.writeBytesToDisk(fakeState.toByteArray())
 
@@ -536,7 +607,7 @@
 
     @Test
     fun restoreWidgets_undefinedUser_restoredAsMain() =
-        testScope.runTest {
+        kosmos.runTest {
             // Write two widgets to file, both of which have user serial number undefined.
             val fakeState =
                 CommunalHubState().apply {
@@ -584,7 +655,7 @@
 
     @Test
     fun restoreWidgets_workProfileNotRestored_widgetSkipped() =
-        testScope.runTest {
+        kosmos.runTest {
             // Write fake state to file
             backupUtils.writeBytesToDisk(fakeStateWithWorkProfile.toByteArray())
 
@@ -610,7 +681,7 @@
 
     @Test
     fun restoreWidgets_workProfileRestored_manuallyBindWidget() =
-        testScope.runTest {
+        kosmos.runTest {
             // Write fake state to file
             backupUtils.writeBytesToDisk(fakeStateWithWorkProfile.toByteArray())
 
@@ -649,7 +720,7 @@
                     componentNameCaptor.capture(),
                     eq(2),
                     eq(testUserSerialNumber(workProfile)),
-                    anyInt(),
+                    any(),
                 )
 
             assertThat(componentNameCaptor.firstValue)
@@ -658,13 +729,29 @@
 
     @Test
     fun pendingWidgets() =
-        testScope.runTest {
+        kosmos.runTest {
             fakeWidgets.value =
                 mapOf(
                     CommunalItemRank(uid = 1L, rank = 1) to
-                        CommunalWidgetItem(uid = 1L, 1, "pk_1/cls_1", 1L, 0, 3),
+                        CommunalWidgetItem(
+                            uid = 1L,
+                            widgetId = 1,
+                            componentName = "pk_1/cls_1",
+                            itemId = 1L,
+                            userSerialNumber = 0,
+                            spanY = 3,
+                            spanYNew = 1,
+                        ),
                     CommunalItemRank(uid = 2L, rank = 2) to
-                        CommunalWidgetItem(uid = 2L, 2, "pk_2/cls_2", 2L, 0, 3),
+                        CommunalWidgetItem(
+                            uid = 2L,
+                            widgetId = 2,
+                            componentName = "pk_2/cls_2",
+                            itemId = 2L,
+                            userSerialNumber = 0,
+                            spanY = 3,
+                            spanYNew = 1,
+                        ),
                 )
 
             // Widget 1 is installed
@@ -672,7 +759,7 @@
 
             // Widget 2 is pending install
             val fakeIcon = mock<Bitmap>()
-            packageChangeRepository.setInstallSessions(
+            fakePackageChangeRepository.setInstallSessions(
                 listOf(
                     PackageInstallSession(
                         sessionId = 1,
@@ -690,7 +777,7 @@
                         appWidgetId = 1,
                         providerInfo = providerInfoA,
                         rank = 1,
-                        spanY = 3,
+                        spanY = if (communalResponsiveGrid()) 1 else 3,
                     ),
                     CommunalWidgetContentModel.Pending(
                         appWidgetId = 2,
@@ -698,23 +785,31 @@
                         componentName = ComponentName("pk_2", "cls_2"),
                         icon = fakeIcon,
                         user = mainUser,
-                        spanY = 3,
+                        spanY = if (communalResponsiveGrid()) 1 else 3,
                     ),
                 )
         }
 
     @Test
     fun pendingWidgets_pendingWidgetBecomesAvailableAfterInstall() =
-        testScope.runTest {
+        kosmos.runTest {
             fakeWidgets.value =
                 mapOf(
                     CommunalItemRank(uid = 1L, rank = 1) to
-                        CommunalWidgetItem(uid = 1L, 1, "pk_1/cls_1", 1L, 0, 3)
+                        CommunalWidgetItem(
+                            uid = 1L,
+                            widgetId = 1,
+                            componentName = "pk_1/cls_1",
+                            itemId = 1L,
+                            userSerialNumber = 0,
+                            spanY = 3,
+                            spanYNew = 1,
+                        )
                 )
 
             // Widget 1 is pending install
             val fakeIcon = mock<Bitmap>()
-            packageChangeRepository.setInstallSessions(
+            fakePackageChangeRepository.setInstallSessions(
                 listOf(
                     PackageInstallSession(
                         sessionId = 1,
@@ -734,12 +829,12 @@
                         componentName = ComponentName("pk_1", "cls_1"),
                         icon = fakeIcon,
                         user = mainUser,
-                        spanY = 3,
+                        spanY = if (communalResponsiveGrid()) 1 else 3,
                     )
                 )
 
             // Package for widget 1 finished installing
-            packageChangeRepository.setInstallSessions(emptyList())
+            fakePackageChangeRepository.setInstallSessions(emptyList())
 
             // Provider info for widget 1 becomes available
             fakeProviders.value = mapOf(1 to providerInfoA)
@@ -752,15 +847,16 @@
                         appWidgetId = 1,
                         providerInfo = providerInfoA,
                         rank = 1,
-                        spanY = 3,
+                        spanY = if (communalResponsiveGrid()) 1 else 3,
                     )
                 )
         }
 
     @Test
     @EnableFlags(FLAG_COMMUNAL_WIDGET_RESIZING)
-    fun updateWidgetSpanY_updatesWidgetInDaoAndRequestsBackup() =
-        testScope.runTest {
+    @DisableFlags(FLAG_COMMUNAL_RESPONSIVE_GRID)
+    fun updateWidgetSpanY_updatesWidgetInDaoAndRequestsBackup_fixed() =
+        kosmos.runTest {
             val widgetId = 1
             val newSpanY = 6
             val widgetIdToRankMap = emptyMap<Int, Int>()
@@ -768,7 +864,24 @@
             underTest.resizeWidget(widgetId, newSpanY, widgetIdToRankMap)
             runCurrent()
 
-            verify(communalWidgetDao).resizeWidget(widgetId, newSpanY, widgetIdToRankMap)
+            verify(communalWidgetDao)
+                .resizeWidget(widgetId, SpanValue.Fixed(newSpanY), widgetIdToRankMap)
+            verify(backupManager).dataChanged()
+        }
+
+    @Test
+    @EnableFlags(FLAG_COMMUNAL_WIDGET_RESIZING, FLAG_COMMUNAL_RESPONSIVE_GRID)
+    fun updateWidgetSpanY_updatesWidgetInDaoAndRequestsBackup_responsive() =
+        kosmos.runTest {
+            val widgetId = 1
+            val newSpanY = 6
+            val widgetIdToRankMap = emptyMap<Int, Int>()
+
+            underTest.resizeWidget(widgetId, newSpanY, widgetIdToRankMap)
+            runCurrent()
+
+            verify(communalWidgetDao)
+                .resizeWidget(widgetId, SpanValue.Responsive(newSpanY), widgetIdToRankMap)
             verify(backupManager).dataChanged()
         }
 
@@ -784,13 +897,19 @@
     }
 
     private fun restoreUser(user: UserHandle) {
-        whenever(backupManager.getUserForAncestralSerialNumber(user.identifier.toLong()))
+        whenever(kosmos.backupManager.getUserForAncestralSerialNumber(user.identifier.toLong()))
             .thenReturn(user)
-        whenever(userManager.getUserSerialNumber(user.identifier))
+        whenever(kosmos.userManager.getUserSerialNumber(user.identifier))
             .thenReturn(testUserSerialNumber(user))
     }
 
-    private companion object {
+    companion object {
+        @JvmStatic
+        @Parameters(name = "{0}")
+        fun getParams(): List<FlagsParameterization> {
+            return FlagsParameterization.allCombinationsOf(FLAG_COMMUNAL_RESPONSIVE_GRID)
+        }
+
         val PROVIDER_INFO_REQUIRES_CONFIGURATION =
             AppWidgetProviderInfo().apply { configure = ComponentName("test.pkg", "test.cmp") }
         val PROVIDER_INFO_CONFIGURATION_OPTIONAL =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
index 611a61a6..b9e646f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
@@ -24,14 +24,16 @@
 import android.os.UserHandle
 import android.os.UserManager
 import android.os.userManager
+import android.platform.test.annotations.DisableFlags
 import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.FlagsParameterization
 import android.provider.Settings
 import android.provider.Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED
 import android.widget.RemoteViews
-import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
+import com.android.systemui.Flags.FLAG_COMMUNAL_RESPONSIVE_GRID
 import com.android.systemui.Flags.FLAG_COMMUNAL_WIDGET_RESIZING
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.broadcast.broadcastDispatcher
@@ -96,6 +98,8 @@
 import org.mockito.Mockito.mock
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
 
 /**
  * This class of test cases assume that communal is enabled. For disabled cases, see
@@ -103,8 +107,8 @@
  */
 @SmallTest
 @OptIn(ExperimentalCoroutinesApi::class)
-@RunWith(AndroidJUnit4::class)
-class CommunalInteractorTest : SysuiTestCase() {
+@RunWith(ParameterizedAndroidJunit4::class)
+class CommunalInteractorTest(flags: FlagsParameterization) : SysuiTestCase() {
     @Mock private lateinit var mainUser: UserInfo
     @Mock private lateinit var secondaryUser: UserInfo
 
@@ -129,6 +133,10 @@
 
     private lateinit var underTest: CommunalInteractor
 
+    init {
+        mSetFlagsRule.setFlagsParameterization(flags)
+    }
+
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
@@ -262,71 +270,84 @@
             assertThat(widgetContent!![2].appWidgetId).isEqualTo(3)
         }
 
+    /** TODO(b/378171351): Handle ongoing content in responsive grid. */
     @Test
+    @DisableFlags(FLAG_COMMUNAL_RESPONSIVE_GRID)
     fun smartspaceDynamicSizing_oneCard_fullSize() =
         testSmartspaceDynamicSizing(
             totalTargets = 1,
-            expectedSizes = listOf(CommunalContentSize.FULL),
+            expectedSizes = listOf(CommunalContentSize.FixedSize.FULL),
         )
 
+    /** TODO(b/378171351): Handle ongoing content in responsive grid. */
     @Test
+    @DisableFlags(FLAG_COMMUNAL_RESPONSIVE_GRID)
     fun smartspace_dynamicSizing_twoCards_halfSize() =
         testSmartspaceDynamicSizing(
             totalTargets = 2,
-            expectedSizes = listOf(CommunalContentSize.HALF, CommunalContentSize.HALF),
+            expectedSizes =
+                listOf(CommunalContentSize.FixedSize.HALF, CommunalContentSize.FixedSize.HALF),
         )
 
+    /** TODO(b/378171351): Handle ongoing content in responsive grid. */
     @Test
+    @DisableFlags(FLAG_COMMUNAL_RESPONSIVE_GRID)
     fun smartspace_dynamicSizing_threeCards_thirdSize() =
         testSmartspaceDynamicSizing(
             totalTargets = 3,
             expectedSizes =
                 listOf(
-                    CommunalContentSize.THIRD,
-                    CommunalContentSize.THIRD,
-                    CommunalContentSize.THIRD,
+                    CommunalContentSize.FixedSize.THIRD,
+                    CommunalContentSize.FixedSize.THIRD,
+                    CommunalContentSize.FixedSize.THIRD,
                 ),
         )
 
+    /** TODO(b/378171351): Handle ongoing content in responsive grid. */
     @Test
+    @DisableFlags(FLAG_COMMUNAL_RESPONSIVE_GRID)
     fun smartspace_dynamicSizing_fourCards_threeThirdSizeAndOneFullSize() =
         testSmartspaceDynamicSizing(
             totalTargets = 4,
             expectedSizes =
                 listOf(
-                    CommunalContentSize.THIRD,
-                    CommunalContentSize.THIRD,
-                    CommunalContentSize.THIRD,
-                    CommunalContentSize.FULL,
+                    CommunalContentSize.FixedSize.THIRD,
+                    CommunalContentSize.FixedSize.THIRD,
+                    CommunalContentSize.FixedSize.THIRD,
+                    CommunalContentSize.FixedSize.FULL,
                 ),
         )
 
+    /** TODO(b/378171351): Handle ongoing content in responsive grid. */
     @Test
+    @DisableFlags(FLAG_COMMUNAL_RESPONSIVE_GRID)
     fun smartspace_dynamicSizing_fiveCards_threeThirdAndTwoHalfSize() =
         testSmartspaceDynamicSizing(
             totalTargets = 5,
             expectedSizes =
                 listOf(
-                    CommunalContentSize.THIRD,
-                    CommunalContentSize.THIRD,
-                    CommunalContentSize.THIRD,
-                    CommunalContentSize.HALF,
-                    CommunalContentSize.HALF,
+                    CommunalContentSize.FixedSize.THIRD,
+                    CommunalContentSize.FixedSize.THIRD,
+                    CommunalContentSize.FixedSize.THIRD,
+                    CommunalContentSize.FixedSize.HALF,
+                    CommunalContentSize.FixedSize.HALF,
                 ),
         )
 
+    /** TODO(b/378171351): Handle ongoing content in responsive grid. */
     @Test
+    @DisableFlags(FLAG_COMMUNAL_RESPONSIVE_GRID)
     fun smartspace_dynamicSizing_sixCards_allThirdSize() =
         testSmartspaceDynamicSizing(
             totalTargets = 6,
             expectedSizes =
                 listOf(
-                    CommunalContentSize.THIRD,
-                    CommunalContentSize.THIRD,
-                    CommunalContentSize.THIRD,
-                    CommunalContentSize.THIRD,
-                    CommunalContentSize.THIRD,
-                    CommunalContentSize.THIRD,
+                    CommunalContentSize.FixedSize.THIRD,
+                    CommunalContentSize.FixedSize.THIRD,
+                    CommunalContentSize.FixedSize.THIRD,
+                    CommunalContentSize.FixedSize.THIRD,
+                    CommunalContentSize.FixedSize.THIRD,
+                    CommunalContentSize.FixedSize.THIRD,
                 ),
         )
 
@@ -383,7 +404,9 @@
             assertThat(umoContent?.size).isEqualTo(0)
         }
 
+    /** TODO(b/378171351): Handle ongoing content in responsive grid. */
     @Test
+    @DisableFlags(FLAG_COMMUNAL_RESPONSIVE_GRID)
     fun ongoing_shouldOrderAndSizeByTimestamp() =
         testScope.runTest {
             // Keyguard showing, and tutorial completed.
@@ -410,15 +433,15 @@
             assertThat(ongoingContent?.size).isEqualTo(4)
             assertThat(ongoingContent?.get(0)?.key)
                 .isEqualTo(CommunalContentModel.KEY.smartspace("timer3"))
-            assertThat(ongoingContent?.get(0)?.size).isEqualTo(CommunalContentSize.HALF)
+            assertThat(ongoingContent?.get(0)?.size).isEqualTo(CommunalContentSize.FixedSize.HALF)
             assertThat(ongoingContent?.get(1)?.key)
                 .isEqualTo(CommunalContentModel.KEY.smartspace("timer2"))
-            assertThat(ongoingContent?.get(1)?.size).isEqualTo(CommunalContentSize.HALF)
+            assertThat(ongoingContent?.get(1)?.size).isEqualTo(CommunalContentSize.FixedSize.HALF)
             assertThat(ongoingContent?.get(2)?.key).isEqualTo(CommunalContentModel.KEY.umo())
-            assertThat(ongoingContent?.get(2)?.size).isEqualTo(CommunalContentSize.HALF)
+            assertThat(ongoingContent?.get(2)?.size).isEqualTo(CommunalContentSize.FixedSize.HALF)
             assertThat(ongoingContent?.get(3)?.key)
                 .isEqualTo(CommunalContentModel.KEY.smartspace("timer1"))
-            assertThat(ongoingContent?.get(3)?.size).isEqualTo(CommunalContentSize.HALF)
+            assertThat(ongoingContent?.get(3)?.size).isEqualTo(CommunalContentSize.FixedSize.HALF)
         }
 
     @Test
@@ -1082,6 +1105,7 @@
 
     @Test
     @EnableFlags(FLAG_COMMUNAL_WIDGET_RESIZING)
+    @DisableFlags(FLAG_COMMUNAL_RESPONSIVE_GRID)
     fun resizeWidget_withoutUpdatingOrder() =
         testScope.runTest {
             val userInfos = listOf(MAIN_USER_INFO)
@@ -1094,45 +1118,97 @@
                 appWidgetId = 1,
                 userId = MAIN_USER_INFO.id,
                 rank = 0,
-                spanY = CommunalContentSize.HALF.span,
+                spanY = CommunalContentSize.FixedSize.HALF.span,
             )
             widgetRepository.addWidget(
                 appWidgetId = 2,
                 userId = MAIN_USER_INFO.id,
                 rank = 1,
-                spanY = CommunalContentSize.HALF.span,
+                spanY = CommunalContentSize.FixedSize.HALF.span,
             )
             widgetRepository.addWidget(
                 appWidgetId = 3,
                 userId = MAIN_USER_INFO.id,
                 rank = 2,
-                spanY = CommunalContentSize.HALF.span,
+                spanY = CommunalContentSize.FixedSize.HALF.span,
             )
 
             val widgetContent by collectLastValue(underTest.widgetContent)
 
             assertThat(widgetContent?.map { it.appWidgetId to it.size })
                 .containsExactly(
-                    1 to CommunalContentSize.HALF,
-                    2 to CommunalContentSize.HALF,
-                    3 to CommunalContentSize.HALF,
+                    1 to CommunalContentSize.FixedSize.HALF,
+                    2 to CommunalContentSize.FixedSize.HALF,
+                    3 to CommunalContentSize.FixedSize.HALF,
                 )
                 .inOrder()
 
-            underTest.resizeWidget(2, CommunalContentSize.FULL.span, emptyMap())
+            underTest.resizeWidget(2, CommunalContentSize.FixedSize.FULL.span, emptyMap())
 
             // Widget 2 should have been resized to FULL
             assertThat(widgetContent?.map { it.appWidgetId to it.size })
                 .containsExactly(
-                    1 to CommunalContentSize.HALF,
-                    2 to CommunalContentSize.FULL,
-                    3 to CommunalContentSize.HALF,
+                    1 to CommunalContentSize.FixedSize.HALF,
+                    2 to CommunalContentSize.FixedSize.FULL,
+                    3 to CommunalContentSize.FixedSize.HALF,
+                )
+                .inOrder()
+        }
+
+    @Test
+    @EnableFlags(FLAG_COMMUNAL_WIDGET_RESIZING, FLAG_COMMUNAL_RESPONSIVE_GRID)
+    fun resizeWidget_withoutUpdatingOrder_responsive() =
+        testScope.runTest {
+            val userInfos = listOf(MAIN_USER_INFO)
+            userRepository.setUserInfos(userInfos)
+            userTracker.set(userInfos = userInfos, selectedUserIndex = 0)
+            runCurrent()
+
+            // Widgets available.
+            widgetRepository.addWidget(
+                appWidgetId = 1,
+                userId = MAIN_USER_INFO.id,
+                rank = 0,
+                spanY = 1,
+            )
+            widgetRepository.addWidget(
+                appWidgetId = 2,
+                userId = MAIN_USER_INFO.id,
+                rank = 1,
+                spanY = 1,
+            )
+            widgetRepository.addWidget(
+                appWidgetId = 3,
+                userId = MAIN_USER_INFO.id,
+                rank = 2,
+                spanY = 1,
+            )
+
+            val widgetContent by collectLastValue(underTest.widgetContent)
+
+            assertThat(widgetContent?.map { it.appWidgetId to it.size })
+                .containsExactly(
+                    1 to CommunalContentSize.Responsive(1),
+                    2 to CommunalContentSize.Responsive(1),
+                    3 to CommunalContentSize.Responsive(1),
+                )
+                .inOrder()
+
+            underTest.resizeWidget(appWidgetId = 2, spanY = 5, widgetIdToRankMap = emptyMap())
+
+            // Widget 2 should have been resized to FULL
+            assertThat(widgetContent?.map { it.appWidgetId to it.size })
+                .containsExactly(
+                    1 to CommunalContentSize.Responsive(1),
+                    2 to CommunalContentSize.Responsive(5),
+                    3 to CommunalContentSize.Responsive(1),
                 )
                 .inOrder()
         }
 
     @Test
     @EnableFlags(FLAG_COMMUNAL_WIDGET_RESIZING)
+    @DisableFlags(FLAG_COMMUNAL_RESPONSIVE_GRID)
     fun resizeWidget_andUpdateOrder() =
         testScope.runTest {
             val userInfos = listOf(MAIN_USER_INFO)
@@ -1145,39 +1221,98 @@
                 appWidgetId = 1,
                 userId = MAIN_USER_INFO.id,
                 rank = 0,
-                spanY = CommunalContentSize.HALF.span,
+                spanY = CommunalContentSize.FixedSize.HALF.span,
             )
             widgetRepository.addWidget(
                 appWidgetId = 2,
                 userId = MAIN_USER_INFO.id,
                 rank = 1,
-                spanY = CommunalContentSize.HALF.span,
+                spanY = CommunalContentSize.FixedSize.HALF.span,
             )
             widgetRepository.addWidget(
                 appWidgetId = 3,
                 userId = MAIN_USER_INFO.id,
                 rank = 2,
-                spanY = CommunalContentSize.HALF.span,
+                spanY = CommunalContentSize.FixedSize.HALF.span,
             )
 
             val widgetContent by collectLastValue(underTest.widgetContent)
 
             assertThat(widgetContent?.map { it.appWidgetId to it.size })
                 .containsExactly(
-                    1 to CommunalContentSize.HALF,
-                    2 to CommunalContentSize.HALF,
-                    3 to CommunalContentSize.HALF,
+                    1 to CommunalContentSize.FixedSize.HALF,
+                    2 to CommunalContentSize.FixedSize.HALF,
+                    3 to CommunalContentSize.FixedSize.HALF,
                 )
                 .inOrder()
 
-            underTest.resizeWidget(2, CommunalContentSize.FULL.span, mapOf(2 to 0, 1 to 1))
+            underTest.resizeWidget(
+                2,
+                CommunalContentSize.FixedSize.FULL.span,
+                mapOf(2 to 0, 1 to 1),
+            )
 
             // Widget 2 should have been resized to FULL and moved to the front of the list
             assertThat(widgetContent?.map { it.appWidgetId to it.size })
                 .containsExactly(
-                    2 to CommunalContentSize.FULL,
-                    1 to CommunalContentSize.HALF,
-                    3 to CommunalContentSize.HALF,
+                    2 to CommunalContentSize.FixedSize.FULL,
+                    1 to CommunalContentSize.FixedSize.HALF,
+                    3 to CommunalContentSize.FixedSize.HALF,
+                )
+                .inOrder()
+        }
+
+    @Test
+    @EnableFlags(FLAG_COMMUNAL_WIDGET_RESIZING, FLAG_COMMUNAL_RESPONSIVE_GRID)
+    fun resizeWidget_andUpdateOrder_responsive() =
+        testScope.runTest {
+            val userInfos = listOf(MAIN_USER_INFO)
+            userRepository.setUserInfos(userInfos)
+            userTracker.set(userInfos = userInfos, selectedUserIndex = 0)
+            runCurrent()
+
+            // Widgets available.
+            widgetRepository.addWidget(
+                appWidgetId = 1,
+                userId = MAIN_USER_INFO.id,
+                rank = 0,
+                spanY = 1,
+            )
+            widgetRepository.addWidget(
+                appWidgetId = 2,
+                userId = MAIN_USER_INFO.id,
+                rank = 1,
+                spanY = 1,
+            )
+            widgetRepository.addWidget(
+                appWidgetId = 3,
+                userId = MAIN_USER_INFO.id,
+                rank = 2,
+                spanY = 1,
+            )
+
+            val widgetContent by collectLastValue(underTest.widgetContent)
+
+            assertThat(widgetContent?.map { it.appWidgetId to it.size })
+                .containsExactly(
+                    1 to CommunalContentSize.Responsive(1),
+                    2 to CommunalContentSize.Responsive(1),
+                    3 to CommunalContentSize.Responsive(1),
+                )
+                .inOrder()
+
+            underTest.resizeWidget(
+                appWidgetId = 2,
+                spanY = 5,
+                widgetIdToRankMap = mapOf(2 to 0, 1 to 1),
+            )
+
+            // Widget 2 should have been resized to FULL and moved to the front of the list
+            assertThat(widgetContent?.map { it.appWidgetId to it.size })
+                .containsExactly(
+                    2 to CommunalContentSize.Responsive(5),
+                    1 to CommunalContentSize.Responsive(1),
+                    3 to CommunalContentSize.Responsive(1),
                 )
                 .inOrder()
         }
@@ -1191,9 +1326,15 @@
         )
     }
 
-    private companion object {
-        val MAIN_USER_INFO = UserInfo(0, "primary", UserInfo.FLAG_MAIN)
-        val USER_INFO_WORK =
+    companion object {
+        @JvmStatic
+        @Parameters(name = "{0}")
+        fun getParams(): List<FlagsParameterization> {
+            return FlagsParameterization.allCombinationsOf(FLAG_COMMUNAL_RESPONSIVE_GRID)
+        }
+
+        private val MAIN_USER_INFO = UserInfo(0, "primary", UserInfo.FLAG_MAIN)
+        private val USER_INFO_WORK =
             UserInfo(
                 10,
                 "work",
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalUserActionsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalUserActionsViewModelTest.kt
index 755c4eb..ca7e203 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalUserActionsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalUserActionsViewModelTest.kt
@@ -85,8 +85,7 @@
             assertThat(actions).isNotEmpty()
             assertThat(actions?.get(Swipe.End)).isEqualTo(UserActionResult(SceneFamilies.Home))
             assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Bouncer))
-            assertThat(actions?.get(Swipe.Down))
-                .isEqualTo(UserActionResult(Scenes.Shade, isIrreversible = true))
+            assertThat(actions?.get(Swipe.Down)).isEqualTo(UserActionResult(Scenes.Shade))
 
             setUpState(
                 isShadeTouchable = false,
@@ -103,8 +102,7 @@
             assertThat(actions).isNotEmpty()
             assertThat(actions?.get(Swipe.End)).isEqualTo(UserActionResult(SceneFamilies.Home))
             assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Gone))
-            assertThat(actions?.get(Swipe.Down))
-                .isEqualTo(UserActionResult(Scenes.Shade, isIrreversible = true))
+            assertThat(actions?.get(Swipe.Down)).isEqualTo(UserActionResult(Scenes.Shade))
         }
 
     @Test
@@ -122,7 +120,7 @@
             assertThat(actions?.get(Swipe.End)).isEqualTo(UserActionResult(SceneFamilies.Home))
             assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Bouncer))
             assertThat(actions?.get(Swipe.Down))
-                .isEqualTo(UserActionResult(Scenes.Shade, ToSplitShade, isIrreversible = true))
+                .isEqualTo(UserActionResult(Scenes.Shade, ToSplitShade))
 
             setUpState(
                 isShadeTouchable = false,
@@ -140,7 +138,7 @@
             assertThat(actions?.get(Swipe.End)).isEqualTo(UserActionResult(SceneFamilies.Home))
             assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Gone))
             assertThat(actions?.get(Swipe.Down))
-                .isEqualTo(UserActionResult(Scenes.Shade, ToSplitShade, isIrreversible = true))
+                .isEqualTo(UserActionResult(Scenes.Shade, ToSplitShade))
         }
 
     @Test
@@ -158,9 +156,7 @@
             assertThat(actions?.get(Swipe.End)).isEqualTo(UserActionResult(SceneFamilies.Home))
             assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Bouncer))
             assertThat(actions?.get(Swipe.Down))
-                .isEqualTo(
-                    UserActionResult.ShowOverlay(Overlays.NotificationsShade, isIrreversible = true)
-                )
+                .isEqualTo(UserActionResult.ShowOverlay(Overlays.NotificationsShade))
 
             setUpState(
                 isShadeTouchable = false,
@@ -174,9 +170,7 @@
             assertThat(actions?.get(Swipe.End)).isEqualTo(UserActionResult(SceneFamilies.Home))
             assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Gone))
             assertThat(actions?.get(Swipe.Down))
-                .isEqualTo(
-                    UserActionResult.ShowOverlay(Overlays.NotificationsShade, isIrreversible = true)
-                )
+                .isEqualTo(UserActionResult.ShowOverlay(Overlays.NotificationsShade))
         }
 
     private fun TestScope.setUpState(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
index 3eba8ff..763ea39 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
@@ -18,12 +18,14 @@
 
 import android.content.ComponentName
 import android.content.pm.UserInfo
+import android.platform.test.annotations.DisableFlags
 import android.platform.test.flag.junit.FlagsParameterization
 import android.provider.Settings
 import android.widget.RemoteViews
 import androidx.test.filters.SmallTest
 import com.android.compose.animation.scene.ObservableTransitionState
 import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
+import com.android.systemui.Flags.FLAG_COMMUNAL_RESPONSIVE_GRID
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.communal.data.model.CommunalSmartspaceTimer
 import com.android.systemui.communal.data.repository.FakeCommunalMediaRepository
@@ -248,7 +250,9 @@
                 .isInstanceOf(CommunalContentModel.CtaTileInViewMode::class.java)
         }
 
+    /** TODO(b/378171351): Handle ongoing content in responsive grid. */
     @Test
+    @DisableFlags(FLAG_COMMUNAL_RESPONSIVE_GRID)
     fun ongoingContent_umoAndOneTimer_sizedAppropriately() =
         testScope.runTest {
             // Widgets available.
@@ -280,11 +284,13 @@
             assertThat(timer).isInstanceOf(CommunalContentModel.Smartspace::class.java)
             assertThat(umo).isInstanceOf(CommunalContentModel.Umo::class.java)
 
-            assertThat(timer?.size).isEqualTo(CommunalContentSize.HALF)
-            assertThat(umo?.size).isEqualTo(CommunalContentSize.HALF)
+            assertThat(timer?.size).isEqualTo(CommunalContentSize.FixedSize.HALF)
+            assertThat(umo?.size).isEqualTo(CommunalContentSize.FixedSize.HALF)
         }
 
+    /** TODO(b/378171351): Handle ongoing content in responsive grid. */
     @Test
+    @DisableFlags(FLAG_COMMUNAL_RESPONSIVE_GRID)
     fun ongoingContent_umoAndTwoTimers_sizedAppropriately() =
         testScope.runTest {
             // Widgets available.
@@ -324,9 +330,9 @@
             assertThat(umo).isInstanceOf(CommunalContentModel.Umo::class.java)
 
             // One full-sized timer and a half-sized timer and half-sized UMO.
-            assertThat(timer1?.size).isEqualTo(CommunalContentSize.HALF)
-            assertThat(timer2?.size).isEqualTo(CommunalContentSize.HALF)
-            assertThat(umo?.size).isEqualTo(CommunalContentSize.FULL)
+            assertThat(timer1?.size).isEqualTo(CommunalContentSize.FixedSize.HALF)
+            assertThat(timer2?.size).isEqualTo(CommunalContentSize.FixedSize.HALF)
+            assertThat(umo?.size).isEqualTo(CommunalContentSize.FixedSize.FULL)
         }
 
     @Test
@@ -891,7 +897,8 @@
         @JvmStatic
         @Parameters(name = "{0}")
         fun getParams(): List<FlagsParameterization> {
-            return FlagsParameterization.allCombinationsOf().andSceneContainer()
+            return FlagsParameterization.allCombinationsOf(FLAG_COMMUNAL_RESPONSIVE_GRID)
+                .andSceneContainer()
         }
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelTest.kt
index 55b87db..d6daa79 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModelTest.kt
@@ -86,8 +86,7 @@
             )
             assertThat(actions).isNotEmpty()
             assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Bouncer))
-            assertThat(actions?.get(Swipe.Down))
-                .isEqualTo(UserActionResult(Scenes.Shade, isIrreversible = true))
+            assertThat(actions?.get(Swipe.Down)).isEqualTo(UserActionResult(Scenes.Shade))
             assertThat(actions?.get(Swipe.Start)).isNull()
             assertThat(actions?.get(Swipe.End)).isNull()
 
@@ -105,8 +104,7 @@
             )
             assertThat(actions).isNotEmpty()
             assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Gone))
-            assertThat(actions?.get(Swipe.Down))
-                .isEqualTo(UserActionResult(Scenes.Shade, isIrreversible = true))
+            assertThat(actions?.get(Swipe.Down)).isEqualTo(UserActionResult(Scenes.Shade))
             assertThat(actions?.get(Swipe.Start)).isNull()
             assertThat(actions?.get(Swipe.End)).isNull()
         }
@@ -127,7 +125,7 @@
             assertThat(actions).isNotEmpty()
             assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Bouncer))
             assertThat(actions?.get(Swipe.Down))
-                .isEqualTo(UserActionResult(Scenes.Shade, ToSplitShade, isIrreversible = true))
+                .isEqualTo(UserActionResult(Scenes.Shade, ToSplitShade))
             assertThat(actions?.get(Swipe.Start)).isNull()
             assertThat(actions?.get(Swipe.End)).isNull()
 
@@ -146,7 +144,7 @@
             assertThat(actions).isNotEmpty()
             assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Gone))
             assertThat(actions?.get(Swipe.Down))
-                .isEqualTo(UserActionResult(Scenes.Shade, ToSplitShade, isIrreversible = true))
+                .isEqualTo(UserActionResult(Scenes.Shade, ToSplitShade))
             assertThat(actions?.get(Swipe.Start)).isNull()
             assertThat(actions?.get(Swipe.End)).isNull()
         }
@@ -167,9 +165,7 @@
             assertThat(actions).isNotEmpty()
             assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Bouncer))
             assertThat(actions?.get(Swipe.Down))
-                .isEqualTo(
-                    UserActionResult.ShowOverlay(Overlays.NotificationsShade, isIrreversible = true)
-                )
+                .isEqualTo(UserActionResult.ShowOverlay(Overlays.NotificationsShade))
             assertThat(actions?.get(Swipe.Start)).isNull()
             assertThat(actions?.get(Swipe.End)).isNull()
 
@@ -184,9 +180,7 @@
             assertThat(actions).isNotEmpty()
             assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Gone))
             assertThat(actions?.get(Swipe.Down))
-                .isEqualTo(
-                    UserActionResult.ShowOverlay(Overlays.NotificationsShade, isIrreversible = true)
-                )
+                .isEqualTo(UserActionResult.ShowOverlay(Overlays.NotificationsShade))
             assertThat(actions?.get(Swipe.Start)).isNull()
             assertThat(actions?.get(Swipe.End)).isNull()
         }
@@ -206,8 +200,7 @@
             )
             assertThat(actions).isNotEmpty()
             assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Bouncer))
-            assertThat(actions?.get(Swipe.Down))
-                .isEqualTo(UserActionResult(Scenes.Shade, isIrreversible = true))
+            assertThat(actions?.get(Swipe.Down)).isEqualTo(UserActionResult(Scenes.Shade))
             assertThat(actions?.get(Swipe.Start)).isEqualTo(UserActionResult(Scenes.Communal))
             assertThat(actions?.get(Swipe.End)).isNull()
 
@@ -225,8 +218,7 @@
             )
             assertThat(actions).isNotEmpty()
             assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Gone))
-            assertThat(actions?.get(Swipe.Down))
-                .isEqualTo(UserActionResult(Scenes.Shade, isIrreversible = true))
+            assertThat(actions?.get(Swipe.Down)).isEqualTo(UserActionResult(Scenes.Shade))
             assertThat(actions?.get(Swipe.Start)).isEqualTo(UserActionResult(Scenes.Communal))
             assertThat(actions?.get(Swipe.End)).isNull()
         }
@@ -247,7 +239,7 @@
             assertThat(actions).isNotEmpty()
             assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Bouncer))
             assertThat(actions?.get(Swipe.Down))
-                .isEqualTo(UserActionResult(Scenes.Shade, ToSplitShade, isIrreversible = true))
+                .isEqualTo(UserActionResult(Scenes.Shade, ToSplitShade))
             assertThat(actions?.get(Swipe.Start)).isEqualTo(UserActionResult(Scenes.Communal))
             assertThat(actions?.get(Swipe.End)).isNull()
 
@@ -266,7 +258,7 @@
             assertThat(actions).isNotEmpty()
             assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Gone))
             assertThat(actions?.get(Swipe.Down))
-                .isEqualTo(UserActionResult(Scenes.Shade, ToSplitShade, isIrreversible = true))
+                .isEqualTo(UserActionResult(Scenes.Shade, ToSplitShade))
             assertThat(actions?.get(Swipe.Start)).isEqualTo(UserActionResult(Scenes.Communal))
             assertThat(actions?.get(Swipe.End)).isNull()
         }
@@ -287,9 +279,7 @@
             assertThat(actions).isNotEmpty()
             assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Bouncer))
             assertThat(actions?.get(Swipe.Down))
-                .isEqualTo(
-                    UserActionResult.ShowOverlay(Overlays.NotificationsShade, isIrreversible = true)
-                )
+                .isEqualTo(UserActionResult.ShowOverlay(Overlays.NotificationsShade))
             assertThat(actions?.get(Swipe.Start)).isEqualTo(UserActionResult(Scenes.Communal))
             assertThat(actions?.get(Swipe.End)).isNull()
 
@@ -304,9 +294,7 @@
             assertThat(actions).isNotEmpty()
             assertThat(actions?.get(Swipe.Up)).isEqualTo(UserActionResult(Scenes.Gone))
             assertThat(actions?.get(Swipe.Down))
-                .isEqualTo(
-                    UserActionResult.ShowOverlay(Overlays.NotificationsShade, isIrreversible = true)
-                )
+                .isEqualTo(UserActionResult.ShowOverlay(Overlays.NotificationsShade))
             assertThat(actions?.get(Swipe.Start)).isEqualTo(UserActionResult(Scenes.Communal))
             assertThat(actions?.get(Swipe.End)).isNull()
         }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/ui/view/ContextualEduUiCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/ui/view/ContextualEduUiCoordinatorTest.kt
index e288522..248b922 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/ui/view/ContextualEduUiCoordinatorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/education/domain/ui/view/ContextualEduUiCoordinatorTest.kt
@@ -20,18 +20,20 @@
 import android.app.Notification
 import android.app.NotificationManager
 import android.content.applicationContext
-import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.contextualeducation.GestureType
+import com.android.systemui.contextualeducation.GestureType.ALL_APPS
 import com.android.systemui.contextualeducation.GestureType.BACK
 import com.android.systemui.contextualeducation.GestureType.HOME
+import com.android.systemui.contextualeducation.GestureType.OVERVIEW
 import com.android.systemui.education.data.repository.fakeEduClock
 import com.android.systemui.education.domain.interactor.KeyboardTouchpadEduInteractor
 import com.android.systemui.education.domain.interactor.contextualEducationInteractor
 import com.android.systemui.education.domain.interactor.keyboardTouchpadEduInteractor
 import com.android.systemui.education.ui.view.ContextualEduUiCoordinator
 import com.android.systemui.education.ui.viewmodel.ContextualEduViewModel
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity
 import com.android.systemui.kosmos.applicationCoroutineScope
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.res.R
@@ -56,11 +58,13 @@
 import org.mockito.kotlin.mock
 import org.mockito.kotlin.verify
 import org.mockito.kotlin.whenever
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
 
 @SmallTest
-@RunWith(AndroidJUnit4::class)
+@RunWith(ParameterizedAndroidJunit4::class)
 @OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
-class ContextualEduUiCoordinatorTest : SysuiTestCase() {
+class ContextualEduUiCoordinatorTest(private val gestureType: GestureType) : SysuiTestCase() {
     private val kosmos = testKosmos()
     private val testScope = kosmos.testScope
     private val interactor = kosmos.contextualEducationInteractor
@@ -112,23 +116,23 @@
     @Test
     fun showDialogOnNewEdu() =
         testScope.runTest {
-            triggerEducation(BACK)
+            triggerEducation(gestureType)
             verify(dialog).show()
         }
 
     @Test
     fun showNotificationOn2ndEdu() =
         testScope.runTest {
-            triggerEducation(BACK)
+            triggerEducation(gestureType)
             eduClock.offset(minDurationForNextEdu)
-            triggerEducation(BACK)
+            triggerEducation(gestureType)
             verify(notificationManager).notifyAsUser(any(), anyInt(), any(), any())
         }
 
     @Test
     fun dismissDialogAfterTimeout() =
         testScope.runTest {
-            triggerEducation(BACK)
+            triggerEducation(gestureType)
             advanceTimeBy(timeoutMillis + 1)
             verify(dialog).dismiss()
         }
@@ -142,26 +146,59 @@
         }
 
     @Test
-    fun verifyBackEduToastContent() =
+    fun verifyEduToastContent() =
         testScope.runTest {
-            triggerEducation(BACK)
-            assertThat(toastContent).isEqualTo(context.getString(R.string.back_edu_toast_content))
+            triggerEducation(gestureType)
+
+            val expectedContent =
+                when (gestureType) {
+                    BACK -> R.string.back_edu_toast_content
+                    HOME -> R.string.home_edu_toast_content
+                    OVERVIEW -> R.string.overview_edu_toast_content
+                    ALL_APPS -> R.string.all_apps_edu_toast_content
+                }
+
+            assertThat(toastContent).isEqualTo(context.getString(expectedContent))
         }
 
     @Test
-    fun verifyBackEduNotificationContent() =
+    fun verifyEduNotificationContent() =
         testScope.runTest {
             val notificationCaptor = ArgumentCaptor.forClass(Notification::class.java)
-            triggerEducation(BACK)
+            triggerEducation(gestureType)
 
             eduClock.offset(minDurationForNextEdu)
-            triggerEducation(BACK)
+            triggerEducation(gestureType)
 
             verify(notificationManager)
                 .notifyAsUser(any(), anyInt(), notificationCaptor.capture(), any())
+
+            val expectedTitle =
+                when (gestureType) {
+                    BACK -> R.string.back_edu_notification_title
+                    HOME -> R.string.home_edu_notification_title
+                    OVERVIEW -> R.string.overview_edu_notification_title
+                    ALL_APPS -> R.string.all_apps_edu_notification_title
+                }
+
+            val expectedContent =
+                when (gestureType) {
+                    BACK -> R.string.back_edu_notification_content
+                    HOME -> R.string.home_edu_notification_content
+                    OVERVIEW -> R.string.overview_edu_notification_content
+                    ALL_APPS -> R.string.all_apps_edu_notification_content
+                }
+
+            val expectedTutorialClassName =
+                when (gestureType) {
+                    OVERVIEW -> TUTORIAL_ACTION
+                    else -> KeyboardTouchpadTutorialActivity::class.qualifiedName
+                }
+
             verifyNotificationContent(
-                R.string.back_edu_notification_title,
-                R.string.back_edu_notification_content,
+                expectedTitle,
+                expectedContent,
+                expectedTutorialClassName,
                 notificationCaptor.value,
             )
         }
@@ -169,6 +206,7 @@
     private fun verifyNotificationContent(
         titleResId: Int,
         contentResId: Int,
+        expectedTutorialClassName: String?,
         notification: Notification,
     ) {
         val expectedContent = context.getString(contentResId)
@@ -177,6 +215,10 @@
         val actualTitle = notification.getString(Notification.EXTRA_TITLE)
         assertThat(actualContent).isEqualTo(expectedContent)
         assertThat(actualTitle).isEqualTo(expectedTitle)
+        val actualTutorialClassName =
+            notification.contentIntent.intent.component?.className
+                ?: notification.contentIntent.intent.action
+        assertThat(actualTutorialClassName).isEqualTo(expectedTutorialClassName)
     }
 
     private fun Notification.getString(key: String): String =
@@ -188,4 +230,14 @@
         }
         runCurrent()
     }
+
+    companion object {
+        @JvmStatic
+        @Parameters(name = "{0}")
+        fun getGestureTypes(): List<GestureType> {
+            return listOf(BACK, HOME, OVERVIEW, ALL_APPS)
+        }
+
+        private const val TUTORIAL_ACTION: String = "com.android.systemui.action.TOUCHPAD_TUTORIAL"
+    }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
index c287da8..cc718c7 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt
@@ -74,6 +74,27 @@
             /* modifiers = */ KeyEvent.META_SHIFT_ON,
         )
 
+    private val ShortcutsWithDiffSizeOfKeys =
+        KeyboardShortcutInfo(
+            /* label = */ "Shortcuts with diff size of keys",
+            /* keycode = */ KeyEvent.KEYCODE_HOME,
+            /* modifiers = */ 0,
+        )
+
+    private val ShortcutsWithDiffSizeOfKeys2 =
+        KeyboardShortcutInfo(
+            /* label = */ ShortcutsWithDiffSizeOfKeys.label,
+            /* keycode = */ KeyEvent.KEYCODE_1,
+            /* modifiers = */ META_META_ON,
+        )
+
+    private val ShortcutsWithDiffSizeOfKeys3 =
+        KeyboardShortcutInfo(
+            /* label = */ ShortcutsWithDiffSizeOfKeys.label,
+            /* keycode = */ KeyEvent.KEYCODE_2,
+            /* modifiers = */ META_META_ON or META_FUNCTION_ON,
+        )
+
     private val shortcutWithGroupedRepeatedLabel =
         shortcut(shortcutInfoWithRepeatedLabel.label!!.toString()) {
             command {
@@ -381,6 +402,16 @@
             groupWithSupportedAndUnsupportedModifierShortcut,
         )
 
+    val groupWithDifferentSizeOfShortcutKeys =
+        KeyboardShortcutGroup(
+            "Group with different size of shortcut keys",
+            listOf(
+                ShortcutsWithDiffSizeOfKeys3,
+                ShortcutsWithDiffSizeOfKeys,
+                ShortcutsWithDiffSizeOfKeys2,
+            ),
+        )
+
     val subCategoriesWithUnsupportedModifiersRemoved =
         listOf(subCategoryWithStandardShortcut, subCategoryWithUnsupportedShortcutsRemoved)
 
@@ -662,7 +693,7 @@
     val standardAddShortcutRequest =
         ShortcutCustomizationRequestInfo.Add(
             label = "Standard shortcut",
-            categoryType = ShortcutCategoryType.System,
+            categoryType = System,
             subCategoryLabel = "Standard subcategory",
         )
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractorTest.kt
index c3cedba..8f0bc64 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractorTest.kt
@@ -369,6 +369,20 @@
         }
     }
 
+    @Test
+    fun categories_showShortcutsInAscendingOrderOfKeySize() =
+        testScope.runTest {
+            systemShortcutsSource.setGroups(TestShortcuts.groupWithDifferentSizeOfShortcutKeys)
+            val categories by collectLastValue(interactor.shortcutCategories)
+
+            helper.showFromActivity()
+
+            val systemCategoryShortcuts = categories?.get(0)?.subCategories?.get(0)?.shortcuts
+            val shortcutKeyCount =
+                systemCategoryShortcuts?.flatMap { it.commands }?.map { it.keys.size }
+            assertThat(shortcutKeyCount).containsExactly(1, 2, 3).inOrder()
+        }
+
     private fun setCustomInputGestures(customInputGestures: List<InputGestureData>) {
         whenever(fakeInputManager.inputManager.getCustomInputGestures(/* filter= */ anyOrNull()))
             .thenReturn(customInputGestures)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt
index 2d05ee0..755c218 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt
@@ -108,7 +108,7 @@
             viewModel.onShortcutCustomizationRequested(ShortcutCustomizationRequestInfo.Reset)
             val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
 
-            assertThat(uiState).isEqualTo(ResetShortcutDialog())
+            assertThat(uiState).isEqualTo(ResetShortcutDialog)
         }
     }
 
@@ -118,45 +118,7 @@
             viewModel.onShortcutCustomizationRequested(allAppsShortcutDeleteRequest)
             val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
 
-            assertThat(uiState).isEqualTo(DeleteShortcutDialog())
-        }
-    }
-
-    @Test
-    fun uiState_consumedOnAddDialogShown() {
-        testScope.runTest {
-            val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
-            viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
-            viewModel.onDialogShown()
-
-            assertThat((uiState as AddShortcutDialog).isDialogShowing)
-                .isTrue()
-        }
-    }
-
-    @Test
-    fun uiState_consumedOnDeleteDialogShown() {
-        testScope.runTest {
-            val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
-            viewModel.onShortcutCustomizationRequested(allAppsShortcutDeleteRequest)
-            viewModel.onDialogShown()
-
-            assertThat(
-                    (uiState as DeleteShortcutDialog).isDialogShowing
-                )
-                .isTrue()
-        }
-    }
-
-    @Test
-    fun uiState_consumedOnResetDialogShown() {
-        testScope.runTest {
-            val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
-            viewModel.onShortcutCustomizationRequested(ShortcutCustomizationRequestInfo.Reset)
-            viewModel.onDialogShown()
-
-            assertThat((uiState as ResetShortcutDialog).isDialogShowing)
-                .isTrue()
+            assertThat(uiState).isEqualTo(DeleteShortcutDialog)
         }
     }
 
@@ -165,7 +127,6 @@
         testScope.runTest {
             val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
             viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest)
-            viewModel.onDialogShown()
             viewModel.onDialogDismissed()
             assertThat(uiState).isEqualTo(ShortcutCustomizationUiState.Inactive)
         }
@@ -199,7 +160,6 @@
         testScope.runTest {
             val uiState by collectLastValue(viewModel.shortcutCustomizationUiState)
             viewModel.onShortcutCustomizationRequested(allAppsShortcutAddRequest)
-            viewModel.onDialogShown()
 
             assertThat((uiState as AddShortcutDialog).errorMessage)
                 .isEmpty()
@@ -339,7 +299,6 @@
 
     private suspend fun openAddShortcutDialogAndSetShortcut() {
         viewModel.onShortcutCustomizationRequested(allAppsShortcutAddRequest)
-        viewModel.onDialogShown()
 
         viewModel.onKeyPressed(keyDownEventWithActionKeyPressed)
         viewModel.onKeyPressed(keyUpEventWithActionKeyPressed)
@@ -349,14 +308,12 @@
 
     private suspend fun openDeleteShortcutDialogAndDeleteShortcut() {
         viewModel.onShortcutCustomizationRequested(allAppsShortcutDeleteRequest)
-        viewModel.onDialogShown()
 
         viewModel.deleteShortcutCurrentlyBeingCustomized()
     }
 
     private suspend fun openResetShortcutDialogAndResetAllCustomShortcuts() {
         viewModel.onShortcutCustomizationRequested(ShortcutCustomizationRequestInfo.Reset)
-        viewModel.onDialogShown()
 
         viewModel.resetAllCustomShortcuts()
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt
similarity index 83%
rename from packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt
index 3bd2496..78fce27 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModelTest.kt
@@ -18,6 +18,13 @@
 
 import android.app.role.RoleManager
 import android.app.role.mockRoleManager
+import android.content.Context
+import android.content.Context.INPUT_SERVICE
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageManager
+import android.content.pm.PackageManager.NameNotFoundException
+import android.hardware.input.InputGestureData
+import android.hardware.input.fakeInputManager
 import android.view.KeyEvent
 import android.view.KeyboardShortcutGroup
 import android.view.KeyboardShortcutInfo
@@ -31,6 +38,7 @@
 import com.android.systemui.coroutines.collectValues
 import com.android.systemui.keyboard.shortcut.data.source.FakeKeyboardShortcutGroupsSource
 import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts
+import com.android.systemui.keyboard.shortcut.data.source.TestShortcuts.allAppsInputGestureData
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.CurrentApp
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.MultiTasking
@@ -56,7 +64,6 @@
 import com.android.systemui.settings.fakeUserTracker
 import com.android.systemui.settings.userTracker
 import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SHORTCUT_HELPER_SHOWING
-import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.UnconfinedTestDispatcher
@@ -64,6 +71,10 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyString
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
@@ -73,6 +84,9 @@
     private val fakeSystemSource = FakeKeyboardShortcutGroupsSource()
     private val fakeMultiTaskingSource = FakeKeyboardShortcutGroupsSource()
     private val fakeCurrentAppsSource = FakeKeyboardShortcutGroupsSource()
+    private val mockPackageManager: PackageManager = mock()
+    private val mockUserContext: Context = mock()
+    private val mockApplicationInfo: ApplicationInfo = mock()
 
     private val kosmos =
         Kosmos().also {
@@ -83,7 +97,7 @@
             it.shortcutHelperAppCategoriesShortcutsSource = FakeKeyboardShortcutGroupsSource()
             it.shortcutHelperInputShortcutsSource = FakeKeyboardShortcutGroupsSource()
             it.shortcutHelperCurrentAppShortcutsSource = fakeCurrentAppsSource
-            it.userTracker = FakeUserTracker(onCreateCurrentUserContext = { context })
+            it.userTracker = FakeUserTracker(onCreateCurrentUserContext = { mockUserContext })
         }
 
     private val testScope = kosmos.testScope
@@ -91,13 +105,20 @@
     private val sysUiState = kosmos.sysUiState
     private val fakeUserTracker = kosmos.fakeUserTracker
     private val mockRoleManager = kosmos.mockRoleManager
+    private val inputManager = kosmos.fakeInputManager.inputManager
     private val viewModel = kosmos.shortcutHelperViewModel
 
+
     @Before
     fun setUp() {
         fakeSystemSource.setGroups(TestShortcuts.systemGroups)
         fakeMultiTaskingSource.setGroups(TestShortcuts.multitaskingGroups)
         fakeCurrentAppsSource.setGroups(TestShortcuts.currentAppGroups)
+        whenever(mockPackageManager.getApplicationInfo(anyString(), eq(0))).thenReturn(mockApplicationInfo)
+        whenever(mockPackageManager.getApplicationLabel(mockApplicationInfo)).thenReturn("Current App")
+        whenever(mockPackageManager.getApplicationIcon(anyString())).thenThrow(NameNotFoundException())
+        whenever(mockUserContext.packageManager).thenReturn(mockPackageManager)
+        whenever(mockUserContext.getSystemService(INPUT_SERVICE)).thenReturn(inputManager)
     }
 
     @Test
@@ -259,11 +280,11 @@
     fun shortcutsUiState_currentAppIsLauncher_defaultSelectedCategoryIsSystem() =
         testScope.runTest {
             whenever(
-                    mockRoleManager.getRoleHoldersAsUser(
-                        RoleManager.ROLE_HOME,
-                        fakeUserTracker.userHandle,
-                    )
+                mockRoleManager.getRoleHoldersAsUser(
+                    RoleManager.ROLE_HOME,
+                    fakeUserTracker.userHandle,
                 )
+            )
                 .thenReturn(listOf(TestShortcuts.currentAppPackageName))
             val uiState by collectLastValue(viewModel.shortcutsUiState)
 
@@ -299,23 +320,23 @@
                         label = "System",
                         iconSource = IconSource(imageVector = Icons.Default.Tv),
                         shortcutCategory =
-                            ShortcutCategory(
-                                System,
-                                subCategoryWithShortcutLabels("first Foo shortcut1"),
-                                subCategoryWithShortcutLabels(
-                                    "second foO shortcut2",
-                                    subCategoryLabel = SECOND_SIMPLE_GROUP_LABEL,
-                                ),
+                        ShortcutCategory(
+                            System,
+                            subCategoryWithShortcutLabels("first Foo shortcut1"),
+                            subCategoryWithShortcutLabels(
+                                "second foO shortcut2",
+                                subCategoryLabel = SECOND_SIMPLE_GROUP_LABEL,
                             ),
+                        ),
                     ),
                     ShortcutCategoryUi(
                         label = "Multitasking",
                         iconSource = IconSource(imageVector = Icons.Default.VerticalSplit),
                         shortcutCategory =
-                            ShortcutCategory(
-                                MultiTasking,
-                                subCategoryWithShortcutLabels("third FoO shortcut1"),
-                            ),
+                        ShortcutCategory(
+                            MultiTasking,
+                            subCategoryWithShortcutLabels("third FoO shortcut1"),
+                        ),
                     ),
                 )
         }
@@ -387,6 +408,31 @@
             assertThat(activeUiState.defaultSelectedCategory).isInstanceOf(CurrentApp::class.java)
         }
 
+    @Test
+    fun shortcutsUiState_shouldShowResetButton_isFalseWhenThereAreNoCustomShortcuts() =
+        testScope.runTest {
+            val uiState by collectLastValue(viewModel.shortcutsUiState)
+
+            testHelper.showFromActivity()
+
+            val activeUiState = uiState as ShortcutsUiState.Active
+            assertThat(activeUiState.shouldShowResetButton).isFalse()
+        }
+
+    @Test
+    fun shortcutsUiState_shouldShowResetButton_isTrueWhenThereAreCustomShortcuts() =
+        testScope.runTest {
+            whenever(
+                inputManager.getCustomInputGestures(/* filter= */ InputGestureData.Filter.KEY)
+            ).thenReturn(listOf(allAppsInputGestureData))
+            val uiState by collectLastValue(viewModel.shortcutsUiState)
+
+            testHelper.showFromActivity()
+
+            val activeUiState = uiState as ShortcutsUiState.Active
+            assertThat(activeUiState.shouldShowResetButton).isTrue()
+        }
+
     private fun groupWithShortcutLabels(
         vararg shortcutLabels: String,
         groupLabel: String = FIRST_SIMPLE_GROUP_LABEL,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
index 74a0bafda..df4d5ab 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
@@ -195,6 +195,7 @@
     @RequiresFlagsEnabled(Flags.FLAG_ENSURE_KEYGUARD_DOES_TRANSITION_STARTING)
     fun setSurfaceBehindVisibility_goesAwayFirst_andIgnoresSecondCall_with_keyguard_shell_transitions() {
         underTest.setLockscreenShown(true)
+        verify(keyguardTransitions).startKeyguardTransition(true, false)
         underTest.setSurfaceBehindVisibility(true)
         verify(keyguardTransitions).startKeyguardTransition(false, false)
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModelTest.kt
index 62cc763..97e6763 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenUserActionsViewModelTest.kt
@@ -306,8 +306,7 @@
                 // Top edge is not applicable in dual shade, as well as two-finger swipe.
                 assertThat(downDestination).isNull()
             } else {
-                assertThat(downDestination)
-                    .isEqualTo(ShowOverlay(Overlays.NotificationsShade, isIrreversible = true))
+                assertThat(downDestination).isEqualTo(ShowOverlay(Overlays.NotificationsShade))
                 assertThat(downDestination?.transitionKey).isNull()
             }
 
@@ -323,7 +322,7 @@
                 downWithTwoPointers -> assertThat(downFromTopRightDestination).isNull()
                 else -> {
                     assertThat(downFromTopRightDestination)
-                        .isEqualTo(ShowOverlay(Overlays.QuickSettingsShade, isIrreversible = true))
+                        .isEqualTo(ShowOverlay(Overlays.QuickSettingsShade))
                     assertThat(downFromTopRightDestination?.transitionKey).isNull()
                 }
             }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest_311121830.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest_311121830.kt
index ee2a1d5..411960f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest_311121830.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest_311121830.kt
@@ -16,7 +16,6 @@
 
 package com.android.systemui.qs.tileimpl
 
-import android.animation.AnimatorTestRule
 import android.content.Context
 import android.service.quicksettings.Tile
 import android.view.ContextThemeWrapper
@@ -26,6 +25,7 @@
 import androidx.test.annotation.UiThreadTest
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.AnimatorTestRule
 import com.android.systemui.plugins.qs.QSTile
 import com.android.systemui.res.R
 import com.android.systemui.statusbar.connectivity.WifiIcons
@@ -77,7 +77,7 @@
         // Set the second state to animate (it shouldn't, because `State.state` is the same) and
         // advance time to 2 animations length
         iconView.setIcon(secondState, /* allowAnimations= */ true)
-        animatorRule.advanceTimeBy(QSIconViewImpl.QS_ANIM_LENGTH * 2)
+        animatorRule.advanceAnimationDuration(QSIconViewImpl.QS_ANIM_LENGTH * 2)
 
         assertThat(iconView.mLastIcon).isEqualTo(secondState.icon)
     }
@@ -126,7 +126,7 @@
         // Set the third state to animate and advance time by two times the animation length
         // to guarantee that all animations are done
         iconView.setIcon(thirdState, /* allowAnimations= */ true)
-        animatorRule.advanceTimeBy(QSIconViewImpl.QS_ANIM_LENGTH * 2)
+        animatorRule.advanceAnimationDuration(QSIconViewImpl.QS_ANIM_LENGTH * 2)
 
         assertThat(iconView.mLastIcon).isEqualTo(thirdState.icon)
     }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt
index 9f84e34..f33de4d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt
@@ -128,7 +128,7 @@
                 viewModel,
                 dialogManager,
                 wifiStateWorker,
-                accessPointController
+                accessPointController,
             )
 
         underTest.initialize()
@@ -156,10 +156,7 @@
         testScope.runTest {
             connectivityRepository.defaultConnections.value = DefaultConnectionModel()
             wifiRepository.wifiScanResults.value =
-                listOf(
-                    WifiScanEntry(ssid = "ssid 1"),
-                    WifiScanEntry(ssid = "ssid 2"),
-                )
+                listOf(WifiScanEntry(ssid = "ssid 1"), WifiScanEntry(ssid = "ssid 2"))
 
             runCurrent()
             looper.processAllMessages()
@@ -204,10 +201,7 @@
         testScope.runTest {
             airplaneModeRepository.setIsAirplaneMode(true)
             connectivityRepository.defaultConnections.value =
-                DefaultConnectionModel(
-                    wifi = Wifi(true),
-                    isValidated = true,
-                )
+                DefaultConnectionModel(wifi = Wifi(true), isValidated = true)
             wifiRepository.setIsWifiEnabled(true)
             wifiRepository.setWifiNetwork(ACTIVE_WIFI)
 
@@ -222,10 +216,7 @@
     fun wifiConnected() =
         testScope.runTest {
             connectivityRepository.defaultConnections.value =
-                DefaultConnectionModel(
-                    wifi = Wifi(true),
-                    isValidated = true,
-                )
+                DefaultConnectionModel(wifi = Wifi(true), isValidated = true)
 
             wifiRepository.setIsWifiEnabled(true)
             wifiRepository.setWifiNetwork(ACTIVE_WIFI)
@@ -242,6 +233,7 @@
         whenever(wifiStateWorker.isWifiEnabled).thenReturn(true)
 
         underTest.secondaryClick(null)
+        looper.processAllMessages()
 
         verify(wifiStateWorker, times(1)).isWifiEnabled = eq(false)
     }
@@ -251,6 +243,7 @@
         whenever(wifiStateWorker.isWifiEnabled).thenReturn(false)
 
         underTest.secondaryClick(null)
+        looper.processAllMessages()
 
         verify(wifiStateWorker, times(1)).isWifiEnabled = eq(true)
     }
@@ -258,10 +251,6 @@
     companion object {
         const val WIFI_SSID = "test ssid"
         val ACTIVE_WIFI =
-            WifiNetworkModel.Active.of(
-                isValidated = true,
-                level = 4,
-                ssid = WIFI_SSID,
-            )
+            WifiNetworkModel.Active.of(isValidated = true, level = 4, ssid = WIFI_SSID)
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileTest.java
index 0cf9604..b5ec0a0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileTest.java
@@ -180,6 +180,7 @@
         when(mWifiStateWorker.isWifiEnabled()).thenReturn(true);
 
         mTile.secondaryClick(null);
+        mTestableLooper.processAllMessages();
 
         verify(mWifiStateWorker, times(1)).setWifiEnabled(eq(false));
     }
@@ -189,6 +190,7 @@
         when(mWifiStateWorker.isWifiEnabled()).thenReturn(false);
 
         mTile.secondaryClick(null);
+        mTestableLooper.processAllMessages();
 
         verify(mWifiStateWorker, times(1)).setWifiEnabled(eq(true));
     }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
index 03c1f92..4068d9f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
@@ -46,6 +46,9 @@
 import android.graphics.drawable.Icon;
 import android.os.Handler;
 import android.os.UserHandle;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.service.quickaccesswallet.Flags;
 import android.service.quickaccesswallet.GetWalletCardsError;
 import android.service.quickaccesswallet.GetWalletCardsResponse;
 import android.service.quickaccesswallet.QuickAccessWalletClient;
@@ -221,6 +224,7 @@
     }
 
     @Test
+    @DisableFlags({Flags.FLAG_LAUNCH_SELECTED_CARD_FROM_QS_TILE})
     public void testHandleClick_startQuickAccessUiIntent_noCard() {
         setUpWalletCard(/* hasCard= */ false);
 
@@ -234,6 +238,7 @@
     }
 
     @Test
+    @DisableFlags({Flags.FLAG_LAUNCH_SELECTED_CARD_FROM_QS_TILE})
     public void testHandleClick_startQuickAccessUiIntent_hasCard() {
         setUpWalletCard(/* hasCard= */ true);
 
@@ -247,6 +252,34 @@
     }
 
     @Test
+    @EnableFlags({Flags.FLAG_LAUNCH_SELECTED_CARD_FROM_QS_TILE})
+    public void testHandleClick_startCardIntent_noCard() {
+        setUpWalletCard(/* hasCard= */ false);
+
+        mTile.handleClick(/* view= */ null);
+        mTestableLooper.processAllMessages();
+
+        verify(mController).startQuickAccessUiIntent(
+                eq(mActivityStarter),
+                eq(null),
+                /* hasCard= */ eq(false));
+    }
+
+    @Test
+    @EnableFlags({Flags.FLAG_LAUNCH_SELECTED_CARD_FROM_QS_TILE})
+    public void testHandleClick_startCardIntent_hasCard() {
+        setUpWalletCard(/* hasCard= */ true);
+
+        mTile.handleClick(null /* view */);
+        mTestableLooper.processAllMessages();
+
+        verify(mController).startWalletCardPendingIntent(
+                any(),
+                eq(mActivityStarter),
+                eq(null));
+    }
+
+    @Test
     public void testHandleUpdateState_updateLabelAndIcon() {
         QSTile.State state = new QSTile.State();
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/GoneUserActionsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/GoneUserActionsViewModelTest.kt
index bb2e941..fc915ca 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/GoneUserActionsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/GoneUserActionsViewModelTest.kt
@@ -104,7 +104,7 @@
             runCurrent()
 
             assertThat(userActions?.get(swipeDownFromTopWithTwoFingers()))
-                .isEqualTo(UserActionResult(Scenes.QuickSettings, isIrreversible = true))
+                .isEqualTo(UserActionResult(Scenes.QuickSettings))
         }
 
     @Test
@@ -116,7 +116,7 @@
             runCurrent()
 
             assertThat(userActions?.get(swipeDownFromTopWithTwoFingers()))
-                .isEqualTo(UserActionResult(Scenes.Shade, ToSplitShade, isIrreversible = true))
+                .isEqualTo(UserActionResult(Scenes.Shade, ToSplitShade))
         }
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorTest.kt
index 7fed47a..e96dd16 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractorTest.kt
@@ -42,7 +42,8 @@
     fun notificationChip_startsWithStartingModel() =
         kosmos.runTest {
             val icon = mock<StatusBarIconView>()
-            val startingNotif = activeNotificationModel(key = "notif1", statusBarChipIcon = icon)
+            val startingNotif =
+                activeNotificationModel(key = "notif1", statusBarChipIcon = icon, whenTime = 5432)
 
             val underTest = factory.create(startingNotif)
 
@@ -50,6 +51,7 @@
 
             assertThat(latest!!.key).isEqualTo("notif1")
             assertThat(latest!!.statusBarChipIconView).isEqualTo(icon)
+            assertThat(latest!!.whenTime).isEqualTo(5432)
         }
 
     @Test
@@ -65,11 +67,16 @@
 
             val newIconView = mock<StatusBarIconView>()
             underTest.setNotification(
-                activeNotificationModel(key = "notif1", statusBarChipIcon = newIconView)
+                activeNotificationModel(
+                    key = "notif1",
+                    statusBarChipIcon = newIconView,
+                    whenTime = 6543,
+                )
             )
 
             assertThat(latest!!.key).isEqualTo("notif1")
             assertThat(latest!!.statusBarChipIconView).isEqualTo(newIconView)
+            assertThat(latest!!.whenTime).isEqualTo(6543)
         }
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt
index 702e101..5a894ca 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt
@@ -30,6 +30,7 @@
 import com.android.systemui.statusbar.notification.data.model.activeNotificationModel
 import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore
 import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
 import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
@@ -60,7 +61,7 @@
                     activeNotificationModel(
                         key = "notif",
                         statusBarChipIcon = mock<StatusBarIconView>(),
-                        isPromoted = true,
+                        promotedContent = PromotedNotificationContentModel.Builder("notif").build(),
                     )
                 )
             )
@@ -90,7 +91,7 @@
                     activeNotificationModel(
                         key = "notif",
                         statusBarChipIcon = null,
-                        isPromoted = true,
+                        promotedContent = PromotedNotificationContentModel.Builder("notif").build(),
                     )
                 )
             )
@@ -110,7 +111,7 @@
                     activeNotificationModel(
                         key = "notif",
                         statusBarChipIcon = icon,
-                        isPromoted = true,
+                        promotedContent = PromotedNotificationContentModel.Builder("notif").build(),
                     )
                 )
             )
@@ -133,17 +134,17 @@
                     activeNotificationModel(
                         key = "notif1",
                         statusBarChipIcon = firstIcon,
-                        isPromoted = true,
+                        promotedContent = PromotedNotificationContentModel.Builder("notif1").build(),
                     ),
                     activeNotificationModel(
                         key = "notif2",
                         statusBarChipIcon = secondIcon,
-                        isPromoted = true,
+                        promotedContent = PromotedNotificationContentModel.Builder("notif2").build(),
                     ),
                     activeNotificationModel(
                         key = "notif3",
                         statusBarChipIcon = mock<StatusBarIconView>(),
-                        isPromoted = false,
+                        promotedContent = null,
                     ),
                 )
             )
@@ -170,7 +171,7 @@
                     activeNotificationModel(
                         key = "notif",
                         statusBarChipIcon = firstIcon,
-                        isPromoted = true,
+                        promotedContent = PromotedNotificationContentModel.Builder("notif").build(),
                     )
                 )
             )
@@ -183,7 +184,7 @@
                     activeNotificationModel(
                         key = "notif",
                         statusBarChipIcon = secondIcon,
-                        isPromoted = true,
+                        promotedContent = PromotedNotificationContentModel.Builder("notif").build(),
                     )
                 )
             )
@@ -196,7 +197,7 @@
                     activeNotificationModel(
                         key = "notif",
                         statusBarChipIcon = thirdIcon,
-                        isPromoted = true,
+                        promotedContent = PromotedNotificationContentModel.Builder("notif").build(),
                     )
                 )
             )
@@ -216,7 +217,7 @@
                     activeNotificationModel(
                         key = "notif",
                         statusBarChipIcon = mock(),
-                        isPromoted = true,
+                        promotedContent = PromotedNotificationContentModel.Builder("notif").build(),
                     )
                 )
             )
@@ -228,7 +229,7 @@
                     activeNotificationModel(
                         key = "notif",
                         statusBarChipIcon = mock(),
-                        isPromoted = false,
+                        promotedContent = null,
                     )
                 )
             )
@@ -239,7 +240,7 @@
                     activeNotificationModel(
                         key = "notif",
                         statusBarChipIcon = mock(),
-                        isPromoted = true,
+                        promotedContent = PromotedNotificationContentModel.Builder("notif").build(),
                     )
                 )
             )
@@ -260,7 +261,8 @@
                     activeNotificationModel(
                         key = "notif|uid1",
                         statusBarChipIcon = firstIcon,
-                        isPromoted = true,
+                        promotedContent =
+                            PromotedNotificationContentModel.Builder("notif|uid1").build(),
                     )
                 )
             )
@@ -274,7 +276,8 @@
                     activeNotificationModel(
                         key = "notif|uid2",
                         statusBarChipIcon = secondIcon,
-                        isPromoted = true,
+                        promotedContent =
+                            PromotedNotificationContentModel.Builder("notif|uid2").build(),
                     )
                 )
             )
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt
index 16376c5..11831ca 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt
@@ -32,6 +32,7 @@
 import com.android.systemui.statusbar.notification.data.model.activeNotificationModel
 import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore
 import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
 import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
@@ -75,7 +76,7 @@
                     activeNotificationModel(
                         key = "notif",
                         statusBarChipIcon = null,
-                        isPromoted = true,
+                        promotedContent = PromotedNotificationContentModel.Builder("notif").build(),
                     )
                 )
             )
@@ -94,14 +95,14 @@
                     activeNotificationModel(
                         key = "notif",
                         statusBarChipIcon = icon,
-                        isPromoted = true,
+                        promotedContent = PromotedNotificationContentModel.Builder("notif").build(),
                     )
                 )
             )
 
             assertThat(latest).hasSize(1)
             val chip = latest!![0]
-            assertThat(chip).isInstanceOf(OngoingActivityChipModel.Shown.IconOnly::class.java)
+            assertThat(chip).isInstanceOf(OngoingActivityChipModel.Shown.ShortTimeDelta::class.java)
             assertThat(chip.icon).isEqualTo(OngoingActivityChipModel.ChipIcon.StatusBarView(icon))
         }
 
@@ -117,17 +118,17 @@
                     activeNotificationModel(
                         key = "notif1",
                         statusBarChipIcon = firstIcon,
-                        isPromoted = true,
+                        promotedContent = PromotedNotificationContentModel.Builder("notif1").build(),
                     ),
                     activeNotificationModel(
                         key = "notif2",
                         statusBarChipIcon = secondIcon,
-                        isPromoted = true,
+                        promotedContent = PromotedNotificationContentModel.Builder("notif2").build(),
                     ),
                     activeNotificationModel(
                         key = "notif3",
                         statusBarChipIcon = mock<StatusBarIconView>(),
-                        isPromoted = false,
+                        promotedContent = null,
                     ),
                 )
             )
@@ -151,7 +152,8 @@
                     activeNotificationModel(
                         key = "clickTest",
                         statusBarChipIcon = mock<StatusBarIconView>(),
-                        isPromoted = true,
+                        promotedContent =
+                            PromotedNotificationContentModel.Builder("clickTest").build(),
                     )
                 )
             )
@@ -171,7 +173,8 @@
 
     companion object {
         fun assertIsNotifChip(latest: OngoingActivityChipModel?, expectedIcon: StatusBarIconView) {
-            assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown.IconOnly::class.java)
+            assertThat(latest)
+                .isInstanceOf(OngoingActivityChipModel.Shown.ShortTimeDelta::class.java)
             assertThat((latest as OngoingActivityChipModel.Shown).icon)
                 .isEqualTo(OngoingActivityChipModel.ChipIcon.StatusBarView(expectedIcon))
         }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt
index eb0978e..b2e7feb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt
@@ -53,6 +53,7 @@
 import com.android.systemui.statusbar.notification.data.model.activeNotificationModel
 import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore
 import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
 import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel
 import com.android.systemui.statusbar.phone.SystemUIDialog
 import com.android.systemui.statusbar.phone.ongoingcall.data.repository.ongoingCallRepository
@@ -307,7 +308,7 @@
                     activeNotificationModel(
                         key = "notif",
                         statusBarChipIcon = icon,
-                        isPromoted = true,
+                        promotedContent = PromotedNotificationContentModel.Builder("notif").build(),
                     )
                 )
             )
@@ -328,12 +329,14 @@
                     activeNotificationModel(
                         key = "firstNotif",
                         statusBarChipIcon = firstIcon,
-                        isPromoted = true,
+                        promotedContent =
+                            PromotedNotificationContentModel.Builder("firstNotif").build(),
                     ),
                     activeNotificationModel(
                         key = "secondNotif",
                         statusBarChipIcon = secondIcon,
-                        isPromoted = true,
+                        promotedContent =
+                            PromotedNotificationContentModel.Builder("secondNotif").build(),
                     ),
                 )
             )
@@ -355,17 +358,20 @@
                     activeNotificationModel(
                         key = "firstNotif",
                         statusBarChipIcon = firstIcon,
-                        isPromoted = true,
+                        promotedContent =
+                            PromotedNotificationContentModel.Builder("firstNotif").build(),
                     ),
                     activeNotificationModel(
                         key = "secondNotif",
                         statusBarChipIcon = secondIcon,
-                        isPromoted = true,
+                        promotedContent =
+                            PromotedNotificationContentModel.Builder("secondNotif").build(),
                     ),
                     activeNotificationModel(
                         key = "thirdNotif",
                         statusBarChipIcon = thirdIcon,
-                        isPromoted = true,
+                        promotedContent =
+                            PromotedNotificationContentModel.Builder("thirdNotif").build(),
                     ),
                 )
             )
@@ -386,12 +392,14 @@
                     activeNotificationModel(
                         key = "firstNotif",
                         statusBarChipIcon = firstIcon,
-                        isPromoted = true,
+                        promotedContent =
+                            PromotedNotificationContentModel.Builder("firstNotif").build(),
                     ),
                     activeNotificationModel(
                         key = "secondNotif",
                         statusBarChipIcon = mock<StatusBarIconView>(),
-                        isPromoted = true,
+                        promotedContent =
+                            PromotedNotificationContentModel.Builder("secondNotif").build(),
                     ),
                 )
             )
@@ -412,7 +420,7 @@
                     activeNotificationModel(
                         key = "notif",
                         statusBarChipIcon = mock<StatusBarIconView>(),
-                        isPromoted = true,
+                        promotedContent = PromotedNotificationContentModel.Builder("notif").build(),
                     )
                 )
             )
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java
index ba85e32..657fffb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java
@@ -26,6 +26,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -45,6 +46,8 @@
 import com.android.systemui.communal.shared.model.CommunalScenes;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.BrokenWithSceneContainer;
+import com.android.systemui.flags.DisableSceneContainer;
+import com.android.systemui.flags.EnableSceneContainer;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.keyguard.shared.model.KeyguardState;
 import com.android.systemui.keyguard.shared.model.TransitionState;
@@ -68,6 +71,7 @@
 import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
 import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor;
 import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.kotlin.JavaAdapter;
 import com.android.systemui.util.time.FakeSystemClock;
@@ -110,6 +114,7 @@
     @Mock private VisibilityLocationProvider mVisibilityLocationProvider;
     @Mock private VisualStabilityProvider mVisualStabilityProvider;
     @Mock private VisualStabilityCoordinatorLogger mLogger;
+    @Mock private KeyguardStateController mKeyguardStateController;
 
     @Captor private ArgumentCaptor<WakefulnessLifecycle.Observer> mWakefulnessObserverCaptor;
     @Captor private ArgumentCaptor<StatusBarStateController.StateListener> mSBStateListenerCaptor;
@@ -155,6 +160,7 @@
                 mKosmos.getCommunalSceneInteractor(),
                 mKosmos.getShadeInteractor(),
                 mKosmos.getKeyguardTransitionInteractor(),
+                mKeyguardStateController,
                 mLogger);
         mCoordinator.attach(mNotifPipeline);
         mTestScope.getTestScheduler().runCurrent();
@@ -539,6 +545,25 @@
 
     @Test
     @EnableFlags(Flags.FLAG_CHECK_LOCKSCREEN_GONE_TRANSITION)
+    @DisableSceneContainer
+    public void testNotLockscreenInGoneTransitionLegacy_invalidationCalled() {
+        // GIVEN visual stability is being maintained b/c animation is playing
+        doReturn(true).when(mKeyguardStateController).isKeyguardFadingAway();
+        mCoordinator.mKeyguardFadeAwayAnimationCallback.onKeyguardFadingAwayChanged();
+
+        assertFalse(mNotifStabilityManager.isPipelineRunAllowed());
+
+        // WHEN the animation has stopped playing
+        doReturn(false).when(mKeyguardStateController).isKeyguardFadingAway();
+        mCoordinator.mKeyguardFadeAwayAnimationCallback.onKeyguardFadingAwayChanged();
+
+        // invalidate is called, b/c we were previously suppressing the pipeline from running
+        verifyStabilityManagerWasInvalidated(times(1));
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_CHECK_LOCKSCREEN_GONE_TRANSITION)
+    @EnableSceneContainer
     @BrokenWithSceneContainer(bugId = 377868472) // mReorderingAllowed is broken with SceneContainer
     public void testNotLockscreenInGoneTransition_invalidationCalled() {
         // GIVEN visual stability is being maintained b/c animation is playing
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractorTest.kt
index 99bda85..54ce88b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractorTest.kt
@@ -31,6 +31,7 @@
 import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore
 import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
 import com.android.systemui.statusbar.notification.data.repository.setActiveNotifs
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
 import com.android.systemui.statusbar.notification.shared.CallType
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
@@ -169,8 +170,12 @@
         testScope.runTest {
             val latest by collectLastValue(underTest.promotedOngoingNotifications)
 
-            val promoted1 = activeNotificationModel(key = "notif1", isPromoted = true)
-            val notPromoted2 = activeNotificationModel(key = "notif2", isPromoted = false)
+            val promoted1 =
+                activeNotificationModel(
+                    key = "notif1",
+                    promotedContent = PromotedNotificationContentModel.Builder("notif1").build(),
+                )
+            val notPromoted2 = activeNotificationModel(key = "notif2", promotedContent = null)
 
             activeNotificationListRepository.activeNotifications.value =
                 ActiveNotificationsStore.Builder()
@@ -189,9 +194,9 @@
 
             activeNotificationListRepository.activeNotifications.value =
                 ActiveNotificationsStore.Builder()
-                    .apply { activeNotificationModel(key = "notif1", isPromoted = false) }
-                    .apply { activeNotificationModel(key = "notif2", isPromoted = false) }
-                    .apply { activeNotificationModel(key = "notif3", isPromoted = false) }
+                    .apply { activeNotificationModel(key = "notif1", promotedContent = null) }
+                    .apply { activeNotificationModel(key = "notif2", promotedContent = null) }
+                    .apply { activeNotificationModel(key = "notif3", promotedContent = null) }
                     .build()
 
             assertThat(latest!!).isEmpty()
@@ -203,10 +208,18 @@
         testScope.runTest {
             val latest by collectLastValue(underTest.promotedOngoingNotifications)
 
-            val promoted1 = activeNotificationModel(key = "notif1", isPromoted = true)
-            val notPromoted2 = activeNotificationModel(key = "notif2", isPromoted = false)
-            val notPromoted3 = activeNotificationModel(key = "notif3", isPromoted = false)
-            val promoted4 = activeNotificationModel(key = "notif4", isPromoted = true)
+            val promoted1 =
+                activeNotificationModel(
+                    key = "notif1",
+                    promotedContent = PromotedNotificationContentModel.Builder("notif1").build(),
+                )
+            val notPromoted2 = activeNotificationModel(key = "notif2", promotedContent = null)
+            val notPromoted3 = activeNotificationModel(key = "notif3", promotedContent = null)
+            val promoted4 =
+                activeNotificationModel(
+                    key = "notif4",
+                    promotedContent = PromotedNotificationContentModel.Builder("notif4").build(),
+                )
 
             activeNotificationListRepository.activeNotifications.value =
                 ActiveNotificationsStore.Builder()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationsListInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationsListInteractorTest.kt
index 183f901..5d9aa71 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationsListInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationsListInteractorTest.kt
@@ -16,7 +16,6 @@
 package com.android.systemui.statusbar.notification.domain.interactor
 
 import android.app.Notification
-import android.app.Notification.FLAG_PROMOTED_ONGOING
 import android.platform.test.annotations.EnableFlags
 import android.service.notification.StatusBarNotification
 import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -29,7 +28,7 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
 import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi
-import com.android.systemui.statusbar.notification.promoted.promotedNotificationsProvider
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
 import com.android.systemui.statusbar.notification.shared.byKey
 import com.android.systemui.testKosmos
 import com.android.systemui.util.mockito.mock
@@ -48,11 +47,7 @@
     private val notifsRepository = kosmos.activeNotificationListRepository
     private val notifsInteractor = kosmos.activeNotificationsInteractor
     private val underTest =
-        RenderNotificationListInteractor(
-            notifsRepository,
-            sectionStyleProvider = mock(),
-            promotedNotificationsProvider = kosmos.promotedNotificationsProvider,
-        )
+        RenderNotificationListInteractor(notifsRepository, sectionStyleProvider = mock())
 
     @Test
     fun setRenderedList_preservesOrdering() =
@@ -127,12 +122,16 @@
 
     @Test
     @EnableFlags(PromotedNotificationUi.FLAG_NAME)
-    fun setRenderList_setsPromotionStatus() =
+    fun setRenderList_setsPromotionContent() =
         testScope.runTest {
             val actual by collectLastValue(notifsInteractor.topLevelRepresentativeNotifications)
 
-            val notPromoted1 = mockNotificationEntry("key1", flag = null)
-            val promoted2 = mockNotificationEntry("key2", flag = FLAG_PROMOTED_ONGOING)
+            val notPromoted1 = mockNotificationEntry("key1", promotedContent = null)
+            val promoted2 =
+                mockNotificationEntry(
+                    "key2",
+                    promotedContent = PromotedNotificationContentModel.Builder("key2").build(),
+                )
 
             underTest.setRenderedList(listOf(notPromoted1, promoted2))
 
@@ -140,22 +139,19 @@
 
             val first = actual!![0]
             assertThat(first.key).isEqualTo("key1")
-            assertThat(first.isPromoted).isFalse()
+            assertThat(first.promotedContent).isNull()
 
             val second = actual!![1]
             assertThat(second.key).isEqualTo("key2")
-            assertThat(second.isPromoted).isTrue()
+            assertThat(second.promotedContent).isNotNull()
         }
 
     private fun mockNotificationEntry(
         key: String,
         rank: Int = 0,
-        flag: Int? = null,
+        promotedContent: PromotedNotificationContentModel? = null,
     ): NotificationEntry {
         val nBuilder = Notification.Builder(context, "a")
-        if (flag != null) {
-            nBuilder.setFlag(flag, true)
-        }
         val notification = nBuilder.build()
 
         val mockSbn =
@@ -169,6 +165,7 @@
             whenever(this.representativeEntry).thenReturn(this)
             whenever(this.ranking).thenReturn(RankingBuilder().setRank(rank).build())
             whenever(this.sbn).thenReturn(mockSbn)
+            whenever(this.promotedNotificationContentModel).thenReturn(promotedContent)
         }
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/AvalancheControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/AvalancheControllerTest.kt
index 22a9c64..31a2bd0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/AvalancheControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/AvalancheControllerTest.kt
@@ -38,6 +38,7 @@
 import com.android.systemui.statusbar.policy.configurationController
 import com.android.systemui.testKosmos
 import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.concurrency.mockExecutorHandler
 import com.android.systemui.util.kotlin.JavaAdapter
 import com.android.systemui.util.settings.FakeGlobalSettings
 import com.android.systemui.util.time.FakeSystemClock
@@ -97,7 +98,7 @@
             AvalancheController(dumpManager, mUiEventLoggerFake, mHeadsUpManagerLogger, mBgHandler)
 
         testableHeadsUpManager =
-            TestableHeadsUpManager(
+            HeadsUpManagerImpl(
                 mContext,
                 mLogger,
                 kosmos.statusBarStateController,
@@ -105,9 +106,10 @@
                 GroupMembershipManagerImpl(),
                 kosmos.visualStabilityProvider,
                 kosmos.configurationController,
-                mExecutor,
+                mockExecutorHandler(mExecutor),
                 mGlobalSettings,
                 mSystemClock,
+                mExecutor,
                 mAccessibilityMgr,
                 mUiEventLoggerFake,
                 JavaAdapter(kosmos.testScope),
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplOldTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplOldTest.kt
index 44a8518..d2a7c61 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplOldTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplOldTest.kt
@@ -39,6 +39,7 @@
 import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper
 import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.concurrency.mockExecutorHandler
 import com.android.systemui.util.kotlin.JavaAdapter
 import com.android.systemui.util.settings.FakeGlobalSettings
 import com.android.systemui.util.time.FakeSystemClock
@@ -87,7 +88,7 @@
     @Mock protected var mRow: ExpandableNotificationRow? = null
 
     private fun createHeadsUpManager(): HeadsUpManagerImpl {
-        return TestableHeadsUpManager(
+        return HeadsUpManagerImpl(
             mContext,
             mLogger,
             mKosmos.statusBarStateController,
@@ -95,9 +96,10 @@
             GroupMembershipManagerImpl(),
             mKosmos.visualStabilityProvider,
             mKosmos.configurationController,
-            mExecutor,
+            mockExecutorHandler(mExecutor),
             mGlobalSettings,
             mSystemClock,
+            mExecutor,
             mAccessibilityMgr,
             mUiEventLoggerFake,
             JavaAdapter(mKosmos.testScope),
@@ -150,6 +152,24 @@
     @Throws(Exception::class)
     override fun SysuiSetup() {
         super.SysuiSetup()
+        mContext.getOrCreateTestableResources().apply {
+            this.addOverride(R.integer.ambient_notification_extension_time, TEST_EXTENSION_TIME)
+            this.addOverride(R.integer.touch_acceptance_delay, TEST_TOUCH_ACCEPTANCE_TIME)
+            this.addOverride(
+                R.integer.heads_up_notification_minimum_time,
+                TEST_MINIMUM_DISPLAY_TIME,
+            )
+            this.addOverride(
+                R.integer.heads_up_notification_minimum_time_with_throttling,
+                TEST_MINIMUM_DISPLAY_TIME,
+            )
+            this.addOverride(R.integer.heads_up_notification_decay, TEST_AUTO_DISMISS_TIME)
+            this.addOverride(
+                R.integer.sticky_heads_up_notification_time,
+                TEST_STICKY_AUTO_DISMISS_TIME,
+            )
+        }
+
         mAvalancheController =
             AvalancheController(dumpManager!!, mUiEventLoggerFake, mLogger, mBgHandler!!)
         Mockito.`when`(mShadeInteractor!!.isAnyExpanded).thenReturn(MutableStateFlow(true))
@@ -662,6 +682,7 @@
     companion object {
         const val TEST_TOUCH_ACCEPTANCE_TIME: Int = 200
         const val TEST_A11Y_AUTO_DISMISS_TIME: Int = 1000
+        const val TEST_EXTENSION_TIME = 500
 
         const val TEST_MINIMUM_DISPLAY_TIME: Int = 400
         const val TEST_AUTO_DISMISS_TIME: Int = 600
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplTest.kt
index 65d282f..96f0201 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplTest.kt
@@ -19,43 +19,40 @@
 import android.platform.test.annotations.EnableFlags
 import android.platform.test.flag.junit.FlagsParameterization
 import android.testing.TestableLooper.RunWithLooper
+import android.view.accessibility.accessibilityManagerWrapper
 import androidx.test.filters.SmallTest
-import com.android.internal.logging.UiEventLogger
-import com.android.systemui.dump.DumpManager
+import com.android.internal.logging.uiEventLoggerFake
+import com.android.systemui.dump.dumpManager
 import com.android.systemui.flags.andSceneContainer
+import com.android.systemui.kosmos.runTest
 import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
 import com.android.systemui.log.logcatLogBuffer
 import com.android.systemui.res.R
-import com.android.systemui.shade.domain.interactor.ShadeInteractor
-import com.android.systemui.statusbar.FakeStatusBarStateController
-import com.android.systemui.statusbar.NotificationShadeWindowController
+import com.android.systemui.shade.domain.interactor.shadeInteractor
+import com.android.systemui.shade.shadeTestUtil
 import com.android.systemui.statusbar.StatusBarState
-import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider
+import com.android.systemui.statusbar.notification.collection.provider.visualStabilityProvider
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager
 import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun
-import com.android.systemui.statusbar.phone.ConfigurationControllerImpl
-import com.android.systemui.statusbar.phone.KeyguardBypassController
-import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper
+import com.android.systemui.statusbar.phone.keyguardBypassController
+import com.android.systemui.statusbar.policy.configurationController
+import com.android.systemui.statusbar.sysuiStatusBarStateController
 import com.android.systemui.testKosmos
 import com.android.systemui.util.concurrency.mockExecutorHandler
 import com.android.systemui.util.kotlin.JavaAdapter
 import com.google.common.truth.Truth.assertThat
 import junit.framework.Assert
-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.Ignore
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers
-import org.mockito.Mock
+import org.mockito.kotlin.mock
 import org.mockito.kotlin.whenever
 import platform.test.runner.parameterized.ParameterizedAndroidJunit4
 import platform.test.runner.parameterized.Parameters
 
-@OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
 @RunWith(ParameterizedAndroidJunit4::class)
 @RunWithLooper
@@ -63,146 +60,133 @@
 
     private val mHeadsUpManagerLogger = HeadsUpManagerLogger(logcatLogBuffer())
 
-    private val kosmos = testKosmos()
+    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
     private val testScope = kosmos.testScope
 
-    @Mock private lateinit var mGroupManager: GroupMembershipManager
+    private val mGroupManager = mock<GroupMembershipManager>()
+    private val mBgHandler = mock<Handler>()
 
-    @Mock private lateinit var mVSProvider: VisualStabilityProvider
-
-    val statusBarStateController = FakeStatusBarStateController()
-
-    @Mock private lateinit var mBypassController: KeyguardBypassController
-
-    @Mock private lateinit var mConfigurationController: ConfigurationControllerImpl
-
-    @Mock private lateinit var mAccessibilityManagerWrapper: AccessibilityManagerWrapper
-
-    @Mock private lateinit var mUiEventLogger: UiEventLogger
-
+    val statusBarStateController = kosmos.sysuiStatusBarStateController
     private val mJavaAdapter: JavaAdapter = JavaAdapter(testScope.backgroundScope)
 
-    @Mock private lateinit var mShadeInteractor: ShadeInteractor
-    @Mock private lateinit var dumpManager: DumpManager
     private lateinit var mAvalancheController: AvalancheController
-
-    @Mock private lateinit var mBgHandler: Handler
-
-    private fun createHeadsUpManagerPhone(): HeadsUpManagerImpl {
-        return HeadsUpManagerImpl(
-            mContext,
-            mHeadsUpManagerLogger,
-            statusBarStateController,
-            mBypassController,
-            mGroupManager,
-            mVSProvider,
-            mConfigurationController,
-            mockExecutorHandler(mExecutor),
-            mGlobalSettings,
-            mSystemClock,
-            mExecutor,
-            mAccessibilityManagerWrapper,
-            mUiEventLogger,
-            mJavaAdapter,
-            mShadeInteractor,
-            mAvalancheController,
-        )
-    }
+    private lateinit var underTest: HeadsUpManagerImpl
 
     @Before
     fun setUp() {
-        whenever(mShadeInteractor.isAnyExpanded).thenReturn(MutableStateFlow(false))
-        whenever(mShadeInteractor.isQsExpanded).thenReturn(MutableStateFlow(false))
-        whenever(mBypassController.bypassEnabled).thenReturn(false)
-        whenever(mVSProvider.isReorderingAllowed).thenReturn(true)
-        val accessibilityMgr =
-            mDependency.injectMockDependency(AccessibilityManagerWrapper::class.java)
-        whenever(
-                accessibilityMgr.getRecommendedTimeoutMillis(
-                    ArgumentMatchers.anyInt(),
-                    ArgumentMatchers.anyInt(),
-                )
+        mContext.getOrCreateTestableResources().apply {
+            this.addOverride(R.integer.ambient_notification_extension_time, TEST_EXTENSION_TIME)
+            this.addOverride(R.integer.touch_acceptance_delay, TEST_TOUCH_ACCEPTANCE_TIME)
+            this.addOverride(
+                R.integer.heads_up_notification_minimum_time,
+                TEST_MINIMUM_DISPLAY_TIME,
             )
-            .thenReturn(TEST_AUTO_DISMISS_TIME)
-        mDependency.injectMockDependency(NotificationShadeWindowController::class.java)
-        mContext
-            .getOrCreateTestableResources()
-            .addOverride(R.integer.ambient_notification_extension_time, 500)
+            this.addOverride(
+                R.integer.heads_up_notification_minimum_time_with_throttling,
+                TEST_MINIMUM_DISPLAY_TIME,
+            )
+            this.addOverride(R.integer.heads_up_notification_decay, TEST_AUTO_DISMISS_TIME)
+            this.addOverride(
+                R.integer.sticky_heads_up_notification_time,
+                TEST_STICKY_AUTO_DISMISS_TIME,
+            )
+        }
+
+        whenever(kosmos.keyguardBypassController.bypassEnabled).thenReturn(false)
+        kosmos.visualStabilityProvider.isReorderingAllowed = true
         mAvalancheController =
-            AvalancheController(dumpManager, mUiEventLogger, mHeadsUpManagerLogger, mBgHandler)
+            AvalancheController(
+                kosmos.dumpManager,
+                kosmos.uiEventLoggerFake,
+                mHeadsUpManagerLogger,
+                mBgHandler,
+            )
+        underTest =
+            HeadsUpManagerImpl(
+                mContext,
+                mHeadsUpManagerLogger,
+                statusBarStateController,
+                kosmos.keyguardBypassController,
+                mGroupManager,
+                kosmos.visualStabilityProvider,
+                kosmos.configurationController,
+                mockExecutorHandler(mExecutor),
+                mGlobalSettings,
+                mSystemClock,
+                mExecutor,
+                kosmos.accessibilityManagerWrapper,
+                kosmos.uiEventLoggerFake,
+                mJavaAdapter,
+                kosmos.shadeInteractor,
+                mAvalancheController,
+            )
     }
 
     @Test
     fun testSnooze() {
-        val hmp: HeadsUpManager = createHeadsUpManagerPhone()
         val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
-        hmp.showNotification(entry)
-        hmp.snooze()
-        Assert.assertTrue(hmp.isSnoozed(entry.sbn.packageName))
+        underTest.showNotification(entry)
+        underTest.snooze()
+        Assert.assertTrue(underTest.isSnoozed(entry.sbn.packageName))
     }
 
     @Test
     fun testSwipedOutNotification() {
-        val hmp: HeadsUpManager = createHeadsUpManagerPhone()
         val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
-        hmp.showNotification(entry)
-        hmp.addSwipedOutNotification(entry.key)
+        underTest.showNotification(entry)
+        underTest.addSwipedOutNotification(entry.key)
 
         // Remove should succeed because the notification is swiped out
         val removedImmediately =
-            hmp.removeNotification(
+            underTest.removeNotification(
                 entry.key,
                 /* releaseImmediately= */ false,
                 /* reason= */ "swipe out",
             )
         Assert.assertTrue(removedImmediately)
-        Assert.assertFalse(hmp.isHeadsUpEntry(entry.key))
+        Assert.assertFalse(underTest.isHeadsUpEntry(entry.key))
     }
 
     @Test
     fun testCanRemoveImmediately_swipedOut() {
-        val hmp: HeadsUpManager = createHeadsUpManagerPhone()
         val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
-        hmp.showNotification(entry)
-        hmp.addSwipedOutNotification(entry.key)
+        underTest.showNotification(entry)
+        underTest.addSwipedOutNotification(entry.key)
 
         // Notification is swiped so it can be immediately removed.
-        Assert.assertTrue(hmp.canRemoveImmediately(entry.key))
+        Assert.assertTrue(underTest.canRemoveImmediately(entry.key))
     }
 
     @Ignore("b/141538055")
     @Test
     fun testCanRemoveImmediately_notTopEntry() {
-        val hmp: HeadsUpManager = createHeadsUpManagerPhone()
         val earlierEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
         val laterEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 1, mContext)
         laterEntry.row = mRow
-        hmp.showNotification(earlierEntry)
-        hmp.showNotification(laterEntry)
+        underTest.showNotification(earlierEntry)
+        underTest.showNotification(laterEntry)
 
         // Notification is "behind" a higher priority notification so we can remove it immediately.
-        Assert.assertTrue(hmp.canRemoveImmediately(earlierEntry.key))
+        Assert.assertTrue(underTest.canRemoveImmediately(earlierEntry.key))
     }
 
     @Test
     fun testExtendHeadsUp() {
-        val hmp = createHeadsUpManagerPhone()
         val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
-        hmp.showNotification(entry)
-        hmp.extendHeadsUp()
-        mSystemClock.advanceTime((TEST_AUTO_DISMISS_TIME + hmp.mExtensionTime / 2).toLong())
-        Assert.assertTrue(hmp.isHeadsUpEntry(entry.key))
+        underTest.showNotification(entry)
+        underTest.extendHeadsUp()
+        mSystemClock.advanceTime(((TEST_AUTO_DISMISS_TIME + TEST_EXTENSION_TIME) / 2).toLong())
+        Assert.assertTrue(underTest.isHeadsUpEntry(entry.key))
     }
 
     @Test
     @EnableFlags(NotificationThrottleHun.FLAG_NAME)
     fun testShowNotification_removeWhenReorderingAllowedTrue() {
-        whenever(mVSProvider.isReorderingAllowed).thenReturn(true)
-        val hmp = createHeadsUpManagerPhone()
+        kosmos.visualStabilityProvider.isReorderingAllowed = true
 
         val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
-        hmp.showNotification(notifEntry)
-        assertThat(hmp.mEntriesToRemoveWhenReorderingAllowed.contains(notifEntry)).isTrue()
+        underTest.showNotification(notifEntry)
+        assertThat(underTest.mEntriesToRemoveWhenReorderingAllowed.contains(notifEntry)).isTrue()
     }
 
     class TestAnimationStateHandler : AnimationStateHandler {
@@ -212,167 +196,157 @@
     @Test
     @EnableFlags(NotificationThrottleHun.FLAG_NAME)
     fun testReorderingAllowed_clearsListOfEntriesToRemove() {
-        whenever(mVSProvider.isReorderingAllowed).thenReturn(true)
-        val hmp = createHeadsUpManagerPhone()
+        kosmos.visualStabilityProvider.isReorderingAllowed = true
 
         val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
-        hmp.showNotification(notifEntry)
-        assertThat(hmp.mEntriesToRemoveWhenReorderingAllowed.contains(notifEntry)).isTrue()
+        underTest.showNotification(notifEntry)
+        assertThat(underTest.mEntriesToRemoveWhenReorderingAllowed.contains(notifEntry)).isTrue()
 
-        hmp.setAnimationStateHandler(TestAnimationStateHandler())
-        hmp.mOnReorderingAllowedListener.onReorderingAllowed()
-        assertThat(hmp.mEntriesToRemoveWhenReorderingAllowed.isEmpty()).isTrue()
+        underTest.setAnimationStateHandler(TestAnimationStateHandler())
+        underTest.mOnReorderingAllowedListener.onReorderingAllowed()
+        assertThat(underTest.mEntriesToRemoveWhenReorderingAllowed.isEmpty()).isTrue()
     }
 
     @Test
     @EnableFlags(NotificationThrottleHun.FLAG_NAME)
     fun testShowNotification_reorderNotAllowed_seenInShadeTrue() {
-        whenever(mVSProvider.isReorderingAllowed).thenReturn(false)
-        val hmp = createHeadsUpManagerPhone()
+        kosmos.visualStabilityProvider.isReorderingAllowed = false
 
         val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
-        hmp.showNotification(notifEntry)
+        underTest.showNotification(notifEntry)
         assertThat(notifEntry.isSeenInShade).isTrue()
     }
 
     @Test
     @EnableFlags(NotificationThrottleHun.FLAG_NAME)
     fun testShowNotification_reorderAllowed_seenInShadeFalse() {
-        whenever(mVSProvider.isReorderingAllowed).thenReturn(true)
-        val hmp = createHeadsUpManagerPhone()
+        kosmos.visualStabilityProvider.isReorderingAllowed = true
 
         val notifEntry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
-        hmp.showNotification(notifEntry)
+        underTest.showNotification(notifEntry)
         assertThat(notifEntry.isSeenInShade).isFalse()
     }
 
     @Test
     fun testShouldHeadsUpBecomePinned_noFSI_false() =
-        testScope.runTest {
-            val hum = createHeadsUpManagerPhone()
+        kosmos.runTest {
             statusBarStateController.setState(StatusBarState.KEYGUARD)
 
             val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
 
-            Assert.assertFalse(hum.shouldHeadsUpBecomePinned(entry))
+            Assert.assertFalse(underTest.shouldHeadsUpBecomePinned(entry))
         }
 
     @Test
     fun testShouldHeadsUpBecomePinned_hasFSI_notUnpinned_true() =
-        testScope.runTest {
-            val hum = createHeadsUpManagerPhone()
+        kosmos.runTest {
             statusBarStateController.setState(StatusBarState.KEYGUARD)
 
             val notifEntry =
                 HeadsUpManagerTestUtil.createFullScreenIntentEntry(/* id= */ 0, mContext)
 
             // Add notifEntry to ANM mAlertEntries map and make it NOT unpinned
-            hum.showNotification(notifEntry)
+            underTest.showNotification(notifEntry)
 
-            val headsUpEntry = hum.getHeadsUpEntry(notifEntry.key)
+            val headsUpEntry = underTest.getHeadsUpEntry(notifEntry.key)
             headsUpEntry!!.mWasUnpinned = false
 
-            Assert.assertTrue(hum.shouldHeadsUpBecomePinned(notifEntry))
+            Assert.assertTrue(underTest.shouldHeadsUpBecomePinned(notifEntry))
         }
 
     @Test
     fun testShouldHeadsUpBecomePinned_wasUnpinned_false() =
-        testScope.runTest {
-            val hum = createHeadsUpManagerPhone()
+        kosmos.runTest {
             statusBarStateController.setState(StatusBarState.KEYGUARD)
 
             val notifEntry =
                 HeadsUpManagerTestUtil.createFullScreenIntentEntry(/* id= */ 0, mContext)
 
             // Add notifEntry to ANM mAlertEntries map and make it unpinned
-            hum.showNotification(notifEntry)
+            underTest.showNotification(notifEntry)
 
-            val headsUpEntry = hum.getHeadsUpEntry(notifEntry.key)
+            val headsUpEntry = underTest.getHeadsUpEntry(notifEntry.key)
             headsUpEntry!!.mWasUnpinned = true
 
-            Assert.assertFalse(hum.shouldHeadsUpBecomePinned(notifEntry))
+            Assert.assertFalse(underTest.shouldHeadsUpBecomePinned(notifEntry))
         }
 
     @Test
     fun shouldHeadsUpBecomePinned_shadeNotExpanded_true() =
-        testScope.runTest {
+        kosmos.runTest {
             // GIVEN
-            whenever(mShadeInteractor.isAnyFullyExpanded).thenReturn(MutableStateFlow(false))
-            val hmp = createHeadsUpManagerPhone()
+            shadeTestUtil.setShadeExpansion(0f)
+            // TODO(b/381869885): Determine why we need both of these ShadeTestUtil calls.
+            shadeTestUtil.setLegacyExpandedOrAwaitingInputTransfer(false)
+
             val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
             statusBarStateController.setState(StatusBarState.SHADE)
-            runCurrent()
 
             // THEN
-            Assert.assertTrue(hmp.shouldHeadsUpBecomePinned(entry))
+            Assert.assertTrue(underTest.shouldHeadsUpBecomePinned(entry))
         }
 
     @Test
     fun shouldHeadsUpBecomePinned_shadeLocked_false() =
-        testScope.runTest {
+        kosmos.runTest {
             // GIVEN
-            val hmp = createHeadsUpManagerPhone()
             val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
             statusBarStateController.setState(StatusBarState.SHADE_LOCKED)
-            runCurrent()
 
             // THEN
-            Assert.assertFalse(hmp.shouldHeadsUpBecomePinned(entry))
+            Assert.assertFalse(underTest.shouldHeadsUpBecomePinned(entry))
         }
 
     @Test
     fun shouldHeadsUpBecomePinned_shadeUnknown_false() =
-        testScope.runTest {
+        kosmos.runTest {
             // GIVEN
-            val hmp = createHeadsUpManagerPhone()
             val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
             statusBarStateController.setState(1207)
-            runCurrent()
 
             // THEN
-            Assert.assertFalse(hmp.shouldHeadsUpBecomePinned(entry))
+            Assert.assertFalse(underTest.shouldHeadsUpBecomePinned(entry))
         }
 
     @Test
     fun shouldHeadsUpBecomePinned_keyguardWithBypassOn_true() =
-        testScope.runTest {
+        kosmos.runTest {
             // GIVEN
-            whenever(mBypassController.bypassEnabled).thenReturn(true)
-            val hmp = createHeadsUpManagerPhone()
+            whenever(keyguardBypassController.bypassEnabled).thenReturn(true)
+
             val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
             statusBarStateController.setState(StatusBarState.KEYGUARD)
-            runCurrent()
 
             // THEN
-            Assert.assertTrue(hmp.shouldHeadsUpBecomePinned(entry))
+            Assert.assertTrue(underTest.shouldHeadsUpBecomePinned(entry))
         }
 
     @Test
     fun shouldHeadsUpBecomePinned_keyguardWithBypassOff_false() =
-        testScope.runTest {
+        kosmos.runTest {
             // GIVEN
-            whenever(mBypassController.bypassEnabled).thenReturn(false)
-            val hmp = createHeadsUpManagerPhone()
+            whenever(keyguardBypassController.bypassEnabled).thenReturn(false)
+
             val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
             statusBarStateController.setState(StatusBarState.KEYGUARD)
-            runCurrent()
 
             // THEN
-            Assert.assertFalse(hmp.shouldHeadsUpBecomePinned(entry))
+            Assert.assertFalse(underTest.shouldHeadsUpBecomePinned(entry))
         }
 
     @Test
     fun shouldHeadsUpBecomePinned_shadeExpanded_false() =
-        testScope.runTest {
+        kosmos.runTest {
             // GIVEN
-            whenever(mShadeInteractor.isAnyExpanded).thenReturn(MutableStateFlow(true))
-            val hmp = createHeadsUpManagerPhone()
+            shadeTestUtil.setShadeExpansion(1f)
+            // TODO(b/381869885): Determine why we need both of these ShadeTestUtil calls.
+            shadeTestUtil.setLegacyExpandedOrAwaitingInputTransfer(true)
+
             val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext)
             statusBarStateController.setState(StatusBarState.SHADE)
-            runCurrent()
 
             // THEN
-            Assert.assertFalse(hmp.shouldHeadsUpBecomePinned(entry))
+            Assert.assertFalse(underTest.shouldHeadsUpBecomePinned(entry))
         }
 
     companion object {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/TestableHeadsUpManager.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/TestableHeadsUpManager.java
deleted file mode 100644
index 7ded1a5..0000000
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/TestableHeadsUpManager.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * 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.notification.headsup;
-
-import static com.android.systemui.util.concurrency.MockExecutorHandlerKt.mockExecutorHandler;
-
-import static org.mockito.Mockito.spy;
-
-import android.content.Context;
-import android.graphics.Region;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.internal.logging.UiEventLogger;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.shade.domain.interactor.ShadeInteractor;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
-import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
-import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.util.concurrency.DelayableExecutor;
-import com.android.systemui.util.kotlin.JavaAdapter;
-import com.android.systemui.util.settings.GlobalSettings;
-import com.android.systemui.util.time.SystemClock;
-
-class TestableHeadsUpManager extends HeadsUpManagerImpl {
-
-    private HeadsUpEntry mLastCreatedEntry;
-
-    TestableHeadsUpManager(
-            Context context,
-            HeadsUpManagerLogger logger,
-            StatusBarStateController statusBarStateController,
-            KeyguardBypassController bypassController,
-            GroupMembershipManager groupMembershipManager,
-            VisualStabilityProvider visualStabilityProvider,
-            ConfigurationController configurationController,
-            DelayableExecutor executor,
-            GlobalSettings globalSettings,
-            SystemClock systemClock,
-            AccessibilityManagerWrapper accessibilityManagerWrapper,
-            UiEventLogger uiEventLogger,
-            JavaAdapter javaAdapter,
-            ShadeInteractor shadeInteractor,
-            AvalancheController avalancheController) {
-        super(
-                context,
-                logger,
-                statusBarStateController,
-                bypassController,
-                groupMembershipManager,
-                visualStabilityProvider,
-                configurationController,
-                mockExecutorHandler(executor),
-                globalSettings,
-                systemClock,
-                executor,
-                accessibilityManagerWrapper,
-                uiEventLogger,
-                javaAdapter,
-                shadeInteractor,
-                avalancheController);
-
-        mTouchAcceptanceDelay = HeadsUpManagerImplOldTest.TEST_TOUCH_ACCEPTANCE_TIME;
-        mMinimumDisplayTime = HeadsUpManagerImplOldTest.TEST_MINIMUM_DISPLAY_TIME;
-        mAutoDismissTime = HeadsUpManagerImplOldTest.TEST_AUTO_DISMISS_TIME;
-        mStickyForSomeTimeAutoDismissTime = HeadsUpManagerImplOldTest.TEST_STICKY_AUTO_DISMISS_TIME;
-    }
-
-    @NonNull
-    @Override
-    protected HeadsUpEntry createHeadsUpEntry(NotificationEntry entry) {
-        mLastCreatedEntry = spy(super.createHeadsUpEntry(entry));
-        return mLastCreatedEntry;
-    }
-
-    // The following are only implemented by HeadsUpManagerPhone. If you need them, use that.
-    @Override
-    public void addHeadsUpPhoneListener(@NonNull OnHeadsUpPhoneListenerChange listener) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void addSwipedOutNotification(@NonNull String key) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void extendHeadsUp() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Nullable
-    @Override
-    public Region getTouchableRegion() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public boolean isHeadsUpAnimatingAwayValue() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void onExpandingFinished() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public boolean removeNotification(@NonNull String key, boolean releaseImmediately,
-            boolean animate, @NonNull String reason) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void setAnimationStateHandler(@NonNull AnimationStateHandler handler) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void setGutsShown(@NonNull NotificationEntry entry, boolean gutsShown) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void setRemoteInputActive(@NonNull NotificationEntry entry,
-            boolean remoteInputActive) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public void setTrackingHeadsUp(boolean tracking) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public boolean shouldSwallowClick(@NonNull String key) {
-        throw new UnsupportedOperationException();
-    }
-}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
deleted file mode 100644
index 3bd12e6..0000000
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar.phone;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.platform.test.annotations.DisableFlags;
-import android.testing.TestableLooper;
-import android.testing.TestableLooper.RunWithLooper;
-import android.view.View;
-import android.widget.TextView;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.plugins.DarkIconDispatcher;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.shade.ShadeHeadsUpTracker;
-import com.android.systemui.shade.ShadeViewController;
-import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.HeadsUpStatusBarView;
-import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationIconInteractor;
-import com.android.systemui.statusbar.notification.headsup.PinnedStatus;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
-import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation;
-import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager;
-import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
-import com.android.systemui.statusbar.policy.Clock;
-import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.Optional;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-@RunWithLooper
-public class HeadsUpAppearanceControllerTest extends SysuiTestCase {
-
-    private final NotificationStackScrollLayoutController mStackScrollerController =
-            mock(NotificationStackScrollLayoutController.class);
-    private final ShadeViewController mShadeViewController =
-            mock(ShadeViewController.class);
-    private final ShadeHeadsUpTracker mShadeHeadsUpTracker = mock(ShadeHeadsUpTracker.class);
-    private final DarkIconDispatcher mDarkIconDispatcher = mock(DarkIconDispatcher.class);
-    private HeadsUpAppearanceController mHeadsUpAppearanceController;
-    private NotificationTestHelper mTestHelper;
-    private ExpandableNotificationRow mRow;
-    private NotificationEntry mEntry;
-    private HeadsUpStatusBarView mHeadsUpStatusBarView;
-    private HeadsUpManager mHeadsUpManager;
-    private View mOperatorNameView;
-    private StatusBarStateController mStatusbarStateController;
-    private PhoneStatusBarTransitions mPhoneStatusBarTransitions;
-    private KeyguardBypassController mBypassController;
-    private NotificationWakeUpCoordinator mWakeUpCoordinator;
-    private KeyguardStateController mKeyguardStateController;
-    private CommandQueue mCommandQueue;
-    private NotificationRoundnessManager mNotificationRoundnessManager;
-
-    @Before
-    public void setUp() throws Exception {
-        allowTestableLooperAsMainThread();
-        mTestHelper = new NotificationTestHelper(
-                mContext,
-                mDependency,
-                TestableLooper.get(this));
-        mRow = mTestHelper.createRow();
-        mEntry = mRow.getEntry();
-        mHeadsUpStatusBarView = new HeadsUpStatusBarView(mContext, mock(View.class),
-                mock(TextView.class));
-        mHeadsUpManager = mock(HeadsUpManager.class);
-        mOperatorNameView = new View(mContext);
-        mStatusbarStateController = mock(StatusBarStateController.class);
-        mPhoneStatusBarTransitions = mock(PhoneStatusBarTransitions.class);
-        mBypassController = mock(KeyguardBypassController.class);
-        mWakeUpCoordinator = mock(NotificationWakeUpCoordinator.class);
-        mKeyguardStateController = mock(KeyguardStateController.class);
-        mCommandQueue = mock(CommandQueue.class);
-        mNotificationRoundnessManager = mock(NotificationRoundnessManager.class);
-        when(mShadeViewController.getShadeHeadsUpTracker()).thenReturn(mShadeHeadsUpTracker);
-        mHeadsUpAppearanceController = new HeadsUpAppearanceController(
-                mHeadsUpManager,
-                mStatusbarStateController,
-                mPhoneStatusBarTransitions,
-                mBypassController,
-                mWakeUpCoordinator,
-                mDarkIconDispatcher,
-                mKeyguardStateController,
-                mCommandQueue,
-                mStackScrollerController,
-                mShadeViewController,
-                mNotificationRoundnessManager,
-                mHeadsUpStatusBarView,
-                new Clock(mContext, null),
-                mock(HeadsUpNotificationIconInteractor.class),
-                Optional.of(mOperatorNameView));
-        mHeadsUpAppearanceController.setAppearFraction(0.0f, 0.0f);
-    }
-
-    @Test
-    public void testShowinEntryUpdated() {
-        mRow.setPinnedStatus(PinnedStatus.PinnedBySystem);
-        when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
-        when(mHeadsUpManager.getTopEntry()).thenReturn(mEntry);
-        mHeadsUpAppearanceController.onHeadsUpPinned(mEntry);
-        assertEquals(mRow.getEntry(), mHeadsUpStatusBarView.getShowingEntry());
-
-        mRow.setPinnedStatus(PinnedStatus.NotPinned);
-        when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
-        mHeadsUpAppearanceController.onHeadsUpUnPinned(mEntry);
-        assertNull(mHeadsUpStatusBarView.getShowingEntry());
-    }
-
-    @Test
-    public void testPinnedStatusUpdated() {
-        mRow.setPinnedStatus(PinnedStatus.PinnedBySystem);
-        when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
-        when(mHeadsUpManager.getTopEntry()).thenReturn(mEntry);
-        mHeadsUpAppearanceController.onHeadsUpPinned(mEntry);
-        assertEquals(PinnedStatus.PinnedBySystem, mHeadsUpAppearanceController.getPinnedStatus());
-
-        mRow.setPinnedStatus(PinnedStatus.NotPinned);
-        when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
-        mHeadsUpAppearanceController.onHeadsUpUnPinned(mEntry);
-        assertEquals(PinnedStatus.NotPinned, mHeadsUpAppearanceController.getPinnedStatus());
-    }
-
-    @Test
-    @DisableFlags(AsyncGroupHeaderViewInflation.FLAG_NAME)
-    public void testHeaderUpdated() {
-        mRow.setPinnedStatus(PinnedStatus.PinnedBySystem);
-        when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
-        when(mHeadsUpManager.getTopEntry()).thenReturn(mEntry);
-        mHeadsUpAppearanceController.onHeadsUpPinned(mEntry);
-        assertEquals(mRow.getHeaderVisibleAmount(), 0.0f, 0.0f);
-
-        mRow.setPinnedStatus(PinnedStatus.NotPinned);
-        when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
-        mHeadsUpAppearanceController.onHeadsUpUnPinned(mEntry);
-        assertEquals(mRow.getHeaderVisibleAmount(), 1.0f, 0.0f);
-    }
-
-    @Test
-    public void testOperatorNameViewUpdated() {
-        mHeadsUpAppearanceController.setAnimationsEnabled(false);
-
-        mRow.setPinnedStatus(PinnedStatus.PinnedBySystem);
-        when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
-        when(mHeadsUpManager.getTopEntry()).thenReturn(mEntry);
-        mHeadsUpAppearanceController.onHeadsUpPinned(mEntry);
-        assertEquals(View.INVISIBLE, mOperatorNameView.getVisibility());
-
-        mRow.setPinnedStatus(PinnedStatus.NotPinned);
-        when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
-        mHeadsUpAppearanceController.onHeadsUpUnPinned(mEntry);
-        assertEquals(View.VISIBLE, mOperatorNameView.getVisibility());
-    }
-
-    @Test
-    public void constructor_animationValuesUpdated() {
-        float appearFraction = .75f;
-        float expandedHeight = 400f;
-        when(mStackScrollerController.getAppearFraction()).thenReturn(appearFraction);
-        when(mStackScrollerController.getExpandedHeight()).thenReturn(expandedHeight);
-
-        HeadsUpAppearanceController newController = new HeadsUpAppearanceController(
-                mHeadsUpManager,
-                mStatusbarStateController,
-                mPhoneStatusBarTransitions,
-                mBypassController,
-                mWakeUpCoordinator,
-                mDarkIconDispatcher,
-                mKeyguardStateController,
-                mCommandQueue,
-                mStackScrollerController,
-                mShadeViewController,
-                mNotificationRoundnessManager,
-                mHeadsUpStatusBarView,
-                new Clock(mContext, null),
-                mock(HeadsUpNotificationIconInteractor.class),
-                Optional.empty());
-
-        assertEquals(expandedHeight, newController.mExpandedHeight, 0.0f);
-        assertEquals(appearFraction, newController.mAppearFraction, 0.0f);
-    }
-
-    @Test
-    public void testDestroy() {
-        reset(mHeadsUpManager);
-        reset(mDarkIconDispatcher);
-        reset(mShadeHeadsUpTracker);
-        reset(mStackScrollerController);
-
-        mHeadsUpAppearanceController.onViewDetached();
-
-        verify(mHeadsUpManager).removeListener(any());
-        verify(mDarkIconDispatcher).removeDarkReceiver(any());
-        verify(mShadeHeadsUpTracker).removeTrackingHeadsUpListener(any());
-        verify(mShadeHeadsUpTracker).setHeadsUpAppearanceController(isNull());
-        verify(mStackScrollerController).removeOnExpandedHeightChangedListener(any());
-    }
-
-    @Test
-    public void testPulsingRoundness_onUpdateHeadsUpAndPulsingRoundness() {
-        // Pulsing: Enable flag and dozing
-        when(mNotificationRoundnessManager.shouldRoundNotificationPulsing()).thenReturn(true);
-        when(mTestHelper.getStatusBarStateController().isDozing()).thenReturn(true);
-
-        // Pulsing: Enabled
-        mRow.setHeadsUp(true);
-        mHeadsUpAppearanceController.updateHeadsUpAndPulsingRoundness(mEntry);
-
-        String debugString = mRow.getRoundableState().debugString();
-        assertEquals(
-                "If Pulsing is enabled, roundness should be set to 1. Value: " + debugString,
-                /* expected = */ 1,
-                /* actual = */ mRow.getTopRoundness(),
-                /* delta = */ 0.001
-        );
-        assertTrue(debugString.contains("Pulsing"));
-
-        // Pulsing: Disabled
-        mRow.setHeadsUp(false);
-        mHeadsUpAppearanceController.updateHeadsUpAndPulsingRoundness(mEntry);
-
-        assertEquals(
-                "If Pulsing is disabled, roundness should be set to 0. Value: "
-                        + mRow.getRoundableState().debugString(),
-                /* expected = */ 0,
-                /* actual = */ mRow.getTopRoundness(),
-                /* delta = */ 0.001
-        );
-    }
-
-    @Test
-    public void testPulsingRoundness_onHeadsUpStateChanged() {
-        // Pulsing: Enable flag and dozing
-        when(mNotificationRoundnessManager.shouldRoundNotificationPulsing()).thenReturn(true);
-        when(mTestHelper.getStatusBarStateController().isDozing()).thenReturn(true);
-
-        // Pulsing: Enabled
-        mEntry.setHeadsUp(true);
-        mHeadsUpAppearanceController.onHeadsUpStateChanged(mEntry, true);
-
-        String debugString = mRow.getRoundableState().debugString();
-        assertEquals(
-                "If Pulsing is enabled, roundness should be set to 1. Value: " + debugString,
-                /* expected = */ 1,
-                /* actual = */ mRow.getTopRoundness(),
-                /* delta = */ 0.001
-        );
-        assertTrue(debugString.contains("Pulsing"));
-
-        // Pulsing: Disabled
-        mEntry.setHeadsUp(false);
-        mHeadsUpAppearanceController.onHeadsUpStateChanged(mEntry, false);
-
-        assertEquals(
-                "If Pulsing is disabled, roundness should be set to 0. Value: "
-                        + mRow.getRoundableState().debugString(),
-                /* expected = */ 0,
-                /* actual = */ mRow.getTopRoundness(),
-                /* delta = */ 0.001
-        );
-    }
-
-    @Test
-    public void onHeadsUpStateChanged_true_transitionsNotified() {
-        mHeadsUpAppearanceController.onHeadsUpStateChanged(mEntry, true);
-
-        verify(mPhoneStatusBarTransitions).onHeadsUpStateChanged(true);
-    }
-
-    @Test
-    public void onHeadsUpStateChanged_false_transitionsNotified() {
-        mHeadsUpAppearanceController.onHeadsUpStateChanged(mEntry, false);
-
-        verify(mPhoneStatusBarTransitions).onHeadsUpStateChanged(false);
-    }
-}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.kt
new file mode 100644
index 0000000..d017402
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.kt
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.systemui.statusbar.phone
+
+import android.platform.test.annotations.DisableFlags
+import android.testing.TestableLooper
+import android.testing.TestableLooper.RunWithLooper
+import android.view.View
+import android.widget.TextView
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.plugins.DarkIconDispatcher
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.shade.ShadeHeadsUpTracker
+import com.android.systemui.shade.ShadeViewController
+import com.android.systemui.statusbar.CommandQueue
+import com.android.systemui.statusbar.HeadsUpStatusBarView
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationIconInteractor
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
+import com.android.systemui.statusbar.notification.headsup.PinnedStatus
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.row.NotificationTestHelper
+import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation
+import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.policy.Clock
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.google.common.truth.Truth.assertThat
+import java.util.Optional
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.reset
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@RunWithLooper
+class HeadsUpAppearanceControllerTest : SysuiTestCase() {
+    private val mStackScrollerController: NotificationStackScrollLayoutController =
+        mock<NotificationStackScrollLayoutController>()
+    private val mShadeViewController: ShadeViewController = mock<ShadeViewController>()
+    private val mShadeHeadsUpTracker: ShadeHeadsUpTracker = mock<ShadeHeadsUpTracker>()
+    private val mDarkIconDispatcher: DarkIconDispatcher = mock<DarkIconDispatcher>()
+    private var mHeadsUpAppearanceController: HeadsUpAppearanceController? = null
+    private var mTestHelper: NotificationTestHelper? = null
+    private var mRow: ExpandableNotificationRow? = null
+    private var mEntry: NotificationEntry? = null
+    private var mHeadsUpStatusBarView: HeadsUpStatusBarView? = null
+    private var mHeadsUpManager: HeadsUpManager? = null
+    private var mOperatorNameView: View? = null
+    private var mStatusbarStateController: StatusBarStateController? = null
+    private var mPhoneStatusBarTransitions: PhoneStatusBarTransitions? = null
+    private var mBypassController: KeyguardBypassController? = null
+    private var mWakeUpCoordinator: NotificationWakeUpCoordinator? = null
+    private var mKeyguardStateController: KeyguardStateController? = null
+    private var mCommandQueue: CommandQueue? = null
+    private var mNotificationRoundnessManager: NotificationRoundnessManager? = null
+
+    @Before
+    @Throws(Exception::class)
+    fun setUp() {
+        allowTestableLooperAsMainThread()
+        mTestHelper = NotificationTestHelper(mContext, mDependency, TestableLooper.get(this))
+        mRow = mTestHelper!!.createRow()
+        mEntry = mRow!!.entry
+        mHeadsUpStatusBarView = HeadsUpStatusBarView(mContext, mock<View>(), mock<TextView>())
+        mHeadsUpManager = mock<HeadsUpManager>()
+        mOperatorNameView = View(mContext)
+        mStatusbarStateController = mock<StatusBarStateController>()
+        mPhoneStatusBarTransitions = mock<PhoneStatusBarTransitions>()
+        mBypassController = mock<KeyguardBypassController>()
+        mWakeUpCoordinator = mock<NotificationWakeUpCoordinator>()
+        mKeyguardStateController = mock<KeyguardStateController>()
+        mCommandQueue = mock<CommandQueue>()
+        mNotificationRoundnessManager = mock<NotificationRoundnessManager>()
+        whenever(mShadeViewController.shadeHeadsUpTracker).thenReturn(mShadeHeadsUpTracker)
+        mHeadsUpAppearanceController =
+            HeadsUpAppearanceController(
+                mHeadsUpManager,
+                mStatusbarStateController,
+                mPhoneStatusBarTransitions,
+                mBypassController,
+                mWakeUpCoordinator,
+                mDarkIconDispatcher,
+                mKeyguardStateController,
+                mCommandQueue,
+                mStackScrollerController,
+                mShadeViewController,
+                mNotificationRoundnessManager,
+                mHeadsUpStatusBarView,
+                Clock(mContext, null),
+                mock<HeadsUpNotificationIconInteractor>(),
+                Optional.of(mOperatorNameView!!),
+            )
+        mHeadsUpAppearanceController!!.setAppearFraction(0.0f, 0.0f)
+    }
+
+    @Test
+    fun testShowinEntryUpdated() {
+        mRow!!.setPinnedStatus(PinnedStatus.PinnedBySystem)
+        whenever(mHeadsUpManager!!.hasPinnedHeadsUp()).thenReturn(true)
+        whenever(mHeadsUpManager!!.getTopEntry()).thenReturn(mEntry)
+        mHeadsUpAppearanceController!!.onHeadsUpPinned(mEntry)
+        assertThat(mHeadsUpStatusBarView!!.showingEntry).isEqualTo(mRow!!.entry)
+
+        mRow!!.setPinnedStatus(PinnedStatus.NotPinned)
+        whenever(mHeadsUpManager!!.hasPinnedHeadsUp()).thenReturn(false)
+        mHeadsUpAppearanceController!!.onHeadsUpUnPinned(mEntry)
+        assertThat(mHeadsUpStatusBarView!!.showingEntry).isNull()
+    }
+
+    @Test
+    fun testPinnedStatusUpdated() {
+        mRow!!.setPinnedStatus(PinnedStatus.PinnedBySystem)
+        whenever(mHeadsUpManager!!.hasPinnedHeadsUp()).thenReturn(true)
+        whenever(mHeadsUpManager!!.getTopEntry()).thenReturn(mEntry)
+        mHeadsUpAppearanceController!!.onHeadsUpPinned(mEntry)
+        assertThat(mHeadsUpAppearanceController!!.pinnedStatus)
+            .isEqualTo(PinnedStatus.PinnedBySystem)
+
+        mRow!!.setPinnedStatus(PinnedStatus.NotPinned)
+        whenever(mHeadsUpManager!!.hasPinnedHeadsUp()).thenReturn(false)
+        mHeadsUpAppearanceController!!.onHeadsUpUnPinned(mEntry)
+        assertThat(mHeadsUpAppearanceController!!.pinnedStatus).isEqualTo(PinnedStatus.NotPinned)
+    }
+
+    @Test
+    @DisableFlags(AsyncGroupHeaderViewInflation.FLAG_NAME)
+    fun testHeaderUpdated() {
+        mRow!!.setPinnedStatus(PinnedStatus.PinnedBySystem)
+        whenever(mHeadsUpManager!!.hasPinnedHeadsUp()).thenReturn(true)
+        whenever(mHeadsUpManager!!.getTopEntry()).thenReturn(mEntry)
+        mHeadsUpAppearanceController!!.onHeadsUpPinned(mEntry)
+        assertThat(mRow!!.headerVisibleAmount).isEqualTo(0.0f)
+
+        mRow!!.setPinnedStatus(PinnedStatus.NotPinned)
+        whenever(mHeadsUpManager!!.hasPinnedHeadsUp()).thenReturn(false)
+        mHeadsUpAppearanceController!!.onHeadsUpUnPinned(mEntry)
+        assertThat(mRow!!.headerVisibleAmount).isEqualTo(1.0f)
+    }
+
+    @Test
+    fun testOperatorNameViewUpdated() {
+        mHeadsUpAppearanceController!!.setAnimationsEnabled(false)
+
+        mRow!!.setPinnedStatus(PinnedStatus.PinnedBySystem)
+        whenever(mHeadsUpManager!!.hasPinnedHeadsUp()).thenReturn(true)
+        whenever(mHeadsUpManager!!.getTopEntry()).thenReturn(mEntry)
+        mHeadsUpAppearanceController!!.onHeadsUpPinned(mEntry)
+        assertThat(mOperatorNameView!!.visibility).isEqualTo(View.INVISIBLE)
+
+        mRow!!.setPinnedStatus(PinnedStatus.NotPinned)
+        whenever(mHeadsUpManager!!.hasPinnedHeadsUp()).thenReturn(false)
+        mHeadsUpAppearanceController!!.onHeadsUpUnPinned(mEntry)
+        assertThat(mOperatorNameView!!.visibility).isEqualTo(View.VISIBLE)
+    }
+
+    @Test
+    fun constructor_animationValuesUpdated() {
+        val appearFraction = .75f
+        val expandedHeight = 400f
+        whenever(mStackScrollerController.appearFraction).thenReturn(appearFraction)
+        whenever(mStackScrollerController.expandedHeight).thenReturn(expandedHeight)
+
+        val newController =
+            HeadsUpAppearanceController(
+                mHeadsUpManager,
+                mStatusbarStateController,
+                mPhoneStatusBarTransitions,
+                mBypassController,
+                mWakeUpCoordinator,
+                mDarkIconDispatcher,
+                mKeyguardStateController,
+                mCommandQueue,
+                mStackScrollerController,
+                mShadeViewController,
+                mNotificationRoundnessManager,
+                mHeadsUpStatusBarView,
+                Clock(mContext, null),
+                mock<HeadsUpNotificationIconInteractor>(),
+                Optional.empty(),
+            )
+
+        assertThat(newController.mExpandedHeight).isEqualTo(expandedHeight)
+        assertThat(newController.mAppearFraction).isEqualTo(appearFraction)
+    }
+
+    @Test
+    fun testDestroy() {
+        reset(mHeadsUpManager)
+        reset(mDarkIconDispatcher)
+        reset(mShadeHeadsUpTracker)
+        reset(mStackScrollerController)
+
+        mHeadsUpAppearanceController!!.onViewDetached()
+
+        verify(mHeadsUpManager!!).removeListener(any())
+        verify(mDarkIconDispatcher).removeDarkReceiver(any())
+        verify(mShadeHeadsUpTracker).removeTrackingHeadsUpListener(any())
+        verify(mShadeHeadsUpTracker).setHeadsUpAppearanceController(null)
+        verify(mStackScrollerController).removeOnExpandedHeightChangedListener(any())
+    }
+
+    @Test
+    fun testPulsingRoundness_onUpdateHeadsUpAndPulsingRoundness() {
+        // Pulsing: Enable flag and dozing
+        whenever(mNotificationRoundnessManager!!.shouldRoundNotificationPulsing()).thenReturn(true)
+        whenever(mTestHelper!!.statusBarStateController.isDozing).thenReturn(true)
+
+        // Pulsing: Enabled
+        mRow!!.isHeadsUp = true
+        mHeadsUpAppearanceController!!.updateHeadsUpAndPulsingRoundness(mEntry)
+
+        val debugString: String = mRow!!.roundableState.debugString()
+        // If Pulsing is enabled, roundness should be set to 1
+        assertThat(mRow!!.topRoundness.toDouble()).isWithin(0.001).of(1.0)
+        assertThat(debugString).contains("Pulsing")
+
+        // Pulsing: Disabled
+        mRow!!.isHeadsUp = false
+        mHeadsUpAppearanceController!!.updateHeadsUpAndPulsingRoundness(mEntry)
+
+        // If Pulsing is disabled, roundness should be set to 0
+        assertThat(mRow!!.topRoundness.toDouble()).isWithin(0.001).of(0.0)
+    }
+
+    @Test
+    fun testPulsingRoundness_onHeadsUpStateChanged() {
+        // Pulsing: Enable flag and dozing
+        whenever(mNotificationRoundnessManager!!.shouldRoundNotificationPulsing()).thenReturn(true)
+        whenever(mTestHelper!!.statusBarStateController.isDozing).thenReturn(true)
+
+        // Pulsing: Enabled
+        mEntry!!.setHeadsUp(true)
+        mHeadsUpAppearanceController!!.onHeadsUpStateChanged(mEntry!!, true)
+
+        val debugString: String = mRow!!.roundableState.debugString()
+        // If Pulsing is enabled, roundness should be set to 1
+        assertThat(mRow!!.topRoundness.toDouble()).isWithin(0.001).of(1.0)
+        assertThat(debugString).contains("Pulsing")
+
+        // Pulsing: Disabled
+        mEntry!!.setHeadsUp(false)
+        mHeadsUpAppearanceController!!.onHeadsUpStateChanged(mEntry!!, false)
+
+        // If Pulsing is disabled, roundness should be set to 0
+        assertThat(mRow!!.topRoundness.toDouble()).isWithin(0.001).of(0.0)
+    }
+
+    @Test
+    fun onHeadsUpStateChanged_true_transitionsNotified() {
+        mHeadsUpAppearanceController!!.onHeadsUpStateChanged(mEntry!!, true)
+
+        verify(mPhoneStatusBarTransitions!!).onHeadsUpStateChanged(true)
+    }
+
+    @Test
+    fun onHeadsUpStateChanged_false_transitionsNotified() {
+        mHeadsUpAppearanceController!!.onHeadsUpStateChanged(mEntry!!, false)
+
+        verify(mPhoneStatusBarTransitions!!).onHeadsUpStateChanged(false)
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaListenerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaListenerTest.kt
index 110dec6..f76ee5e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaListenerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaListenerTest.kt
@@ -87,7 +87,7 @@
 @RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 @OptIn(ExperimentalCoroutinesApi::class)
-@DisableFlags(FLAG_STATUS_BAR_USE_REPOS_FOR_CALL_CHIP)
+@DisableFlags(FLAG_STATUS_BAR_USE_REPOS_FOR_CALL_CHIP, StatusBarChipsModernization.FLAG_NAME)
 class OngoingCallControllerViaListenerTest : SysuiTestCase() {
     private val kosmos = Kosmos()
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaRepoTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaRepoTest.kt
index 2ad50cc..647b5f8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaRepoTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaRepoTest.kt
@@ -29,6 +29,7 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.Flags.FLAG_STATUS_BAR_CALL_CHIP_NOTIFICATION_ICON
+import com.android.systemui.Flags.FLAG_STATUS_BAR_CHIPS_MODERNIZATION
 import com.android.systemui.Flags.FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS
 import com.android.systemui.Flags.FLAG_STATUS_BAR_USE_REPOS_FOR_CALL_CHIP
 import com.android.systemui.SysuiTestCase
@@ -77,6 +78,7 @@
 @TestableLooper.RunWithLooper
 @OptIn(ExperimentalCoroutinesApi::class)
 @EnableFlags(FLAG_STATUS_BAR_USE_REPOS_FOR_CALL_CHIP)
+@DisableFlags(StatusBarChipsModernization.FLAG_NAME)
 class OngoingCallControllerViaRepoTest : SysuiTestCase() {
     private val kosmos = Kosmos()
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepositoryTest.kt
index 4c6eaa5..a446313 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepositoryTest.kt
@@ -16,10 +16,13 @@
 
 package com.android.systemui.statusbar.phone.ongoingcall.data.repository
 
+import android.platform.test.annotations.DisableFlags
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.systemui.Flags.FLAG_STATUS_BAR_CHIPS_MODERNIZATION
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization
 import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel
 import com.android.systemui.statusbar.phone.ongoingcall.shared.model.inCallModel
 import com.google.common.truth.Truth.assertThat
@@ -28,6 +31,7 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
+@DisableFlags(StatusBarChipsModernization.FLAG_NAME)
 class OngoingCallRepositoryTest : SysuiTestCase() {
     private val kosmos = Kosmos()
     private val underTest = kosmos.ongoingCallRepository
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt
new file mode 100644
index 0000000..ca1413e
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt
@@ -0,0 +1,208 @@
+/*
+ * 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.
+ */
+
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.statusbar.phone.ongoingcall.domain.interactor
+
+import android.app.PendingIntent
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.activity.data.repository.activityManagerRepository
+import com.android.systemui.activity.data.repository.fake
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runTest
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.statusbar.StatusBarIconView
+import com.android.systemui.statusbar.notification.data.model.activeNotificationModel
+import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore
+import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
+import com.android.systemui.statusbar.notification.shared.CallType
+import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class OngoingCallInteractorTest : SysuiTestCase() {
+    private val kosmos = Kosmos().useUnconfinedTestDispatcher()
+    private val repository = kosmos.activeNotificationListRepository
+    private val underTest = kosmos.ongoingCallInteractor
+
+    @Test
+    fun noNotification_emitsNoCall() = runTest {
+        val state by collectLastValue(underTest.ongoingCallState)
+        assertThat(state).isInstanceOf(OngoingCallModel.NoCall::class.java)
+    }
+
+    @Test
+    fun ongoingCallNotification_setsNotificationIconAndIntent() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.ongoingCallState)
+
+            // Set up notification with icon view and intent
+            val testIconView: StatusBarIconView = mock()
+            val testIntent: PendingIntent = mock()
+            repository.activeNotifications.value =
+                ActiveNotificationsStore.Builder()
+                    .apply {
+                        addIndividualNotif(
+                            activeNotificationModel(
+                                key = "notif1",
+                                whenTime = 1000L,
+                                callType = CallType.Ongoing,
+                                statusBarChipIcon = testIconView,
+                                contentIntent = testIntent
+                            )
+                        )
+                    }
+                    .build()
+
+            // Verify model is InCall and has the correct icon and intent.
+            assertThat(latest).isInstanceOf(OngoingCallModel.InCall::class.java)
+            val model = latest as OngoingCallModel.InCall
+            assertThat(model.notificationIconView).isSameInstanceAs(testIconView)
+            assertThat(model.intent).isSameInstanceAs(testIntent)
+        }
+
+    @Test
+    fun ongoingCallNotification_emitsInCall() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.ongoingCallState)
+
+            repository.activeNotifications.value =
+                ActiveNotificationsStore.Builder()
+                    .apply {
+                        addIndividualNotif(
+                            activeNotificationModel(
+                                key = "notif1", whenTime = 1000L, callType = CallType.Ongoing
+                            )
+                        )
+                    }
+                    .build()
+
+            assertThat(latest).isInstanceOf(OngoingCallModel.InCall::class.java)
+        }
+
+    @Test
+    fun notificationRemoved_emitsNoCall() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.ongoingCallState)
+
+            repository.activeNotifications.value =
+                ActiveNotificationsStore.Builder()
+                    .apply {
+                        addIndividualNotif(
+                            activeNotificationModel(
+                                key = "notif1", whenTime = 1000L, callType = CallType.Ongoing
+                            )
+                        )
+                    }
+                    .build()
+
+            repository.activeNotifications.value = ActiveNotificationsStore()
+            assertThat(latest).isInstanceOf(OngoingCallModel.NoCall::class.java)
+        }
+
+    @Test
+    fun ongoingCallNotification_appVisibleInitially_emitsInCallWithVisibleApp() =
+        kosmos.runTest {
+            kosmos.activityManagerRepository.fake.startingIsAppVisibleValue = true
+            val latest by collectLastValue(underTest.ongoingCallState)
+
+            repository.activeNotifications.value =
+                ActiveNotificationsStore.Builder()
+                    .apply {
+                        addIndividualNotif(
+                            activeNotificationModel(
+                                key = "notif1",
+                                whenTime = 1000L,
+                                callType = CallType.Ongoing,
+                                uid = UID
+                            )
+                        )
+                    }
+                    .build()
+
+            assertThat(latest).isInstanceOf(OngoingCallModel.InCallWithVisibleApp::class.java)
+        }
+
+    @Test
+    fun ongoingCallNotification_appNotVisibleInitially_emitsInCall() =
+        kosmos.runTest {
+            kosmos.activityManagerRepository.fake.startingIsAppVisibleValue = false
+            val latest by collectLastValue(underTest.ongoingCallState)
+
+            repository.activeNotifications.value =
+                ActiveNotificationsStore.Builder()
+                    .apply {
+                        addIndividualNotif(
+                            activeNotificationModel(
+                                key = "notif1",
+                                whenTime = 1000L,
+                                callType = CallType.Ongoing,
+                                uid = UID
+                            )
+                        )
+                    }
+                    .build()
+
+            assertThat(latest).isInstanceOf(OngoingCallModel.InCall::class.java)
+        }
+
+    @Test
+    fun ongoingCallNotification_visibilityChanges_updatesState() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.ongoingCallState)
+
+            // Start with notification and app not visible
+            kosmos.activityManagerRepository.fake.startingIsAppVisibleValue = false
+            repository.activeNotifications.value =
+                ActiveNotificationsStore.Builder()
+                    .apply {
+                        addIndividualNotif(
+                            activeNotificationModel(
+                                key = "notif1",
+                                whenTime = 1000L,
+                                callType = CallType.Ongoing,
+                                uid = UID
+                            )
+                        )
+                    }
+                    .build()
+            assertThat(latest)
+                .isInstanceOf(OngoingCallModel.InCall::class.java)
+
+            // App becomes visible
+            kosmos.activityManagerRepository.fake.setIsAppVisible(UID, true)
+            assertThat(latest).isInstanceOf(OngoingCallModel.InCallWithVisibleApp::class.java)
+
+            // App becomes invisible again
+            kosmos.activityManagerRepository.fake.setIsAppVisible(UID, false)
+            assertThat(latest).isInstanceOf(OngoingCallModel.InCall::class.java)
+        }
+
+    companion object {
+        private const val UID = 885
+    }
+}
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 42e9092..113f3d2 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -172,6 +172,9 @@
     <!-- Minimum display time for a heads up notification, in milliseconds. -->
     <integer name="heads_up_notification_minimum_time">2000</integer>
 
+    <!-- Minimum display time for a heads up notification if throttling is enabled, in milliseconds. -->
+    <integer name="heads_up_notification_minimum_time_with_throttling">500</integer>
+
     <!-- Display time for a sticky heads up notification, in milliseconds. -->
     <integer name="sticky_heads_up_notification_time">60000</integer>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index bc81a4b..e417da4 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -3814,6 +3814,9 @@
          shortcut helper The helper is a  component that shows the  user which keyboard shortcuts
          they can use. [CHAR LIMIT=NONE] -->
     <string name="shortcut_helper_customize_button_text">Customize</string>
+    <!-- Description text of the button that allows user to resets all custom shortcuts in keyboard
+         shortcut helper when in customization mode. [CHAR LIMIT=NONE] -->
+    <string name="shortcut_helper_reset_button_text">Reset</string>
     <!-- Description text of the button that allows user to exit shortcut customization mode in
          keyboard shortcut helper The helper is a  component that shows the  user which keyboard
          shortcuts they can use. [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/schemas/com.android.systemui.communal.data.db.CommunalDatabase/5.json b/packages/SystemUI/schemas/com.android.systemui.communal.data.db.CommunalDatabase/5.json
new file mode 100644
index 0000000..c5a83c4
--- /dev/null
+++ b/packages/SystemUI/schemas/com.android.systemui.communal.data.db.CommunalDatabase/5.json
@@ -0,0 +1,95 @@
+{
+  "formatVersion": 1,
+  "database": {
+    "version": 5,
+    "identityHash": "a83f96ef4babe730b3a00e8acb777a25",
+    "entities": [
+      {
+        "tableName": "communal_widget_table",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `widget_id` INTEGER NOT NULL, `component_name` TEXT NOT NULL, `item_id` INTEGER NOT NULL, `user_serial_number` INTEGER NOT NULL DEFAULT -1, `span_y` INTEGER NOT NULL DEFAULT 3, `span_y_new` INTEGER NOT NULL DEFAULT 1)",
+        "fields": [
+          {
+            "fieldPath": "uid",
+            "columnName": "uid",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "widgetId",
+            "columnName": "widget_id",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "componentName",
+            "columnName": "component_name",
+            "affinity": "TEXT",
+            "notNull": true
+          },
+          {
+            "fieldPath": "itemId",
+            "columnName": "item_id",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "userSerialNumber",
+            "columnName": "user_serial_number",
+            "affinity": "INTEGER",
+            "notNull": true,
+            "defaultValue": "-1"
+          },
+          {
+            "fieldPath": "spanY",
+            "columnName": "span_y",
+            "affinity": "INTEGER",
+            "notNull": true,
+            "defaultValue": "3"
+          },
+          {
+            "fieldPath": "spanYNew",
+            "columnName": "span_y_new",
+            "affinity": "INTEGER",
+            "notNull": true,
+            "defaultValue": "1"
+          }
+        ],
+        "primaryKey": {
+          "autoGenerate": true,
+          "columnNames": [
+            "uid"
+          ]
+        }
+      },
+      {
+        "tableName": "communal_item_rank_table",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `rank` INTEGER NOT NULL DEFAULT 0)",
+        "fields": [
+          {
+            "fieldPath": "uid",
+            "columnName": "uid",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "rank",
+            "columnName": "rank",
+            "affinity": "INTEGER",
+            "notNull": true,
+            "defaultValue": "0"
+          }
+        ],
+        "primaryKey": {
+          "autoGenerate": true,
+          "columnNames": [
+            "uid"
+          ]
+        }
+      }
+    ],
+    "setupQueries": [
+      "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'a83f96ef4babe730b3a00e8acb777a25')"
+    ]
+  }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index ab61190..fc536bd 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -25,9 +25,17 @@
 import android.annotation.LongDef;
 import android.content.Context;
 import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.IInterface;
+import android.os.RemoteException;
+import android.util.Log;
 import android.view.ViewConfiguration;
 import android.view.WindowManagerPolicyConstants;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
 import com.android.internal.policy.ScreenDecorationsUtils;
 
 import java.lang.annotation.Retention;
@@ -39,10 +47,7 @@
  */
 public class QuickStepContract {
 
-    public static final String KEY_EXTRA_SYSUI_PROXY = "extra_sysui_proxy";
-    public static final String KEY_EXTRA_UNFOLD_ANIMATION_FORWARDER = "extra_unfold_animation";
-    // See ISysuiUnlockAnimationController.aidl
-    public static final String KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER = "unlock_animation";
+    private static final String TAG = "QuickStepContract";
 
     public static final String NAV_BAR_MODE_3BUTTON_OVERLAY =
             WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY;
@@ -412,4 +417,20 @@
     public static boolean supportsRoundedCornersOnWindows(Resources resources) {
         return ScreenDecorationsUtils.supportsRoundedCornersOnWindows(resources);
     }
+
+    /**
+     * Adds the provided interface to the bundle using the interface descriptor as the key
+     */
+    public static void addInterface(@Nullable IInterface iInterface, @NonNull Bundle out) {
+        if (iInterface != null) {
+            IBinder binder = iInterface.asBinder();
+            if (binder != null) {
+                try {
+                    out.putIBinder(binder.getInterfaceDescriptor(), binder);
+                } catch (RemoteException e) {
+                    Log.d(TAG, "Invalid interface description " + binder, e);
+                }
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index 071cf8a..5af80cb 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -63,6 +63,7 @@
 import com.android.systemui.plugins.clocks.ZenData
 import com.android.systemui.plugins.clocks.ZenData.ZenMode
 import com.android.systemui.res.R as SysuiR
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.shared.regionsampling.RegionSampler
 import com.android.systemui.statusbar.policy.BatteryController
@@ -466,6 +467,15 @@
         batteryController.addCallback(batteryCallback)
         keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
         zenModeController.addCallback(zenModeCallback)
+        if (SceneContainerFlag.isEnabled) {
+            handleDoze(
+                when (AOD) {
+                    keyguardTransitionInteractor.getCurrentState() -> 1f
+                    keyguardTransitionInteractor.getStartedState() -> 1f
+                    else -> 0f
+                }
+            )
+        }
         disposableHandle =
             parent.repeatWhenAttached {
                 repeatOnLifecycle(Lifecycle.State.CREATED) {
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/backup/CommunalBackupUtils.kt b/packages/SystemUI/src/com/android/systemui/communal/data/backup/CommunalBackupUtils.kt
index c3d2683..41ea7b6 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/backup/CommunalBackupUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/backup/CommunalBackupUtils.kt
@@ -29,9 +29,7 @@
 import kotlinx.coroutines.runBlocking
 
 /** Utilities for communal backup and restore. */
-class CommunalBackupUtils(
-    private val context: Context,
-) {
+class CommunalBackupUtils(private val context: Context) {
 
     /**
      * Retrieves a communal hub state protobuf that represents the current state of the communal
@@ -50,6 +48,8 @@
                     widgetId = widget.widgetId
                     componentName = widget.componentName
                     userSerialNumber = widget.userSerialNumber
+                    spanY = widget.spanY
+                    spanYNew = widget.spanYNew
                 }
             )
         }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalDatabase.kt b/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalDatabase.kt
index e72088f..679d071 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalDatabase.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalDatabase.kt
@@ -26,9 +26,11 @@
 import androidx.room.migration.Migration
 import androidx.sqlite.db.SupportSQLiteDatabase
 import com.android.systemui.communal.shared.model.GlanceableHubMultiUserHelperImpl
+import com.android.systemui.communal.shared.model.SpanValue
+import com.android.systemui.communal.shared.model.toResponsive
 import com.android.systemui.res.R
 
-@Database(entities = [CommunalWidgetItem::class, CommunalItemRank::class], version = 4)
+@Database(entities = [CommunalWidgetItem::class, CommunalItemRank::class], version = 5)
 abstract class CommunalDatabase : RoomDatabase() {
     abstract fun communalWidgetDao(): CommunalWidgetDao
 
@@ -59,7 +61,12 @@
                             context.resources.getString(R.string.config_communalDatabase),
                         )
                         .also { builder ->
-                            builder.addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4)
+                            builder.addMigrations(
+                                MIGRATION_1_2,
+                                MIGRATION_2_3,
+                                MIGRATION_3_4,
+                                MIGRATION_4_5,
+                            )
                             builder.fallbackToDestructiveMigration(dropAllTables = true)
                             callback?.let { callback -> builder.addCallback(callback) }
                         }
@@ -123,5 +130,30 @@
                     )
                 }
             }
+
+        /** This migration adds a new spanY column for responsive grid sizing. */
+        @VisibleForTesting
+        val MIGRATION_4_5 =
+            object : Migration(4, 5) {
+                override fun migrate(db: SupportSQLiteDatabase) {
+                    Log.i(TAG, "Migrating from version 4 to 5")
+                    db.execSQL(
+                        "ALTER TABLE communal_widget_table " +
+                            "ADD COLUMN span_y_new INTEGER NOT NULL DEFAULT 1"
+                    )
+                    db.query("SELECT item_id, span_y FROM communal_widget_table").use { cursor ->
+                        while (cursor.moveToNext()) {
+                            val id = cursor.getInt(cursor.getColumnIndex("item_id"))
+                            val spanYFixed =
+                                SpanValue.Fixed(cursor.getInt(cursor.getColumnIndex("span_y")))
+                            val spanYResponsive = spanYFixed.toResponsive()
+                            db.execSQL(
+                                "UPDATE communal_widget_table SET span_y_new = " +
+                                    "${spanYResponsive.value} WHERE item_id = $id"
+                            )
+                        }
+                    }
+                }
+            }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalEntities.kt b/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalEntities.kt
index f9d2a84..6ef4bb8 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalEntities.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalEntities.kt
@@ -45,7 +45,12 @@
      * The vertical span of the widget. Span_Y default value corresponds to
      * CommunalContentSize.HALF.span
      */
-    @ColumnInfo(name = "span_y", defaultValue = "3") val spanY: Int,
+    @Deprecated("Use spanYNew instead")
+    @ColumnInfo(name = "span_y", defaultValue = "3")
+    val spanY: Int,
+
+    /** The vertical span of the widget in grid cell units. */
+    @ColumnInfo(name = "span_y_new", defaultValue = "1") val spanYNew: Int,
 ) {
     companion object {
         /**
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalWidgetDao.kt b/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalWidgetDao.kt
index 3d40aa7..3907a37 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalWidgetDao.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/db/CommunalWidgetDao.kt
@@ -27,7 +27,9 @@
 import androidx.sqlite.db.SupportSQLiteDatabase
 import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.communal.nano.CommunalHubState
-import com.android.systemui.communal.shared.model.CommunalContentSize
+import com.android.systemui.communal.shared.model.SpanValue
+import com.android.systemui.communal.shared.model.toFixed
+import com.android.systemui.communal.shared.model.toResponsive
 import com.android.systemui.communal.widgets.CommunalWidgetHost
 import com.android.systemui.communal.widgets.CommunalWidgetModule.Companion.DEFAULT_WIDGETS
 import com.android.systemui.dagger.SysUISingleton
@@ -101,6 +103,7 @@
                                 componentName = name,
                                 rank = index,
                                 userSerialNumber = userSerialNumber,
+                                spanY = SpanValue.Fixed(3),
                             )
                     }
                 }
@@ -155,15 +158,16 @@
 
     @Query(
         "INSERT INTO communal_widget_table" +
-            "(widget_id, component_name, item_id, user_serial_number, span_y) " +
-            "VALUES(:widgetId, :componentName, :itemId, :userSerialNumber, :spanY)"
+            "(widget_id, component_name, item_id, user_serial_number, span_y, span_y_new) " +
+            "VALUES(:widgetId, :componentName, :itemId, :userSerialNumber, :spanY, :spanYNew)"
     )
     fun insertWidget(
         widgetId: Int,
         componentName: String,
         itemId: Long,
         userSerialNumber: Int,
-        spanY: Int = 3,
+        spanY: Int,
+        spanYNew: Int,
     ): Long
 
     @Query("INSERT INTO communal_item_rank_table(rank) VALUES(:rank)")
@@ -189,10 +193,12 @@
     }
 
     @Transaction
-    fun resizeWidget(appWidgetId: Int, spanY: Int, widgetIdToRankMap: Map<Int, Int>) {
+    fun resizeWidget(appWidgetId: Int, spanY: SpanValue, widgetIdToRankMap: Map<Int, Int>) {
         val widget = getWidgetByIdNow(appWidgetId)
         if (widget != null) {
-            updateWidget(widget.copy(spanY = spanY))
+            updateWidget(
+                widget.copy(spanY = spanY.toFixed().value, spanYNew = spanY.toResponsive().value)
+            )
         }
         updateWidgetOrder(widgetIdToRankMap)
     }
@@ -203,7 +209,7 @@
         provider: ComponentName,
         rank: Int? = null,
         userSerialNumber: Int,
-        spanY: Int = CommunalContentSize.HALF.span,
+        spanY: SpanValue,
     ): Long {
         return addWidget(
             widgetId = widgetId,
@@ -220,7 +226,7 @@
         componentName: String,
         rank: Int? = null,
         userSerialNumber: Int,
-        spanY: Int = 3,
+        spanY: SpanValue,
     ): Long {
         val widgets = getWidgetsNow()
 
@@ -241,7 +247,8 @@
             componentName = componentName,
             itemId = insertItemRank(newRank),
             userSerialNumber = userSerialNumber,
-            spanY = spanY,
+            spanY = spanY.toFixed().value,
+            spanYNew = spanY.toResponsive().value,
         )
     }
 
@@ -264,7 +271,11 @@
         clearCommunalItemRankTable()
 
         state.widgets.forEach {
-            val spanY = if (it.spanY != 0) it.spanY else CommunalContentSize.HALF.span
+            // Check if there is a new value to restore. If so, restore that new value.
+            val spanYResponsive = if (it.spanYNew != 0) SpanValue.Responsive(it.spanYNew) else null
+            // If no new value, restore any existing old values.
+            val spanY = spanYResponsive ?: SpanValue.Fixed(it.spanY.coerceIn(3, 6))
+
             addWidget(it.widgetId, it.componentName, it.rank, it.userSerialNumber, spanY)
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepository.kt
index 29569f8..e44d78b 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalWidgetRepository.kt
@@ -22,6 +22,7 @@
 import android.os.UserHandle
 import android.os.UserManager
 import com.android.app.tracing.coroutines.launchTraced as launch
+import com.android.systemui.Flags.communalResponsiveGrid
 import com.android.systemui.Flags.communalWidgetResizing
 import com.android.systemui.common.data.repository.PackageChangeRepository
 import com.android.systemui.common.shared.model.PackageInstallSession
@@ -33,6 +34,7 @@
 import com.android.systemui.communal.nano.CommunalHubState
 import com.android.systemui.communal.proto.toCommunalHubState
 import com.android.systemui.communal.shared.model.CommunalWidgetContentModel
+import com.android.systemui.communal.shared.model.SpanValue
 import com.android.systemui.communal.widgets.CommunalAppWidgetHost
 import com.android.systemui.communal.widgets.CommunalWidgetHost
 import com.android.systemui.communal.widgets.WidgetConfigurator
@@ -143,15 +145,21 @@
                     componentName = widget.componentName,
                     rank = rank.rank,
                     providerInfo = providers[widget.widgetId],
-                    spanY = widget.spanY,
+                    spanY = if (communalResponsiveGrid()) widget.spanYNew else widget.spanY,
                 )
             }
         }
 
     override fun resizeWidget(appWidgetId: Int, spanY: Int, widgetIdToRankMap: Map<Int, Int>) {
         if (!communalWidgetResizing()) return
+        val spanValue =
+            if (communalResponsiveGrid()) {
+                SpanValue.Responsive(spanY)
+            } else {
+                SpanValue.Fixed(spanY)
+            }
         bgScope.launch {
-            communalWidgetDao.resizeWidget(appWidgetId, spanY, widgetIdToRankMap)
+            communalWidgetDao.resizeWidget(appWidgetId, spanValue, widgetIdToRankMap)
             logger.i({ "Updated spanY of widget $int1 to $int2." }) {
                 int1 = appWidgetId
                 int2 = spanY
@@ -225,7 +233,7 @@
                     provider = provider,
                     rank = rank,
                     userSerialNumber = userManager.getUserSerialNumber(user.identifier),
-                    spanY = 3,
+                    spanY = SpanValue.Fixed(3),
                 )
                 backupManager.dataChanged()
             } else {
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 602fe30..f9b30c6 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
@@ -34,9 +34,9 @@
 import com.android.systemui.communal.domain.model.CommunalContentModel
 import com.android.systemui.communal.domain.model.CommunalContentModel.WidgetContent
 import com.android.systemui.communal.shared.model.CommunalContentSize
-import com.android.systemui.communal.shared.model.CommunalContentSize.FULL
-import com.android.systemui.communal.shared.model.CommunalContentSize.HALF
-import com.android.systemui.communal.shared.model.CommunalContentSize.THIRD
+import com.android.systemui.communal.shared.model.CommunalContentSize.FixedSize.FULL
+import com.android.systemui.communal.shared.model.CommunalContentSize.FixedSize.HALF
+import com.android.systemui.communal.shared.model.CommunalContentSize.FixedSize.THIRD
 import com.android.systemui.communal.shared.model.CommunalScenes
 import com.android.systemui.communal.shared.model.CommunalWidgetContentModel
 import com.android.systemui.communal.shared.model.EditModeState
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt
index 30f580e..da613f5 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt
@@ -22,6 +22,7 @@
 import android.content.pm.ApplicationInfo
 import android.graphics.Bitmap
 import android.widget.RemoteViews
+import com.android.systemui.Flags.communalResponsiveGrid
 import com.android.systemui.communal.shared.model.CommunalContentSize
 import java.util.UUID
 
@@ -35,7 +36,7 @@
 
     /** The minimum size content can be resized to. */
     val minSize: CommunalContentSize
-        get() = CommunalContentSize.HALF
+        get() = fixedHalfOrResponsiveSize()
 
     /**
      * A type of communal content is ongoing / live / ephemeral, and can be sized and ordered
@@ -44,7 +45,12 @@
     sealed interface Ongoing : CommunalContentModel {
         override var size: CommunalContentSize
         override val minSize
-            get() = CommunalContentSize.THIRD
+            get() =
+                if (communalResponsiveGrid()) {
+                    CommunalContentSize.Responsive(1)
+                } else {
+                    CommunalContentSize.FixedSize.THIRD
+                }
 
         /** Timestamp in milliseconds of when the content was created. */
         val createdTimestampMillis: Long
@@ -100,14 +106,16 @@
     class WidgetPlaceholder : CommunalContentModel {
         override val key: String = KEY.widgetPlaceholder()
         // Same as widget size.
-        override val size = CommunalContentSize.HALF
+        override val size: CommunalContentSize
+            get() = fixedHalfOrResponsiveSize()
     }
 
     /** A CTA tile in the glanceable hub view mode which can be dismissed. */
     class CtaTileInViewMode : CommunalContentModel {
         override val key: String = KEY.CTA_TILE_IN_VIEW_MODE_KEY
         // Same as widget size.
-        override val size = CommunalContentSize.HALF
+        override val size: CommunalContentSize
+            get() = fixedHalfOrResponsiveSize()
     }
 
     class Tutorial(id: Int, override var size: CommunalContentSize) : CommunalContentModel {
@@ -118,15 +126,15 @@
         smartspaceTargetId: String,
         val remoteViews: RemoteViews,
         override val createdTimestampMillis: Long,
-        override var size: CommunalContentSize = CommunalContentSize.HALF,
+        override var size: CommunalContentSize = fixedHalfOrResponsiveSize(),
     ) : Ongoing {
         override val key = KEY.smartspace(smartspaceTargetId)
     }
 
     class Umo(
         override val createdTimestampMillis: Long,
-        override var size: CommunalContentSize = CommunalContentSize.HALF,
-        override var minSize: CommunalContentSize = CommunalContentSize.HALF,
+        override var size: CommunalContentSize = fixedHalfOrResponsiveSize(),
+        override var minSize: CommunalContentSize = fixedHalfOrResponsiveSize(),
     ) : Ongoing {
         override val key = KEY.umo()
     }
@@ -170,3 +178,10 @@
 
     fun isLiveContent() = this is Smartspace || this is Umo
 }
+
+private fun fixedHalfOrResponsiveSize() =
+    if (communalResponsiveGrid()) {
+        CommunalContentSize.Responsive(1)
+    } else {
+        CommunalContentSize.FixedSize.HALF
+    }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/proto/communal_hub_state.proto b/packages/SystemUI/src/com/android/systemui/communal/proto/communal_hub_state.proto
index 7602a7a..04717d0 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/proto/communal_hub_state.proto
+++ b/packages/SystemUI/src/com/android/systemui/communal/proto/communal_hub_state.proto
@@ -39,7 +39,10 @@
         // Serial number of the user associated with the widget.
         int32 user_serial_number = 4;
 
-        // The vertical span of the widget
+        // The vertical span of the widget, replaced by span_y_new.
         int32 span_y = 5;
+
+        // The vertical span of the widget.
+        int32 span_y_new = 6;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalContentSize.kt b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalContentSize.kt
index cf80b7d..df30716 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalContentSize.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalContentSize.kt
@@ -16,27 +16,39 @@
 
 package com.android.systemui.communal.shared.model
 
+import com.android.systemui.Flags.communalResponsiveGrid
+
 /**
  * Supported sizes for communal content in the layout grid.
  *
- * @param span The span of the content in a column. For example, if FULL is 6, then 3 represents
- *   HALF, 2 represents THIRD, and 1 represents SIXTH.
+ * @property span The span of the content in a column.
  */
-enum class CommunalContentSize(val span: Int) {
-    /** Content takes the full height of the column. */
-    FULL(6),
+sealed interface CommunalContentSize {
+    val span: Int
 
-    /** Content takes half of the height of the column. */
-    HALF(3),
+    @Deprecated("Use Responsive size instead")
+    enum class FixedSize(override val span: Int) : CommunalContentSize {
+        /** Content takes the full height of the column. */
+        FULL(6),
 
-    /** Content takes a third of the height of the column. */
-    THIRD(2);
+        /** Content takes half of the height of the column. */
+        HALF(3),
+
+        /** Content takes a third of the height of the column. */
+        THIRD(2),
+    }
+
+    @JvmInline value class Responsive(override val span: Int) : CommunalContentSize
 
     companion object {
         /** Converts from span to communal content size. */
         fun toSize(span: Int): CommunalContentSize {
-            return entries.find { it.span == span }
-                ?: throw IllegalArgumentException("$span is not a valid span size")
+            return if (communalResponsiveGrid()) {
+                Responsive(span)
+            } else {
+                FixedSize.entries.find { it.span == span }
+                    ?: throw IllegalArgumentException("$span is not a valid span size")
+            }
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/shared/model/SpanValue.kt b/packages/SystemUI/src/com/android/systemui/communal/shared/model/SpanValue.kt
new file mode 100644
index 0000000..15cc6b0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/communal/shared/model/SpanValue.kt
@@ -0,0 +1,40 @@
+/*
+ * 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.communal.shared.model
+
+/** Models possible span values for different grid formats. */
+sealed interface SpanValue {
+    val value: Int
+
+    @Deprecated("Use Responsive sizes instead")
+    @JvmInline
+    value class Fixed(override val value: Int) : SpanValue
+
+    @JvmInline value class Responsive(override val value: Int) : SpanValue
+}
+
+fun SpanValue.toResponsive(): SpanValue.Responsive =
+    when (this) {
+        is SpanValue.Responsive -> this
+        is SpanValue.Fixed -> SpanValue.Responsive((this.value / 3).coerceAtMost(1))
+    }
+
+fun SpanValue.toFixed(): SpanValue.Fixed =
+    when (this) {
+        is SpanValue.Fixed -> this
+        is SpanValue.Responsive -> SpanValue.Fixed((this.value * 3).coerceIn(3, 6))
+    }
diff --git a/packages/SystemUI/src/com/android/systemui/education/ui/view/ContextualEduUiCoordinator.kt b/packages/SystemUI/src/com/android/systemui/education/ui/view/ContextualEduUiCoordinator.kt
index c49ba80..a36e45f 100644
--- a/packages/SystemUI/src/com/android/systemui/education/ui/view/ContextualEduUiCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/education/ui/view/ContextualEduUiCoordinator.kt
@@ -29,6 +29,11 @@
 import androidx.core.app.NotificationCompat
 import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.CoreStartable
+import com.android.systemui.contextualeducation.GestureType
+import com.android.systemui.contextualeducation.GestureType.ALL_APPS
+import com.android.systemui.contextualeducation.GestureType.BACK
+import com.android.systemui.contextualeducation.GestureType.HOME
+import com.android.systemui.contextualeducation.GestureType.OVERVIEW
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.education.ui.viewmodel.ContextualEduNotificationViewModel
@@ -37,6 +42,10 @@
 import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity
 import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_ENTRY_POINT_CONTEXTUAL_EDU
 import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_ENTRY_POINT_KEY
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_KEY
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_KEYBOARD
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_TOUCHPAD_BACK
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity.Companion.INTENT_TUTORIAL_SCOPE_TOUCHPAD_HOME
 import com.android.systemui.res.R
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
@@ -59,6 +68,8 @@
         private const val CHANNEL_ID = "ContextualEduNotificationChannel"
         private const val TAG = "ContextualEduUiCoordinator"
         private const val NOTIFICATION_ID = 1000
+        private const val TUTORIAL_ACTION: String = "com.android.systemui.action.TOUCHPAD_TUTORIAL"
+        private const val SYSTEMUI_PACKAGE_NAME: String = "com.android.systemui"
     }
 
     @Inject
@@ -125,7 +136,7 @@
                 .setSmallIcon(R.drawable.ic_settings)
                 .setContentTitle(model.title)
                 .setContentText(model.message)
-                .setContentIntent(createPendingIntent())
+                .setContentIntent(createPendingIntent(model.gestureType))
                 .setPriority(NotificationCompat.PRIORITY_DEFAULT)
                 .setAutoCancel(true)
                 .addExtras(extras)
@@ -138,21 +149,37 @@
         )
     }
 
-    private fun createPendingIntent(): PendingIntent {
+    private fun createPendingIntent(gestureType: GestureType): PendingIntent {
         val intent =
-            Intent(context, KeyboardTouchpadTutorialActivity::class.java).apply {
-                addCategory(Intent.CATEGORY_DEFAULT)
-                flags = Intent.FLAG_ACTIVITY_NEW_TASK
-                putExtra(
-                    INTENT_TUTORIAL_ENTRY_POINT_KEY,
-                    INTENT_TUTORIAL_ENTRY_POINT_CONTEXTUAL_EDU,
-                )
+            when (gestureType) {
+                BACK -> createKeyboardTouchpadTutorialIntent(INTENT_TUTORIAL_SCOPE_TOUCHPAD_BACK)
+                HOME -> createKeyboardTouchpadTutorialIntent(INTENT_TUTORIAL_SCOPE_TOUCHPAD_HOME)
+                ALL_APPS -> createKeyboardTouchpadTutorialIntent(INTENT_TUTORIAL_SCOPE_KEYBOARD)
+                OVERVIEW -> createTouchpadTutorialIntent()
             }
+
         return PendingIntent.getActivity(
             context,
             /* requestCode= */ 0,
             intent,
-            PendingIntent.FLAG_IMMUTABLE,
+            // FLAG_UPDATE_CURRENT to avoid caching of intent extras and always use latest values
+            PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT,
         )
     }
+
+    private fun createKeyboardTouchpadTutorialIntent(tutorialType: String): Intent {
+        return Intent(context, KeyboardTouchpadTutorialActivity::class.java).apply {
+            addCategory(Intent.CATEGORY_DEFAULT)
+            flags = Intent.FLAG_ACTIVITY_NEW_TASK
+            putExtra(INTENT_TUTORIAL_SCOPE_KEY, tutorialType)
+            putExtra(INTENT_TUTORIAL_ENTRY_POINT_KEY, INTENT_TUTORIAL_ENTRY_POINT_CONTEXTUAL_EDU)
+        }
+    }
+
+    private fun createTouchpadTutorialIntent(): Intent {
+        return Intent(TUTORIAL_ACTION).apply {
+            flags = Intent.FLAG_ACTIVITY_NEW_TASK
+            setPackage(SYSTEMUI_PACKAGE_NAME)
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduContentViewModel.kt b/packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduContentViewModel.kt
index 5a02cda..06c0d6c 100644
--- a/packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduContentViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduContentViewModel.kt
@@ -16,11 +16,14 @@
 
 package com.android.systemui.education.ui.viewmodel
 
+import com.android.systemui.contextualeducation.GestureType
+
 sealed class ContextualEduContentViewModel(open val userId: Int)
 
 data class ContextualEduNotificationViewModel(
     val title: String,
     val message: String,
+    val gestureType: GestureType,
     override val userId: Int,
 ) : ContextualEduContentViewModel(userId)
 
diff --git a/packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduViewModel.kt b/packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduViewModel.kt
index 7417a70..443ad020 100644
--- a/packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/education/ui/viewmodel/ContextualEduViewModel.kt
@@ -68,6 +68,7 @@
                     ContextualEduNotificationViewModel(
                         getEduTitle(it),
                         getEduContent(it),
+                        it.gestureType,
                         it.userId,
                     )
                 } else {
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/SystemShortcutsSource.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/SystemShortcutsSource.kt
index 687ad95..5060abd 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/SystemShortcutsSource.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/SystemShortcutsSource.kt
@@ -54,7 +54,7 @@
         listOf(
             KeyboardShortcutGroup(
                 resources.getString(R.string.shortcut_helper_category_system_controls),
-                hardwareShortcuts(deviceId) + systemControlsShortcuts(),
+                systemControlsShortcuts() + hardwareShortcuts(deviceId),
             ),
             KeyboardShortcutGroup(
                 resources.getString(R.string.shortcut_helper_category_system_apps),
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt
index 2385cc6..d625846 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt
@@ -95,7 +95,7 @@
                 Shortcut(
                     label = commonLabel,
                     icon = groupedShortcuts.firstOrNull()?.icon,
-                    commands = groupedShortcuts.flatMap { it.commands },
+                    commands = groupedShortcuts.flatMap { it.commands }.sortedBy { it.keys.size },
                     contentDescription =
                         toContentDescription(commonLabel, groupedShortcuts.flatMap { it.commands }),
                 )
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutSubCategory.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutSubCategory.kt
index 1401678..37433ca 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutSubCategory.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/shared/model/ShortcutSubCategory.kt
@@ -16,7 +16,9 @@
 
 package com.android.systemui.keyboard.shortcut.shared.model
 
-data class ShortcutSubCategory(val label: String, val shortcuts: List<Shortcut>)
+data class ShortcutSubCategory(val label: String, val shortcuts: List<Shortcut>) {
+    val containsCustomShortcuts: Boolean = shortcuts.any { it.containsCustomShortcutCommands }
+}
 
 class ShortcutSubCategoryBuilder(val label: String) {
     private val shortcuts = mutableListOf<Shortcut>()
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt
index bd0430b..274fa59 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt
@@ -53,15 +53,18 @@
 
     override suspend fun onActivated(): Nothing {
         viewModel.shortcutCustomizationUiState.collect { uiState ->
-            val shouldShowAddDialog = uiState is AddShortcutDialog && !uiState.isDialogShowing
-            val shouldShowDeleteDialog = uiState is DeleteShortcutDialog && !uiState.isDialogShowing
-            val shouldShowResetDialog = uiState is ResetShortcutDialog && !uiState.isDialogShowing
-            if (shouldShowDeleteDialog || shouldShowAddDialog || shouldShowResetDialog) {
-                dialog = createDialog().also { it.show() }
-                viewModel.onDialogShown()
-            } else if (uiState is ShortcutCustomizationUiState.Inactive) {
-                dialog?.dismiss()
-                dialog = null
+            when(uiState){
+                is AddShortcutDialog,
+                is DeleteShortcutDialog,
+                is ResetShortcutDialog -> {
+                    if (dialog == null){
+                        dialog = createDialog().also { it.show() }
+                    }
+                }
+                is ShortcutCustomizationUiState.Inactive -> {
+                    dialog?.dismiss()
+                    dialog = null
+                }
             }
         }
         awaitCancellation()
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
index 7929307..2fdcf87 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt
@@ -19,6 +19,7 @@
 import android.graphics.drawable.Icon
 import androidx.compose.animation.AnimatedVisibility
 import androidx.compose.animation.core.animateFloatAsState
+import androidx.compose.foundation.BorderStroke
 import androidx.compose.foundation.Image
 import androidx.compose.foundation.background
 import androidx.compose.foundation.border
@@ -56,6 +57,7 @@
 import androidx.compose.material.icons.filled.Add
 import androidx.compose.material.icons.filled.DeleteOutline
 import androidx.compose.material.icons.filled.ExpandMore
+import androidx.compose.material.icons.filled.Refresh
 import androidx.compose.material.icons.filled.Search
 import androidx.compose.material.icons.filled.Tune
 import androidx.compose.material3.CenterAlignedTopAppBar
@@ -113,7 +115,6 @@
 import androidx.compose.ui.util.fastForEachIndexed
 import com.android.compose.modifiers.thenIf
 import com.android.compose.ui.graphics.painter.rememberDrawablePainter
-import com.android.systemui.keyboard.shortcut.shared.model.Shortcut as ShortcutModel
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCommand
 import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCustomizationRequestInfo
@@ -125,6 +126,7 @@
 import com.android.systemui.keyboard.shortcut.ui.model.ShortcutsUiState
 import com.android.systemui.res.R
 import kotlinx.coroutines.delay
+import com.android.systemui.keyboard.shortcut.shared.model.Shortcut as ShortcutModel
 
 @Composable
 fun ShortcutHelper(
@@ -187,6 +189,7 @@
             onKeyboardSettingsClicked,
             shortcutsUiState.isShortcutCustomizerFlagEnabled,
             onCustomizationRequested,
+            shortcutsUiState.shouldShowResetButton
         )
     }
 }
@@ -377,6 +380,7 @@
     onKeyboardSettingsClicked: () -> Unit,
     isShortcutCustomizerFlagEnabled: Boolean,
     onCustomizationRequested: (ShortcutCustomizationRequestInfo) -> Unit = {},
+    shouldShowResetButton: Boolean
 ) {
     val selectedCategory = categories.fastFirstOrNull { it.type == selectedCategoryType }
     var isCustomizing by remember { mutableStateOf(false) }
@@ -389,11 +393,14 @@
                     TitleBar(isCustomizing)
                 }
                 if (isShortcutCustomizerFlagEnabled) {
-                    if (isCustomizing) {
-                        DoneButton(onClick = { isCustomizing = false })
-                    } else {
-                        CustomizeButton(onClick = { isCustomizing = true })
-                    }
+                    CustomizationButtonsContainer(
+                        isCustomizing = isCustomizing,
+                        onToggleCustomizationMode = { isCustomizing = !isCustomizing },
+                        onReset = {
+                            onCustomizationRequested(ShortcutCustomizationRequestInfo.Reset)
+                        },
+                        shouldShowResetButton = shouldShowResetButton,
+                    )
                 } else {
                     Spacer(modifier = Modifier.width(if (isCustomizing) 69.dp else 133.dp))
                 }
@@ -422,6 +429,38 @@
 }
 
 @Composable
+private fun CustomizationButtonsContainer(
+    isCustomizing: Boolean,
+    shouldShowResetButton: Boolean,
+    onToggleCustomizationMode: () -> Unit,
+    onReset: () -> Unit,
+) {
+    Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
+        if (isCustomizing) {
+            if (shouldShowResetButton) {
+                ResetButton(onClick = onReset)
+            }
+            DoneButton(onClick = onToggleCustomizationMode)
+        } else {
+            CustomizeButton(onClick = onToggleCustomizationMode)
+        }
+    }
+}
+
+@Composable
+private fun ResetButton(onClick: () -> Unit) {
+    ShortcutHelperButton(
+        onClick = onClick,
+        color = Color.Transparent,
+        width = 99.dp,
+        iconSource = IconSource(imageVector = Icons.Default.Refresh),
+        text = stringResource(id = R.string.shortcut_helper_reset_button_text),
+        contentColor = MaterialTheme.colorScheme.primary,
+        border = BorderStroke(color = MaterialTheme.colorScheme.outlineVariant, width = 1.dp),
+    )
+}
+
+@Composable
 private fun CustomizeButton(onClick: () -> Unit) {
     ShortcutHelperButton(
         onClick = onClick,
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt
index 58ce194..55c0fe2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt
@@ -228,74 +228,8 @@
     contentColor: Color,
     contentPaddingHorizontal: Dp = 16.dp,
     contentPaddingVertical: Dp = 10.dp,
-) {
-    ClickableShortcutSurface(
-        onClick = onClick,
-        shape = shape,
-        color = color,
-        modifier = modifier.semantics { role = Role.Button }.width(width).height(height),
-        interactionsConfig =
-            InteractionsConfig(
-                hoverOverlayColor = MaterialTheme.colorScheme.onSurface,
-                hoverOverlayAlpha = 0.11f,
-                pressedOverlayColor = MaterialTheme.colorScheme.onSurface,
-                pressedOverlayAlpha = 0.15f,
-                focusOutlineColor = MaterialTheme.colorScheme.secondary,
-                focusOutlineStrokeWidth = 3.dp,
-                focusOutlinePadding = 2.dp,
-                surfaceCornerRadius = 28.dp,
-                focusOutlineCornerRadius = 33.dp,
-            ),
-    ) {
-        Row(
-            modifier =
-                Modifier.padding(
-                    horizontal = contentPaddingHorizontal,
-                    vertical = contentPaddingVertical,
-                ),
-            verticalAlignment = Alignment.CenterVertically,
-            horizontalArrangement = Arrangement.Center,
-        ) {
-            if (iconSource.imageVector != null) {
-                Icon(
-                    tint = contentColor,
-                    imageVector = iconSource.imageVector,
-                    contentDescription = null,
-                    modifier = Modifier.size(20.dp).wrapContentSize(Alignment.Center),
-                )
-            }
-
-            if (iconSource.imageVector != null && text != null) {
-                Spacer(modifier = Modifier.weight(1f))
-            }
-
-            if (text != null) {
-                Text(
-                    text,
-                    color = contentColor,
-                    fontSize = 14.sp,
-                    style = MaterialTheme.typography.labelLarge,
-                    modifier = Modifier.wrapContentSize(Alignment.Center),
-                )
-            }
-        }
-    }
-}
-
-@Composable
-fun ShortcutHelperButton(
-    modifier: Modifier = Modifier,
-    onClick: () -> Unit,
-    shape: Shape = RoundedCornerShape(360.dp),
-    color: Color,
-    width: Dp,
-    height: Dp = 40.dp,
-    iconSource: IconSource = IconSource(),
-    text: String? = null,
-    contentColor: Color,
-    contentPaddingHorizontal: Dp = 16.dp,
-    contentPaddingVertical: Dp = 10.dp,
     enabled: Boolean = true,
+    border: BorderStroke? = null,
 ) {
     ShortcutHelperButtonSurface(
         onClick = onClick,
@@ -305,6 +239,7 @@
         enabled = enabled,
         width = width,
         height = height,
+        border = border,
     ) {
         Row(
             modifier =
@@ -342,7 +277,7 @@
 }
 
 @Composable
-fun ShortcutHelperButtonSurface(
+private fun ShortcutHelperButtonSurface(
     onClick: () -> Unit,
     shape: Shape,
     color: Color,
@@ -350,6 +285,7 @@
     enabled: Boolean,
     width: Dp,
     height: Dp,
+    border: BorderStroke?,
     content: @Composable () -> Unit,
 ) {
     if (enabled) {
@@ -357,6 +293,7 @@
             onClick = onClick,
             shape = shape,
             color = color,
+            border = border,
             modifier = modifier.semantics { role = Role.Button }.width(width).height(height),
             interactionsConfig =
                 InteractionsConfig(
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCategoryUi.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCategoryUi.kt
index f5d478b..2728772 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCategoryUi.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCategoryUi.kt
@@ -31,4 +31,6 @@
         iconSource: IconSource,
         shortcutCategory: ShortcutCategory,
     ) : this(label, iconSource, shortcutCategory.type, shortcutCategory.subCategories)
+
+    val containsCustomShortcuts: Boolean = subCategories.any { it.containsCustomShortcuts }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt
index bfc9486..36c5ae0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt
@@ -23,17 +23,12 @@
         val shortcutLabel: String,
         val errorMessage: String = "",
         val defaultCustomShortcutModifierKey: ShortcutKey.Icon.ResIdIcon,
-        val isDialogShowing: Boolean = false,
         val pressedKeys: List<ShortcutKey> = emptyList(),
     ) : ShortcutCustomizationUiState
 
-    data class DeleteShortcutDialog(
-        val isDialogShowing: Boolean = false
-    ) : ShortcutCustomizationUiState
+    data object DeleteShortcutDialog : ShortcutCustomizationUiState
 
-    data class ResetShortcutDialog(
-        val isDialogShowing: Boolean = false
-    ) : ShortcutCustomizationUiState
+    data object ResetShortcutDialog : ShortcutCustomizationUiState
 
     data object Inactive : ShortcutCustomizationUiState
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutsUiState.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutsUiState.kt
index 02b0b43..52ab157 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutsUiState.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutsUiState.kt
@@ -25,6 +25,7 @@
         val shortcutCategories: List<ShortcutCategoryUi>,
         val defaultSelectedCategory: ShortcutCategoryType?,
         val isShortcutCustomizerFlagEnabled: Boolean = false,
+        val shouldShowResetButton: Boolean = false,
     ) : ShortcutsUiState
 
     data object Inactive : ShortcutsUiState
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt
index 76a2e60..92e2592 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt
@@ -73,32 +73,22 @@
                         shortcutLabel = requestInfo.label,
                         defaultCustomShortcutModifierKey =
                             shortcutCustomizationInteractor.getDefaultCustomShortcutModifierKey(),
-                        isDialogShowing = false,
                         pressedKeys = emptyList(),
                     )
                 shortcutCustomizationInteractor.onCustomizationRequested(requestInfo)
             }
 
             is ShortcutCustomizationRequestInfo.Delete -> {
-                _shortcutCustomizationUiState.value = DeleteShortcutDialog(isDialogShowing = false)
+                _shortcutCustomizationUiState.value = DeleteShortcutDialog
                 shortcutCustomizationInteractor.onCustomizationRequested(requestInfo)
             }
 
             ShortcutCustomizationRequestInfo.Reset -> {
-                _shortcutCustomizationUiState.value = ResetShortcutDialog(isDialogShowing = false)
+                _shortcutCustomizationUiState.value = ResetShortcutDialog
             }
         }
     }
 
-    fun onDialogShown() {
-        _shortcutCustomizationUiState.update { uiState ->
-            (uiState as? AddShortcutDialog)?.copy(isDialogShowing = true)
-                ?: (uiState as? DeleteShortcutDialog)?.copy(isDialogShowing = true)
-                ?: (uiState as? ResetShortcutDialog)?.copy(isDialogShowing = true)
-                ?: uiState
-        }
-    }
-
     fun onDialogDismissed() {
         _shortcutCustomizationUiState.value = ShortcutCustomizationUiState.Inactive
         shortcutCustomizationInteractor.onCustomizationRequested(null)
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt
index 08fd0af8..0f5f073 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutHelperViewModel.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.keyboard.shortcut.ui.viewmodel
 
 import android.app.role.RoleManager
+import android.content.Context
 import android.content.pm.PackageManager.NameNotFoundException
 import android.util.Log
 import androidx.compose.material.icons.Icons
@@ -40,7 +41,6 @@
 import com.android.systemui.keyboard.shortcut.ui.model.ShortcutsUiState
 import com.android.systemui.res.R
 import com.android.systemui.settings.UserTracker
-import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.MutableStateFlow
@@ -51,10 +51,12 @@
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.stateIn
 import kotlinx.coroutines.withContext
+import javax.inject.Inject
 
 class ShortcutHelperViewModel
 @Inject
 constructor(
+    private val context: Context,
     private val roleManager: RoleManager,
     private val userTracker: UserTracker,
     @Background private val backgroundScope: CoroutineScope,
@@ -88,6 +90,7 @@
                         shortcutCategories = shortcutCategoriesUi,
                         defaultSelectedCategory = getDefaultSelectedCategory(filteredCategories),
                         isShortcutCustomizerFlagEnabled = keyboardShortcutHelperShortcutCustomizer(),
+                        shouldShowResetButton = shouldShowResetButton(shortcutCategoriesUi)
                     )
                 }
             }
@@ -97,6 +100,10 @@
                 initialValue = ShortcutsUiState.Inactive,
             )
 
+    private fun shouldShowResetButton(categoriesUi: List<ShortcutCategoryUi>): Boolean {
+        return categoriesUi.any { it.containsCustomShortcuts }
+    }
+
     private fun convertCategoriesModelToUiModel(
         categories: List<ShortcutCategory>
     ): List<ShortcutCategoryUi> {
@@ -136,13 +143,13 @@
     private fun getShortcutCategoryLabel(type: ShortcutCategoryType): String =
         when (type) {
             ShortcutCategoryType.System ->
-                userContext.getString(R.string.shortcut_helper_category_system)
+                context.getString(R.string.shortcut_helper_category_system)
             ShortcutCategoryType.MultiTasking ->
-                userContext.getString(R.string.shortcut_helper_category_multitasking)
+                context.getString(R.string.shortcut_helper_category_multitasking)
             ShortcutCategoryType.InputMethodEditor ->
-                userContext.getString(R.string.shortcut_helper_category_input)
+                context.getString(R.string.shortcut_helper_category_input)
             ShortcutCategoryType.AppCategories ->
-                userContext.getString(R.string.shortcut_helper_category_app_shortcuts)
+                context.getString(R.string.shortcut_helper_category_app_shortcuts)
             is CurrentApp -> getApplicationLabelForCurrentApp(type)
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractor.kt
index 2d7da38..0a4022a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractor.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.keyguard.domain.interactor
 
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.internal.policy.IKeyguardDismissCallback
 import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
@@ -39,7 +40,6 @@
 import kotlinx.coroutines.flow.filter
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.merge
-import com.android.app.tracing.coroutines.launchTraced as launch
 import kotlinx.coroutines.withContext
 
 /** Encapsulates business logic for requesting the keyguard to dismiss/finish/done. */
@@ -53,8 +53,8 @@
     private val primaryBouncerInteractor: PrimaryBouncerInteractor,
     private val selectedUserInteractor: SelectedUserInteractor,
     private val dismissCallbackRegistry: DismissCallbackRegistry,
+    private val alternateBouncerInteractor: AlternateBouncerInteractor,
     trustRepository: TrustRepository,
-    alternateBouncerInteractor: AlternateBouncerInteractor,
     powerInteractor: PowerInteractor,
 ) {
     /*
@@ -151,13 +151,16 @@
                     dismissCallbackRegistry.addCallback(callback)
                 }
 
-                // This will either show the bouncer, or dismiss the keyguard if insecure.
-                // We currently need to request showing the primary bouncer in order to start a
-                // transition to PRIMARY_BOUNCER. Once we refactor that so that starting the
-                // transition is what causes the bouncer to show, we can remove this entire method,
-                // and simply ask KeyguardTransitionInteractor to transition to a bouncer state or
-                // dismiss keyguard.
-                primaryBouncerInteractor.show(true)
+                // This will either show the bouncer, or dismiss the keyguard if insecure. We
+                // currently need to request showing the bouncer in order to start a transition to
+                // *_BOUNCER. Once we refactor that so that starting the transition is what causes
+                // the bouncer to show, we can remove this entire method, and simply call
+                // KeyguardDismissTransitionInteractor#startDismissKeyguardTransition.
+                if (alternateBouncerInteractor.canShowAlternateBouncer.value) {
+                    alternateBouncerInteractor.forceShow()
+                } else {
+                    primaryBouncerInteractor.show(true)
+                }
             }
         }
     }
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 32de56f..6f5d262 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseMediaProjectionPermissionDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseMediaProjectionPermissionDialogDelegate.kt
@@ -50,22 +50,14 @@
     @ScreenShareMode val defaultSelectedMode: Int = screenShareOptions.first().mode,
 ) : DialogDelegate<T>, AdapterView.OnItemSelectedListener {
     private lateinit var dialogTitle: TextView
-    private lateinit var startButton: TextView
     private lateinit var cancelButton: TextView
-    private lateinit var warning: TextView
     private lateinit var screenShareModeSpinner: Spinner
     protected lateinit var dialog: AlertDialog
-    private var shouldLogCancel: Boolean = true
-    var selectedScreenShareOption: ScreenShareOption =
-        screenShareOptions.first { it.mode == defaultSelectedMode }
+    private lateinit var viewBinder: BaseMediaProjectionPermissionViewBinder
 
     @CallSuper
     override fun onStop(dialog: T) {
-        // onStop can be called multiple times and we only want to log once.
-        if (shouldLogCancel) {
-            mediaProjectionMetricsLogger.notifyProjectionRequestCancelled(hostUid)
-            shouldLogCancel = false
-        }
+        viewBinder.unbind()
     }
 
     @CallSuper
@@ -75,12 +67,22 @@
         dialog.window?.setGravity(Gravity.CENTER)
         dialog.setContentView(R.layout.screen_share_dialog)
         dialogTitle = dialog.requireViewById(R.id.screen_share_dialog_title)
-        warning = dialog.requireViewById(R.id.text_warning)
-        startButton = dialog.requireViewById(android.R.id.button1)
         cancelButton = dialog.requireViewById(android.R.id.button2)
         updateIcon()
-        initScreenShareOptions()
         createOptionsView(getOptionsViewLayoutId())
+        if (!::viewBinder.isInitialized) {
+            viewBinder =
+                BaseMediaProjectionPermissionViewBinder(
+                    screenShareOptions,
+                    appName,
+                    hostUid,
+                    mediaProjectionMetricsLogger,
+                    defaultSelectedMode,
+                    dialog,
+                )
+        }
+        viewBinder.bind()
+        initScreenShareSpinner()
     }
 
     private fun updateIcon() {
@@ -93,18 +95,6 @@
         }
     }
 
-    private fun initScreenShareOptions() {
-        selectedScreenShareOption = screenShareOptions.first { it.mode == defaultSelectedMode }
-        setOptionSpecificFields()
-        initScreenShareSpinner()
-    }
-
-    private val warningText: String
-        get() = dialog.context.getString(selectedScreenShareOption.warningText, appName)
-
-    private val startButtonText: String
-        get() = dialog.context.getString(selectedScreenShareOption.startButtonText)
-
     private fun initScreenShareSpinner() {
         val adapter = OptionsAdapter(dialog.context.applicationContext, screenShareOptions)
         screenShareModeSpinner = dialog.requireViewById(R.id.screen_share_mode_options)
@@ -128,18 +118,15 @@
     }
 
     override fun onItemSelected(adapterView: AdapterView<*>?, view: View, pos: Int, id: Long) {
-        selectedScreenShareOption = screenShareOptions[pos]
-        setOptionSpecificFields()
-    }
-
-    /** Sets fields on the dialog that change based on which option is selected. */
-    private fun setOptionSpecificFields() {
-        warning.text = warningText
-        startButton.text = startButtonText
+        viewBinder.onItemSelected(pos)
     }
 
     override fun onNothingSelected(parent: AdapterView<*>?) {}
 
+    fun getSelectedScreenShareOption(): ScreenShareOption {
+        return viewBinder.selectedScreenShareOption
+    }
+
     /** Protected methods for the text updates & functionality */
     protected fun setDialogTitle(@StringRes stringId: Int) {
         val title = dialog.context.getString(stringId, appName)
@@ -147,10 +134,7 @@
     }
 
     protected fun setStartButtonOnClickListener(listener: View.OnClickListener?) {
-        startButton.setOnClickListener { view ->
-            shouldLogCancel = false
-            listener?.onClick(view)
-        }
+        viewBinder.setStartButtonOnClickListener(listener)
     }
 
     protected fun setCancelButtonOnClickListener(listener: View.OnClickListener?) {
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseMediaProjectionPermissionViewBinder.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseMediaProjectionPermissionViewBinder.kt
new file mode 100644
index 0000000..70b25f5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/BaseMediaProjectionPermissionViewBinder.kt
@@ -0,0 +1,81 @@
+/*
+ * 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.mediaprojection.permission
+
+import android.app.AlertDialog
+import android.view.View
+import android.widget.TextView
+import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger
+import com.android.systemui.res.R
+
+open class BaseMediaProjectionPermissionViewBinder(
+    private val screenShareOptions: List<ScreenShareOption>,
+    private val appName: String?,
+    private val hostUid: Int,
+    private val mediaProjectionMetricsLogger: MediaProjectionMetricsLogger,
+    @ScreenShareMode val defaultSelectedMode: Int = screenShareOptions.first().mode,
+    private val dialog: AlertDialog,
+) {
+    private lateinit var warning: TextView
+    private lateinit var startButton: TextView
+    var selectedScreenShareOption: ScreenShareOption =
+        screenShareOptions.first { it.mode == defaultSelectedMode }
+    private var shouldLogCancel: Boolean = true
+
+    fun unbind() {
+        // unbind can be called multiple times and we only want to log once.
+        if (shouldLogCancel) {
+            mediaProjectionMetricsLogger.notifyProjectionRequestCancelled(hostUid)
+            shouldLogCancel = false
+        }
+    }
+
+    open fun bind() {
+        warning = dialog.requireViewById(R.id.text_warning)
+        startButton = dialog.requireViewById(android.R.id.button1)
+        initScreenShareOptions()
+    }
+
+    private fun initScreenShareOptions() {
+        selectedScreenShareOption = screenShareOptions.first { it.mode == defaultSelectedMode }
+        setOptionSpecificFields()
+    }
+
+    /** Sets fields on the dialog that change based on which option is selected. */
+    private fun setOptionSpecificFields() {
+        warning.text = warningText
+        startButton.text = startButtonText
+    }
+
+    fun onItemSelected(pos: Int) {
+        selectedScreenShareOption = screenShareOptions[pos]
+        setOptionSpecificFields()
+    }
+
+    private val warningText: String
+        get() = dialog.context.getString(selectedScreenShareOption.warningText, appName)
+
+    private val startButtonText: String
+        get() = dialog.context.getString(selectedScreenShareOption.startButtonText)
+
+    fun setStartButtonOnClickListener(listener: View.OnClickListener?) {
+        startButton.setOnClickListener { view ->
+            shouldLogCancel = false
+            listener?.onClick(view)
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QuickQuickSettingsRowRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QuickQuickSettingsRowRepository.kt
index 1def7b3..636f703 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QuickQuickSettingsRowRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/QuickQuickSettingsRowRepository.kt
@@ -19,7 +19,6 @@
 import android.content.res.Resources
 import com.android.systemui.common.ui.data.repository.ConfigurationRepository
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.res.R
 import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.util.kotlin.emitOnStart
@@ -30,7 +29,7 @@
 class QuickQuickSettingsRowRepository
 @Inject
 constructor(
-    @Main private val resources: Resources,
+    @ShadeDisplayAware private val resources: Resources,
     @ShadeDisplayAware configurationRepository: ConfigurationRepository,
 ) {
     val rows =
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt
index 75debb6..9efdd98 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt
@@ -9,6 +9,7 @@
 import android.service.quicksettings.Tile
 import android.text.TextUtils
 import android.text.format.DateFormat
+import android.widget.Button
 import androidx.annotation.VisibleForTesting
 import com.android.internal.jank.InteractionJankMonitor
 import com.android.internal.logging.MetricsLogger
@@ -70,7 +71,10 @@
     }
 
     override fun newTileState(): QSTile.State {
-        return QSTile.State().apply { handlesLongClick = false }
+        return QSTile.State().apply {
+            handlesLongClick = false
+            expandedAccessibilityClassName = Button::class.java.name
+        }
     }
 
     override fun handleClick(expandable: Expandable?) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
index 404ace1..7213f7a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
@@ -21,6 +21,7 @@
 import android.os.Handler
 import android.os.Looper
 import android.service.quicksettings.Tile
+import android.widget.Button
 import com.android.internal.jank.InteractionJankMonitor
 import com.android.internal.logging.MetricsLogger
 import com.android.systemui.animation.Expandable
@@ -163,6 +164,7 @@
         } else {
             state.state = Tile.STATE_UNAVAILABLE
         }
+        state.expandedAccessibilityClassName = Button::class.java.name
     }
 
     override fun getMetricsCategory(): Int {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java
index 374bcda..e37ed16 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java
@@ -32,6 +32,7 @@
 import android.service.quicksettings.Tile;
 import android.text.TextUtils;
 import android.util.Log;
+import android.widget.Switch;
 
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
@@ -176,6 +177,7 @@
         } else {
             state.state = isDreaming() ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
         }
+        state.expandedAccessibilityClassName = Switch.class.getName();
     }
 
     @Nullable
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 48b39dc..74563ff 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HearingDevicesTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HearingDevicesTile.java
@@ -24,6 +24,7 @@
 import android.os.UserManager;
 import android.provider.Settings;
 import android.service.quicksettings.Tile;
+import android.widget.Button;
 
 import androidx.annotation.Nullable;
 
@@ -124,6 +125,7 @@
             state.state = Tile.STATE_INACTIVE;
             state.secondaryLabel = "";
         }
+        state.expandedAccessibilityClassName = Button.class.getName();
     }
 
     @Nullable
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
index e9c5f4a..0a59529 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
@@ -30,7 +30,7 @@
 import android.text.Html;
 import android.text.TextUtils;
 import android.util.Log;
-import android.widget.Switch;
+import android.widget.Button;
 
 import androidx.annotation.Nullable;
 
@@ -136,7 +136,7 @@
     }
 
     @Override
-    public void secondaryClick(@Nullable Expandable expandable) {
+    public void handleSecondaryClick(@Nullable Expandable expandable) {
         // TODO(b/358352265): Figure out the correct action for the secondary click
         // Toggle Wifi
         mWifiStateWorker.setWifiEnabled(!mWifiStateWorker.isWifiEnabled());
@@ -577,7 +577,7 @@
         state.contentDescription = minimalContentDescription.toString();
         state.dualLabelContentDescription = r.getString(
                 R.string.accessibility_quick_settings_open_settings, getTileLabel());
-        state.expandedAccessibilityClassName = Switch.class.getName();
+        state.expandedAccessibilityClassName = Button.class.getName();
         if (DEBUG) {
             Log.d(TAG, "handleUpdateWifiState: " + "BooleanState = " + state.toString());
         }
@@ -594,7 +594,7 @@
         boolean mobileDataEnabled = mDataController.isMobileDataSupported()
                 && mDataController.isMobileDataEnabled();
         state.value = mobileDataEnabled;
-        state.expandedAccessibilityClassName = Switch.class.getName();
+        state.expandedAccessibilityClassName = Button.class.getName();
 
         if (cb.mAirplaneModeEnabled && cb.mQsTypeIcon != TelephonyIcons.ICON_CWF) {
             state.state = Tile.STATE_INACTIVE;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt
index 7225800..6d3e5d0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTileNewImpl.kt
@@ -20,7 +20,7 @@
 import android.os.Handler
 import android.os.Looper
 import android.provider.Settings
-import android.widget.Switch
+import android.widget.Button
 import com.android.internal.logging.MetricsLogger
 import com.android.systemui.animation.Expandable
 import com.android.systemui.dagger.qualifiers.Background
@@ -71,7 +71,7 @@
         metricsLogger,
         statusBarStateController,
         activityStarter,
-        qsLogger
+        qsLogger,
     ) {
     private var model: InternetTileModel = viewModel.tileModel.value
 
@@ -110,7 +110,7 @@
         return InternetDetailsViewModel { longClick(null) }
     }
 
-    override fun secondaryClick(expandable: Expandable?) {
+    override fun handleSecondaryClick(expandable: Expandable?) {
         // TODO(b/358352265): Figure out the correct action for the secondary click
         // Toggle wifi
         wifiStateWorker.isWifiEnabled = !wifiStateWorker.isWifiEnabled
@@ -118,7 +118,7 @@
 
     override fun handleUpdateState(state: QSTile.BooleanState, arg: Any?) {
         state.label = mContext.resources.getString(R.string.quick_settings_internet_label)
-        state.expandedAccessibilityClassName = Switch::class.java.name
+        state.expandedAccessibilityClassName = Button::class.java.name
 
         model.applyTo(state, mContext)
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java
index 93a51cf..467233d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java
@@ -21,6 +21,7 @@
 import android.os.Looper;
 import android.service.quicksettings.Tile;
 import android.util.Log;
+import android.widget.Button;
 
 import androidx.annotation.Nullable;
 
@@ -126,6 +127,7 @@
         // would go to "Unavailable" state only when GMS core is updating.
         state.secondaryLabel = state.state == Tile.STATE_UNAVAILABLE
                 ? mContext.getString(R.string.qr_code_scanner_updating_secondary_label) : null;
+        state.expandedAccessibilityClassName = Button.class.getName();
     }
 
     @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 3d039e6..6deb192 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
@@ -40,6 +40,7 @@
 import android.service.quickaccesswallet.WalletCard;
 import android.service.quicksettings.Tile;
 import android.util.Log;
+import android.widget.Button;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -142,8 +143,16 @@
                         InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE);
 
         mUiHandler.post(
-                () -> mController.startQuickAccessUiIntent(
-                        mActivityStarter, animationController, mSelectedCard != null));
+                () -> {
+                    if (android.service.quickaccesswallet.Flags.launchSelectedCardFromQsTile()
+                            && mSelectedCard != null) {
+                        mController.startWalletCardPendingIntent(
+                                mSelectedCard, mActivityStarter, animationController);
+                    } else {
+                        mController.startQuickAccessUiIntent(
+                                mActivityStarter, animationController, mSelectedCard != null);
+                    }
+                });
     }
 
     @Override
@@ -178,6 +187,7 @@
             state.secondaryLabel = null;
             state.sideViewCustomDrawable = null;
         }
+        state.expandedAccessibilityClassName = Button.class.getName();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt
index 87f542e..aeb6cef 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.qs.tiles.base.viewmodel
 
 import android.os.UserHandle
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.Dumpable
 import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.qs.tiles.base.analytics.QSTileAnalytics
@@ -58,11 +59,8 @@
 import kotlinx.coroutines.flow.merge
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.flow.onStart
-import kotlinx.coroutines.flow.shareIn
 import kotlinx.coroutines.flow.stateIn
 import kotlinx.coroutines.flow.transformLatest
-import com.android.app.tracing.coroutines.launchTraced as launch
-import kotlinx.coroutines.withContext
 
 /**
  * Provides a hassle-free way to implement new tiles according to current System UI architecture
@@ -90,36 +88,35 @@
 
     private val users: MutableStateFlow<UserHandle> =
         MutableStateFlow(userRepository.getSelectedUserInfo().userHandle)
+
     private val userInputs: MutableSharedFlow<QSTileUserAction> = MutableSharedFlow()
+
     private val forceUpdates: MutableSharedFlow<Unit> = MutableSharedFlow()
     private val spec
         get() = config.tileSpec
 
-    private val tileData: SharedFlow<DATA_TYPE> = createTileDataFlow()
+    private val tileData: SharedFlow<DATA_TYPE?> = createTileDataFlow()
 
     override val state: StateFlow<QSTileState?> =
         tileData
             .map { data ->
-                withContext(uiBackgroundDispatcher) { mapper().map(config, data) }
-                    .also { state -> qsTileLogger.logStateUpdate(spec, state, data) }
+                data?.let {
+                    mapper().map(config, it).also { state ->
+                        qsTileLogger.logStateUpdate(spec, state, it)
+                    }
+                }
             }
-            .stateIn(
-                tileScope,
-                SharingStarted.WhileSubscribed(),
-                null,
-            )
+            .flowOn(uiBackgroundDispatcher)
+            .stateIn(tileScope, SharingStarted.WhileSubscribed(), null)
+
     override val isAvailable: StateFlow<Boolean> =
         users
             .flatMapLatest { tileDataInteractor().availability(it) }
             .flowOn(backgroundDispatcher)
-            .stateIn(
-                tileScope,
-                SharingStarted.WhileSubscribed(),
-                true,
-            )
+            .stateIn(tileScope, SharingStarted.WhileSubscribed(), true)
 
     override fun forceUpdate() {
-        tileScope.launch { forceUpdates.emit(Unit) }
+        tileScope.launch(context = backgroundDispatcher) { forceUpdates.emit(Unit) }
     }
 
     override fun onUserChanged(user: UserHandle) {
@@ -131,9 +128,9 @@
             userAction,
             spec,
             tileData.replayCache.isNotEmpty(),
-            state.replayCache.isNotEmpty()
+            state.replayCache.isNotEmpty(),
         )
-        tileScope.launch { userInputs.emit(userAction) }
+        tileScope.launch(context = backgroundDispatcher) { userInputs.emit(userAction) }
     }
 
     override fun destroy() {
@@ -147,7 +144,7 @@
             println(state.replayCache.lastOrNull().toString())
         }
 
-    private fun createTileDataFlow(): SharedFlow<DATA_TYPE> =
+    private fun createTileDataFlow(): SharedFlow<DATA_TYPE?> =
         users
             .transformLatest { user ->
                 coroutineScope {
@@ -159,6 +156,7 @@
                                     .onEach { qsTileLogger.logForceUpdate(spec) },
                             )
                             .onStart { qsTileLogger.logInitialRequest(spec) }
+                            .flowOn(backgroundDispatcher)
                             .stateIn(this, SharingStarted.Eagerly, DataUpdateTrigger.InitialRequest)
                     tileDataInteractor()
                         .tileData(user, updateTriggers)
@@ -171,11 +169,8 @@
                 }
             }
             .distinctUntilChanged()
-            .shareIn(
-                tileScope,
-                SharingStarted.WhileSubscribed(),
-                replay = 1, // we only care about the most recent value
-            )
+            .flowOn(backgroundDispatcher)
+            .stateIn(tileScope, SharingStarted.WhileSubscribed(), null)
 
     /**
      * Creates a user input flow which:
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileDataInteractor.kt
index 8f870d4..4806c3f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileDataInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileDataInteractor.kt
@@ -18,7 +18,7 @@
 
 import android.os.UserHandle
 import android.service.quicksettings.Tile
-import com.android.systemui.common.coroutine.ConflatedCallbackFlow
+import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.qs.pipeline.shared.TileSpec
 import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
 import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor
@@ -28,6 +28,7 @@
 import com.android.systemui.qs.tiles.impl.custom.domain.entity.CustomTileDataModel
 import com.android.systemui.qs.tiles.impl.di.QSTileScope
 import com.android.systemui.user.data.repository.UserRepository
+import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -44,7 +45,6 @@
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.flow.onStart
 import kotlinx.coroutines.flow.shareIn
-import com.android.app.tracing.coroutines.launchTraced as launch
 
 @QSTileScope
 @OptIn(ExperimentalCoroutinesApi::class)
@@ -64,7 +64,7 @@
     private val bindingFlow =
         mutableUserFlow
             .flatMapLatest { user ->
-                ConflatedCallbackFlow.conflatedCallbackFlow {
+                conflatedCallbackFlow {
                     serviceInteractor.setUser(user)
 
                     // Wait for the CustomTileInteractor to become initialized first, because
@@ -79,7 +79,7 @@
                             defaultsRepository.requestNewDefaults(
                                 user,
                                 tileSpec.componentName,
-                                true
+                                true,
                             )
                         }
                         .launchIn(this)
@@ -99,7 +99,7 @@
 
     override fun tileData(
         user: UserHandle,
-        triggers: Flow<DataUpdateTrigger>
+        triggers: Flow<DataUpdateTrigger>,
     ): Flow<CustomTileDataModel> {
         tileScope.launch { mutableUserFlow.emit(user) }
         return bindingFlow.combine(triggers) { _, _ -> }.flatMapLatest { dataFlow(user) }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt
index ab3862b..f9a1ad5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt
@@ -25,6 +25,7 @@
 import com.android.systemui.animation.Expandable
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.UiBackground
 import com.android.systemui.plugins.qs.QSTile
 import com.android.systemui.qs.QSHost
 import com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIcon
@@ -35,14 +36,17 @@
 import dagger.assisted.AssistedInject
 import java.io.PrintWriter
 import java.util.concurrent.CopyOnWriteArraySet
+import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.flow.collectIndexed
 import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.flow.takeWhile
+import kotlinx.coroutines.launch
 
 // TODO(b/http://b/299909989): Use QSTileViewModel directly after the rollout
 class QSTileViewModelAdapter
@@ -51,6 +55,7 @@
     @Application private val applicationScope: CoroutineScope,
     private val qsHost: QSHost,
     @Assisted private val qsTileViewModel: QSTileViewModel,
+    @UiBackground private val uiBgDispatcher: CoroutineDispatcher,
 ) : QSTile, Dumpable {
 
     private val context
@@ -162,19 +167,25 @@
     override fun setListening(client: Any?, listening: Boolean) {
         client ?: return
         if (listening) {
-            val clientWasNotAlreadyListening = listeningClients.add(client)
-            if (clientWasNotAlreadyListening && listeningClients.size == 1) {
-                stateJob =
-                    qsTileViewModel.state
-                        .filterNotNull()
-                        .map { mapState(context, it, qsTileViewModel.config) }
-                        .onEach { legacyState ->
-                            val changed = legacyState.copyTo(cachedState)
-                            if (changed) {
-                                callbacks.forEach { it.onStateChanged(legacyState) }
+            applicationScope.launch(uiBgDispatcher) {
+                val shouldStartMappingJob =
+                    listeningClients.add(client) // new client
+                    && listeningClients.size == 1 // first client
+
+                if (shouldStartMappingJob) {
+                    stateJob =
+                        qsTileViewModel.state
+                            .filterNotNull()
+                            .map { mapState(context, it, qsTileViewModel.config) }
+                            .onEach { legacyState ->
+                                val changed = legacyState.copyTo(cachedState)
+                                if (changed) {
+                                    callbacks.forEach { it.onStateChanged(legacyState) }
+                                }
                             }
-                        }
-                        .launchIn(applicationScope)
+                            .flowOn(uiBgDispatcher)
+                            .launchIn(applicationScope)
+                }
             }
         } else {
             listeningClients.remove(client)
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index a5eb92b..e3cf411 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -26,11 +26,6 @@
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
 import static android.window.BackEvent.EDGE_NONE;
 
-import static com.android.window.flags.Flags.predictiveBackSwipeEdgeNoneApi;
-import static com.android.window.flags.Flags.predictiveBackThreeButtonNav;
-import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
-import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNFOLD_ANIMATION_FORWARDER;
-import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_AWAKE;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_COMMUNAL_HUB_SHOWING;
@@ -42,6 +37,9 @@
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_WAKEFULNESS_TRANSITION;
+import static com.android.systemui.shared.system.QuickStepContract.addInterface;
+import static com.android.window.flags.Flags.predictiveBackSwipeEdgeNoneApi;
+import static com.android.window.flags.Flags.predictiveBackThreeButtonNav;
 
 import android.annotation.FloatRange;
 import android.annotation.Nullable;
@@ -559,13 +557,9 @@
             mOverviewProxy = IOverviewProxy.Stub.asInterface(service);
 
             Bundle params = new Bundle();
-            params.putBinder(KEY_EXTRA_SYSUI_PROXY, mSysUiProxy.asBinder());
-            params.putBinder(KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER,
-                    mSysuiUnlockAnimationController.asBinder());
-            mUnfoldTransitionProgressForwarder.ifPresent(
-                    unfoldProgressForwarder -> params.putBinder(
-                            KEY_EXTRA_UNFOLD_ANIMATION_FORWARDER,
-                            unfoldProgressForwarder.asBinder()));
+            addInterface(mSysUiProxy, params);
+            addInterface(mSysuiUnlockAnimationController, params);
+            addInterface(mUnfoldTransitionProgressForwarder.orElse(null), params);
             // Add all the interfaces exposed by the shell
             mShellInterface.createExternalInterfaces(params);
 
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegate.kt
index eb568f7..d9cc0c8 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegate.kt
@@ -133,6 +133,7 @@
         dialog.setTitle(R.string.screenrecord_title)
         setStartButtonOnClickListener { v: View? ->
             onStartRecordingClicked?.run()
+            val selectedScreenShareOption = getSelectedScreenShareOption()
             if (selectedScreenShareOption.mode == ENTIRE_SCREEN) {
                 requestScreenCapture(/* captureTarget= */ null, selectedScreenShareOption.displayId)
             }
@@ -212,7 +213,8 @@
     }
 
     private fun updateTapsViewVisibility() {
-        tapsView.visibility = if (selectedScreenShareOption.mode == SINGLE_APP) GONE else VISIBLE
+        tapsView.visibility =
+            if (getSelectedScreenShareOption().mode == SINGLE_APP) GONE else VISIBLE
     }
 
     /**
@@ -226,7 +228,7 @@
         displayId: Int = Display.DEFAULT_DISPLAY,
     ) {
         val userContext = userContextProvider.userContext
-        val showTaps = selectedScreenShareOption.mode != SINGLE_APP && tapsSwitch.isChecked
+        val showTaps = getSelectedScreenShareOption().mode != SINGLE_APP && tapsSwitch.isChecked
         val audioMode =
             if (audioSwitch.isChecked) options.selectedItem as ScreenRecordingAudioSource
             else ScreenRecordingAudioSource.NONE
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 88522d5..3a6c250 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -172,6 +172,7 @@
 import com.android.systemui.shade.data.repository.FlingInfo;
 import com.android.systemui.shade.data.repository.ShadeRepository;
 import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractor;
+import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround;
 import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.GestureRecorder;
@@ -2269,7 +2270,11 @@
     }
 
     float getDisplayDensity() {
-        return mCentralSurfaces.getDisplayDensity();
+        if (ShadeWindowGoesAround.isEnabled()) {
+            return mView.getContext().getResources().getConfiguration().densityDpi;
+        } else {
+            return mCentralSurfaces.getDisplayDensity();
+        }
     }
 
     /** Return whether a touch is near the gesture handle at the bottom of screen */
@@ -3830,7 +3835,7 @@
                     /* screenOnFromTouch=*/ getWakefulness().isAwakeFromTapOrGesture());
             // Log collapse gesture if on lock screen.
             if (!expand && onKeyguard) {
-                float displayDensity = mCentralSurfaces.getDisplayDensity();
+                float displayDensity = getDisplayDensity();
                 int heightDp = (int) Math.abs((y - mInitialExpandY) / displayDensity);
                 int velocityDp = (int) Math.abs(vel / displayDensity);
                 mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_UNLOCK, heightDp, velocityDp);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeUserActions.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeUserActions.kt
index dd1b58c..c6752f8 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeUserActions.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeUserActions.kt
@@ -30,8 +30,8 @@
     isDownFromTopEdgeEnabled: Boolean = true,
     requireTwoPointersForTopEdgeForQs: Boolean = false,
 ): Array<Pair<UserAction, UserActionResult>> {
-    val shadeUserActionResult = UserActionResult(Scenes.Shade, isIrreversible = true)
-    val qsSceneUserActionResult = UserActionResult(Scenes.QuickSettings, isIrreversible = true)
+    val shadeUserActionResult = UserActionResult(Scenes.Shade)
+    val qsSceneUserActionResult = UserActionResult(Scenes.QuickSettings)
     return buildList {
             // Swiping down, not from the edge, always goes to shade.
             add(Swipe.Down to shadeUserActionResult)
@@ -53,7 +53,7 @@
 
 /** Returns collection of [UserAction] to [UserActionResult] pairs for opening the split shade. */
 fun splitShadeActions(): Array<Pair<UserAction, UserActionResult>> {
-    val shadeUserActionResult = UserActionResult(Scenes.Shade, ToSplitShade, isIrreversible = true)
+    val shadeUserActionResult = UserActionResult(Scenes.Shade, ToSplitShade)
     return arrayOf(
         // Swiping down, not from the edge, always goes to shade.
         Swipe.Down to shadeUserActionResult,
@@ -66,10 +66,8 @@
 
 /** Returns collection of [UserAction] to [UserActionResult] pairs for opening the dual shade. */
 fun dualShadeActions(): Array<Pair<UserAction, UserActionResult>> {
-    val notifShadeUserActionResult =
-        UserActionResult.ShowOverlay(Overlays.NotificationsShade, isIrreversible = true)
-    val qsShadeuserActionResult =
-        UserActionResult.ShowOverlay(Overlays.QuickSettingsShade, isIrreversible = true)
+    val notifShadeUserActionResult = UserActionResult.ShowOverlay(Overlays.NotificationsShade)
+    val qsShadeuserActionResult = UserActionResult.ShowOverlay(Overlays.QuickSettingsShade)
     return arrayOf(
         Swipe.Down to notifShadeUserActionResult,
         Swipe.Down(fromSource = SceneContainerEdge.TopRight) to qsShadeuserActionResult,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractor.kt
index bb0467f..2eae3eb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractor.kt
@@ -23,6 +23,8 @@
 import com.android.systemui.statusbar.chips.StatusBarChipLogTags.pad
 import com.android.systemui.statusbar.chips.StatusBarChipsLog
 import com.android.systemui.statusbar.phone.ongoingcall.data.repository.OngoingCallRepository
+import com.android.systemui.statusbar.phone.ongoingcall.domain.interactor.OngoingCallInteractor
+import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization
 import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
@@ -37,17 +39,30 @@
 @Inject
 constructor(
     @Application private val scope: CoroutineScope,
+    ongoingCallInteractor: OngoingCallInteractor,
     repository: OngoingCallRepository,
     @StatusBarChipsLog private val logger: LogBuffer,
 ) {
     val ongoingCallState: StateFlow<OngoingCallModel> =
-        repository.ongoingCallState
+        (if (StatusBarChipsModernization.isEnabled)
+            ongoingCallInteractor.ongoingCallState
+        else
+            repository.ongoingCallState)
             .onEach {
-                logger.log(TAG, LogLevel.INFO, { str1 = it::class.simpleName }, { "State: $str1" })
+                logger.log(
+                    TAG,
+                    LogLevel.INFO,
+                    { str1 = it::class.simpleName },
+                    { "State: $str1" }
+                )
             }
-            .stateIn(scope, SharingStarted.Lazily, OngoingCallModel.NoCall)
+            .stateIn(
+                scope,
+                SharingStarted.Lazily,
+                OngoingCallModel.NoCall
+            )
 
     companion object {
         private val TAG = "OngoingCall".pad()
     }
-}
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
index b8cdd25..6f491e7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
@@ -59,7 +59,8 @@
         interactor.ongoingCallState
             .map { state ->
                 when (state) {
-                    is OngoingCallModel.NoCall -> OngoingActivityChipModel.Hidden()
+                    is OngoingCallModel.NoCall,
+                    is OngoingCallModel.InCallWithVisibleApp -> OngoingActivityChipModel.Hidden()
                     is OngoingCallModel.InCall -> {
                         val icon =
                             if (
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt
index 087b510..c57c807 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt
@@ -105,7 +105,7 @@
             }
             return null
         }
-        return NotificationChipModel(key, statusBarChipIconView)
+        return NotificationChipModel(key, statusBarChipIconView, whenTime)
     }
 
     @AssistedFactory
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/model/NotificationChipModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/model/NotificationChipModel.kt
index 5698ee6..bc4241d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/model/NotificationChipModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/model/NotificationChipModel.kt
@@ -19,4 +19,8 @@
 import com.android.systemui.statusbar.StatusBarIconView
 
 /** Modeling all the data needed to render a status bar notification chip. */
-data class NotificationChipModel(val key: String, val statusBarChipIconView: StatusBarIconView)
+data class NotificationChipModel(
+    val key: String,
+    val statusBarChipIconView: StatusBarIconView,
+    val whenTime: Long,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt
index 9eff627..b2f7e2f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt
@@ -63,9 +63,13 @@
                     )
                 }
             }
-        return OngoingActivityChipModel.Shown.IconOnly(icon, colors, onClickListener)
+        return OngoingActivityChipModel.Shown.ShortTimeDelta(
+            icon,
+            colors,
+            time = this.whenTime,
+            onClickListener,
+        )
         // TODO(b/364653005): Use Notification.showWhen to determine if we should show the time.
-        // TODO(b/364653005): If Notification.whenTime is in the past, show "ago" in the text.
         // TODO(b/364653005): If Notification.shortCriticalText is set, use that instead of `when`.
         // TODO(b/364653005): If the app that posted the notification is in the foreground, don't
         // show that app's chip.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt
index f4462a4..730784a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt
@@ -192,10 +192,14 @@
             }
             is OngoingActivityChipModel.Shown.ShortTimeDelta -> {
                 chipShortTimeDeltaView.setTime(chipModel.time)
-                // TODO(b/364653005): DateTimeView's relative time doesn't quite match the format we
-                //  want in the status bar chips.
-                chipShortTimeDeltaView.isShowRelativeTime = true
                 chipShortTimeDeltaView.visibility = View.VISIBLE
+                chipShortTimeDeltaView.isShowRelativeTime = true
+                chipShortTimeDeltaView.setRelativeTimeDisambiguationTextMask(
+                    DateTimeView.DISAMBIGUATION_TEXT_PAST
+                )
+                chipShortTimeDeltaView.setRelativeTimeUnitDisplayLength(
+                    DateTimeView.UNIT_DISPLAY_LENGTH_MEDIUM
+                )
 
                 chipTextView.visibility = View.GONE
                 chipTimeView.hide()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
index 47b695e..2588c7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarModule.kt
@@ -36,6 +36,7 @@
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy
 import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController
 import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallLog
+import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.statusbar.ui.SystemBarUtilsProxyImpl
 import com.android.systemui.statusbar.window.MultiDisplayStatusBarWindowControllerStore
@@ -63,11 +64,6 @@
 
     @Binds
     @IntoMap
-    @ClassKey(OngoingCallController::class)
-    fun bindOngoingCallController(impl: OngoingCallController): CoreStartable
-
-    @Binds
-    @IntoMap
     @ClassKey(LightBarController::class)
     fun lightBarControllerAsCoreStartable(controller: LightBarController): CoreStartable
 
@@ -90,6 +86,18 @@
     ): LightBarController.Factory
 
     companion object {
+        @Provides
+        @SysUISingleton
+        @IntoMap
+        @ClassKey(OngoingCallController::class)
+        fun ongoingCallController(
+            controller: OngoingCallController
+        ): CoreStartable =
+            if (StatusBarChipsModernization.isEnabled) {
+                CoreStartable.NOP
+            } else {
+                controller
+            }
 
         @Provides
         @SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
index e75c11d..3c31d89 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
@@ -46,6 +46,7 @@
 import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor;
 import com.android.systemui.statusbar.notification.shared.NotificationMinimalism;
 import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 import com.android.systemui.util.kotlin.BooleanFlowOperators;
 import com.android.systemui.util.kotlin.JavaAdapter;
@@ -78,6 +79,7 @@
     private final CommunalSceneInteractor mCommunalSceneInteractor;
     private final ShadeInteractor mShadeInteractor;
     private final KeyguardTransitionInteractor mKeyguardTransitionInteractor;
+    private final KeyguardStateController mKeyguardStateController;
     private final VisualStabilityCoordinatorLogger mLogger;
 
     private boolean mSleepy = true;
@@ -120,6 +122,7 @@
             CommunalSceneInteractor communalSceneInteractor,
             ShadeInteractor shadeInteractor,
             KeyguardTransitionInteractor keyguardTransitionInteractor,
+            KeyguardStateController keyguardStateController,
             VisualStabilityCoordinatorLogger logger) {
         mHeadsUpManager = headsUpManager;
         mShadeAnimationInteractor = shadeAnimationInteractor;
@@ -133,6 +136,7 @@
         mCommunalSceneInteractor = communalSceneInteractor;
         mShadeInteractor = shadeInteractor;
         mKeyguardTransitionInteractor = keyguardTransitionInteractor;
+        mKeyguardStateController = keyguardStateController;
         mLogger = logger;
 
         dumpManager.registerDumpable(this);
@@ -162,17 +166,29 @@
                             KeyguardState.LOCKSCREEN),
                     this::onLockscreenKeyguardStateTransitionValueChanged);
         }
-        if (Flags.checkLockscreenGoneTransition()) {
-            mJavaAdapter.alwaysCollectFlow(mKeyguardTransitionInteractor.isInTransition(
-                            Edge.create(KeyguardState.LOCKSCREEN, Scenes.Gone),
-                            Edge.create(KeyguardState.LOCKSCREEN, KeyguardState.GONE)),
-                    this::onLockscreenInGoneTransitionChanged);
-        }
 
+        if (Flags.checkLockscreenGoneTransition()) {
+            if (SceneContainerFlag.isEnabled()) {
+                mJavaAdapter.alwaysCollectFlow(mKeyguardTransitionInteractor.isInTransition(
+                                Edge.create(KeyguardState.LOCKSCREEN, Scenes.Gone), null),
+                        this::onLockscreenInGoneTransitionChanged);
+            } else {
+                mKeyguardStateController.addCallback(mKeyguardFadeAwayAnimationCallback);
+            }
+        }
 
         pipeline.setVisualStabilityManager(mNotifStabilityManager);
     }
 
+    final KeyguardStateController.Callback mKeyguardFadeAwayAnimationCallback =
+            new KeyguardStateController.Callback() {
+                @Override
+                public void onKeyguardFadingAwayChanged() {
+                    onLockscreenInGoneTransitionChanged(
+                            mKeyguardStateController.isKeyguardFadingAway());
+                }
+            };
+
     // TODO(b/203826051): Ensure stability manager can allow reordering off-screen
     //  HUNs to the top of the shade
     private final NotifStabilityManager mNotifStabilityManager =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractor.kt
index cff5bef..6b93ee1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractor.kt
@@ -79,11 +79,10 @@
     /** The notifications that are promoted and ongoing. Sorted by priority order. */
     val promotedOngoingNotifications: Flow<List<ActiveNotificationModel>> =
         if (StatusBarNotifChips.isEnabled) {
-            // TODO(b/364653005): Filter all the notifications down to just the promoted ones.
             // TODO(b/364653005): [ongoingCallNotification] should be incorporated into this flow
             // instead of being separate.
             topLevelRepresentativeNotifications
-                .map { notifs -> notifs.filter { it.isPromoted } }
+                .map { notifs -> notifs.filter { it.promotedContent != null } }
                 .distinctUntilChanged()
                 .flowOn(backgroundDispatcher)
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt
index 8bd7a1a..042389f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractor.kt
@@ -33,7 +33,6 @@
 import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider
 import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationListRepository
 import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore
-import com.android.systemui.statusbar.notification.promoted.PromotedNotificationsProvider
 import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
 import com.android.systemui.statusbar.notification.shared.ActiveNotificationEntryModel
 import com.android.systemui.statusbar.notification.shared.ActiveNotificationGroupModel
@@ -52,7 +51,6 @@
 constructor(
     private val repository: ActiveNotificationListRepository,
     private val sectionStyleProvider: SectionStyleProvider,
-    private val promotedNotificationsProvider: PromotedNotificationsProvider,
 ) {
     /**
      * Sets the current list of rendered notification entries as displayed in the notification list.
@@ -60,11 +58,7 @@
     fun setRenderedList(entries: List<ListEntry>) {
         traceSection("RenderNotificationListInteractor.setRenderedList") {
             repository.activeNotifications.update { existingModels ->
-                buildActiveNotificationsStore(
-                    existingModels,
-                    sectionStyleProvider,
-                    promotedNotificationsProvider,
-                ) {
+                buildActiveNotificationsStore(existingModels, sectionStyleProvider) {
                     entries.forEach(::addListEntry)
                     setRankingsMap(entries)
                 }
@@ -76,21 +70,13 @@
 private fun buildActiveNotificationsStore(
     existingModels: ActiveNotificationsStore,
     sectionStyleProvider: SectionStyleProvider,
-    promotedNotificationsProvider: PromotedNotificationsProvider,
     block: ActiveNotificationsStoreBuilder.() -> Unit,
 ): ActiveNotificationsStore =
-    ActiveNotificationsStoreBuilder(
-            existingModels,
-            sectionStyleProvider,
-            promotedNotificationsProvider,
-        )
-        .apply(block)
-        .build()
+    ActiveNotificationsStoreBuilder(existingModels, sectionStyleProvider).apply(block).build()
 
 private class ActiveNotificationsStoreBuilder(
     private val existingModels: ActiveNotificationsStore,
     private val sectionStyleProvider: SectionStyleProvider,
-    private val promotedNotificationsProvider: PromotedNotificationsProvider,
 ) {
     private val builder = ActiveNotificationsStore.Builder()
 
@@ -163,7 +149,6 @@
             key = key,
             groupKey = sbn.groupKey,
             whenTime = sbn.notification.`when`,
-            isPromoted = promotedNotificationsProvider.shouldPromote(this),
             isAmbient = sectionStyleProvider.isMinimized(this),
             isRowDismissed = isRowDismissed,
             isSilent = sectionStyleProvider.isSilent(this),
@@ -190,7 +175,6 @@
     key: String,
     groupKey: String?,
     whenTime: Long,
-    isPromoted: Boolean,
     isAmbient: Boolean,
     isRowDismissed: Boolean,
     isSilent: Boolean,
@@ -215,7 +199,6 @@
             key = key,
             groupKey = groupKey,
             whenTime = whenTime,
-            isPromoted = isPromoted,
             isAmbient = isAmbient,
             isRowDismissed = isRowDismissed,
             isSilent = isSilent,
@@ -240,7 +223,6 @@
             key = key,
             groupKey = groupKey,
             whenTime = whenTime,
-            isPromoted = isPromoted,
             isAmbient = isAmbient,
             isRowDismissed = isRowDismissed,
             isSilent = isSilent,
@@ -266,7 +248,6 @@
     key: String,
     groupKey: String?,
     whenTime: Long,
-    isPromoted: Boolean,
     isAmbient: Boolean,
     isRowDismissed: Boolean,
     isSilent: Boolean,
@@ -290,7 +271,6 @@
         key != this.key -> false
         groupKey != this.groupKey -> false
         whenTime != this.whenTime -> false
-        isPromoted != this.isPromoted -> false
         isAmbient != this.isAmbient -> false
         isRowDismissed != this.isRowDismissed -> false
         isSilent != this.isSilent -> false
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java
index e13baf8..0b188afa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java
@@ -119,8 +119,7 @@
     protected int mAutoDismissTime;
     protected DelayableExecutor mExecutor;
 
-    @VisibleForTesting
-    public final int mExtensionTime;
+    private final int mExtensionTime;
 
     // TODO(b/328393698) move the topHeadsUpRow logic to an interactor
     private final MutableStateFlow<HeadsUpRowRepository> mTopHeadsUpRow =
@@ -213,7 +212,8 @@
         mVisualStabilityProvider = visualStabilityProvider;
         Resources resources = context.getResources();
         mMinimumDisplayTime = NotificationThrottleHun.isEnabled()
-                ? 500 : resources.getInteger(R.integer.heads_up_notification_minimum_time);
+                ? resources.getInteger(R.integer.heads_up_notification_minimum_time_with_throttling)
+                : resources.getInteger(R.integer.heads_up_notification_minimum_time);
         mStickyForSomeTimeAutoDismissTime = resources.getInteger(
                 R.integer.sticky_heads_up_notification_time);
         mAutoDismissTime = resources.getInteger(R.integer.heads_up_notification_decay);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/EnsureEnrViewsVisibility.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/EnsureEnrViewsVisibility.kt
deleted file mode 100644
index aa63f4ddb..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/EnsureEnrViewsVisibility.kt
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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.notification.row
-
-import com.android.systemui.Flags
-import com.android.systemui.flags.FlagToken
-import com.android.systemui.flags.RefactorFlagUtils
-
-/** Helper for reading or using the ensure enr views visibility flag state. */
-@Suppress("NOTHING_TO_INLINE")
-object EnsureEnrViewsVisibility {
-    /** The aconfig flag name */
-    const val FLAG_NAME = Flags.FLAG_ENSURE_ENR_VIEWS_VISIBILITY
-
-    /** A token used for dependency declaration */
-    val token: FlagToken
-        get() = FlagToken(FLAG_NAME, isEnabled)
-
-    /** Is the refactor enabled */
-    @JvmStatic
-    inline val isEnabled
-        get() = Flags.ensureEnrViewsVisibility()
-
-    /**
-     * Called to ensure code is only run when the flag is enabled. This protects users from the
-     * unintended behaviors caused by accidentally running new logic, while also crashing on an eng
-     * build to ensure that the refactor author catches issues in testing.
-     */
-    @JvmStatic
-    inline fun isUnexpectedlyInLegacyMode() =
-        RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)
-
-    /**
-     * Called to ensure code is only run when the flag is disabled. This will throw an exception if
-     * the flag is not enabled to ensure that the refactor author catches issues in testing.
-     * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
-     */
-    @JvmStatic
-    inline fun assertInNewMode() = RefactorFlagUtils.assertInNewMode(isEnabled, FLAG_NAME)
-
-    /**
-     * Called to ensure code is only run when the flag is disabled. This will throw an exception if
-     * the flag is enabled to ensure that the refactor author catches issues in testing.
-     */
-    @JvmStatic
-    inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 7ad65fc..d71b1b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -2603,10 +2603,6 @@
     }
 
     private void updateChildrenVisibility() {
-        if (EnsureEnrViewsVisibility.isEnabled()) {
-            mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
-        }
-
         boolean hideContentWhileLaunching = mExpandAnimationRunning && mGuts != null
                 && mGuts.isExposed();
         mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren
@@ -3166,13 +3162,7 @@
             } else {
                 mLogger.logSkipResetAllContentAlphas(getEntry());
             }
-
-            if (!EnsureEnrViewsVisibility.isEnabled()) {
-                // mPublicLayout.setVisibility moved to updateChildrenVisibility when the flag is on
-                // in order to ensure public and private views are not visible
-                // together at the same time.
-                mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
-            }
+            mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
             updateChildrenVisibility();
         } else {
             animateShowingPublic(delay, duration, mShowingPublic);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/ActiveNotificationModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/ActiveNotificationModel.kt
index a2b7155..ab8be30 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/ActiveNotificationModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/ActiveNotificationModel.kt
@@ -38,9 +38,6 @@
     val groupKey: String?,
     /** When this notification was posted. */
     val whenTime: Long,
-    // TODO(b/377566661): Make isPromoted just check if promotedContent != null.
-    /** True if this notification should be promoted and false otherwise. */
-    val isPromoted: Boolean,
     /** Is this entry in the ambient / minimized section (lowest priority)? */
     val isAmbient: Boolean,
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index cfca830..6293640 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -499,7 +499,7 @@
 
         mGroupHeaderWrapper.setExpanded(mChildrenExpanded);
         mGroupHeaderWrapper.onContentUpdated(mContainingNotification);
-
+        resetHeaderVisibilityIfNeeded(mGroupHeader, calculateDesiredHeader());
         updateHeaderVisibility(false /* animate */);
         updateChildrenAppearance();
 
@@ -535,6 +535,7 @@
         invalidate();
 
         mMinimizedGroupHeaderWrapper.onContentUpdated(mContainingNotification);
+        resetHeaderVisibilityIfNeeded(mMinimizedGroupHeader, calculateDesiredHeader());
         updateHeaderVisibility(false /* animate */);
         updateChildrenAppearance();
     }
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 6de4928..e4768e8 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
@@ -71,6 +71,7 @@
 import com.android.systemui.statusbar.phone.fragment.dagger.HomeStatusBarComponent.Startable;
 import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
 import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallListener;
+import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization;
 import com.android.systemui.statusbar.phone.ui.DarkIconManager;
 import com.android.systemui.statusbar.phone.ui.StatusBarIconController;
 import com.android.systemui.statusbar.pipeline.shared.ui.binder.HomeStatusBarViewBinder;
@@ -960,7 +961,9 @@
             mOngoingCallController.addCallback(mOngoingCallListener);
         }
         // TODO(b/364653005): Do we also need to set the secondary activity chip?
-        mOngoingCallController.setChipView(mPrimaryOngoingActivityChip);
+        if (!StatusBarChipsModernization.isEnabled()) {
+            mOngoingCallController.setChipView(mPrimaryOngoingActivityChip);
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
index 78926c7..2166304 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
@@ -60,7 +60,10 @@
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 
-/** A controller to handle the ongoing call chip in the collapsed status bar. */
+/** A controller to handle the ongoing call chip in the collapsed status bar.
+ * @deprecated Use [OngoingCallInteractor] instead, which follows recommended architecture patterns
+ */
+@Deprecated("Use OngoingCallInteractor instead")
 @SysUISingleton
 class OngoingCallController
 @Inject
@@ -165,6 +168,9 @@
         }
 
     override fun start() {
+        if (StatusBarChipsModernization.isEnabled)
+            return
+
         dumpManager.registerDumpable(this)
 
         if (Flags.statusBarUseReposForCallChip()) {
@@ -201,6 +207,8 @@
      * [com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment].
      */
     fun setChipView(chipView: View) {
+        StatusBarChipsModernization.assertInLegacyMode()
+
         tearDownChipView()
         this.chipView = chipView
         val backgroundView: ChipBackgroundContainer? =
@@ -217,6 +225,8 @@
      * Returns true if there's an active ongoing call that should be displayed in a status bar chip.
      */
     fun hasOngoingCall(): Boolean {
+        StatusBarChipsModernization.assertInLegacyMode()
+
         return callNotificationInfo?.isOngoing == true &&
             // When the user is in the phone app, don't show the chip.
             !uidObserver.isCallAppVisible
@@ -224,6 +234,8 @@
 
     /** Creates the right [OngoingCallModel] based on the call state. */
     private fun getOngoingCallModel(): OngoingCallModel {
+        StatusBarChipsModernization.assertInLegacyMode()
+
         if (hasOngoingCall()) {
             val currentInfo =
                 callNotificationInfo
@@ -255,6 +267,8 @@
     }
 
     override fun addCallback(listener: OngoingCallListener) {
+        StatusBarChipsModernization.assertInLegacyMode()
+
         synchronized(mListeners) {
             if (!mListeners.contains(listener)) {
                 mListeners.add(listener)
@@ -263,10 +277,14 @@
     }
 
     override fun removeCallback(listener: OngoingCallListener) {
+        StatusBarChipsModernization.assertInLegacyMode()
+
         synchronized(mListeners) { mListeners.remove(listener) }
     }
 
     private fun updateInfoFromNotifModel(notifModel: ActiveNotificationModel?) {
+        StatusBarChipsModernization.assertInLegacyMode()
+
         if (notifModel == null) {
             logger.log(TAG, LogLevel.DEBUG, {}, { "NotifInteractorCallModel: null" })
             removeChip()
@@ -310,6 +328,8 @@
     }
 
     private fun updateChip() {
+        StatusBarChipsModernization.assertInLegacyMode()
+
         val currentCallNotificationInfo = callNotificationInfo ?: return
 
         val currentChipView = chipView
@@ -360,6 +380,8 @@
     }
 
     private fun updateChipClickListener() {
+        StatusBarChipsModernization.assertInLegacyMode()
+
         if (Flags.statusBarScreenSharingChips()) {
             return
         }
@@ -386,10 +408,14 @@
 
     /** Returns true if the given [procState] represents a process that's visible to the user. */
     private fun isProcessVisibleToUser(procState: Int): Boolean {
+        StatusBarChipsModernization.assertInLegacyMode()
+
         return procState <= ActivityManager.PROCESS_STATE_TOP
     }
 
     private fun updateGestureListening() {
+        StatusBarChipsModernization.assertInLegacyMode()
+
         if (
             callNotificationInfo == null ||
                 callNotificationInfo?.statusBarSwipedAway == true ||
@@ -404,6 +430,8 @@
     }
 
     private fun removeChip() {
+        StatusBarChipsModernization.assertInLegacyMode()
+
         callNotificationInfo = null
         if (!Flags.statusBarScreenSharingChips()) {
             tearDownChipView()
@@ -432,6 +460,8 @@
      * detected.
      */
     private fun onSwipeAwayGestureDetected() {
+        StatusBarChipsModernization.assertInLegacyMode()
+
         logger.log(TAG, LogLevel.DEBUG, {}, { "Swipe away gesture detected" })
         callNotificationInfo = callNotificationInfo?.copy(statusBarSwipedAway = true)
         statusBarWindowControllerStore.defaultDisplay.setOngoingProcessRequiresStatusBarVisible(
@@ -441,6 +471,8 @@
     }
 
     private fun sendStateChangeEvent() {
+        StatusBarChipsModernization.assertInLegacyMode()
+
         ongoingCallRepository.setOngoingCallState(getOngoingCallModel())
         mListeners.forEach { l -> l.onOngoingCallStateChanged(animate = true) }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/StatusBarChipsModernization.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/StatusBarChipsModernization.kt
new file mode 100644
index 0000000..2ab2b68
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/StatusBarChipsModernization.kt
@@ -0,0 +1,52 @@
+/*
+* 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.phone.ongoingcall
+
+import com.android.systemui.Flags
+import com.android.systemui.flags.FlagToken
+import com.android.systemui.flags.RefactorFlagUtils
+
+/** Helper for reading or using the status_bar_use_interactor_for_call_chip flag state. */
+@Suppress("NOTHING_TO_INLINE")
+object StatusBarChipsModernization {
+    /** The aconfig flag name */
+    const val FLAG_NAME = Flags.FLAG_STATUS_BAR_CHIPS_MODERNIZATION
+
+    /** A token used for dependency declaration */
+    val token: FlagToken
+        get() = FlagToken(FLAG_NAME, isEnabled)
+
+    /** Is the refactor enabled */
+    @JvmStatic
+    inline val isEnabled
+        get() = Flags.statusBarChipsModernization() && Flags.statusBarRootModernization()
+
+    /**
+     * Called to ensure code is only run when the flag is enabled. This protects users from the
+     * unintended behaviors caused by accidentally running new logic, while also crashing on an eng
+     * build to ensure that the refactor author catches issues in testing.
+     */
+    @JvmStatic
+    inline fun isUnexpectedlyInLegacyMode() =
+        RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)
+
+    /**
+     * Called to ensure code is only run when the flag is disabled. This will throw an exception if
+     * the flag is enabled to ensure that the refactor author catches issues in testing.
+     */
+    @JvmStatic
+    inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepository.kt
index f16371a..b932c71a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepository.kt
@@ -20,6 +20,7 @@
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.core.LogLevel
 import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallLog
+import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization
 import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel
 import javax.inject.Inject
 import kotlinx.coroutines.flow.MutableStateFlow
@@ -33,7 +34,9 @@
  * [com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController] and
  * [com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore]. Instead, those two
  * classes both refer to this repository.
+ * @deprecated Use [OngoingCallInteractor] instead.
  */
+@Deprecated("Use OngoingCallInteractor instead")
 @SysUISingleton
 class OngoingCallRepository
 @Inject
@@ -49,6 +52,8 @@
      * [com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController].
      */
     fun setOngoingCallState(state: OngoingCallModel) {
+        StatusBarChipsModernization.assertInLegacyMode()
+
         logger.log(
             TAG,
             LogLevel.DEBUG,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt
new file mode 100644
index 0000000..1f7bd14
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt
@@ -0,0 +1,104 @@
+/*
+ * 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.phone.ongoingcall.domain.interactor
+
+import com.android.systemui.activity.data.repository.ActivityManagerRepository
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.core.Logger
+import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
+import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallLog
+import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.stateIn
+
+/**
+ * Interactor for determining whether to show a chip in the status bar for ongoing phone calls.
+ *
+ * This class monitors call notifications and the visibility of call apps to determine the appropriate
+ * chip state. It emits:
+ *  * - [OngoingCallModel.NoCall] when there is no call notification
+ *  * - [OngoingCallModel.InCallWithVisibleApp] when there is a call notification but the call app is visible
+ *  * - [OngoingCallModel.InCall] when there is a call notification and the call app is not visible
+ *  */
+@OptIn(ExperimentalCoroutinesApi::class)
+@SysUISingleton
+class OngoingCallInteractor @Inject constructor(
+    @Application private val scope: CoroutineScope,
+    activityManagerRepository: ActivityManagerRepository,
+    activeNotificationsInteractor: ActiveNotificationsInteractor,
+    @OngoingCallLog private val logBuffer: LogBuffer,
+) {
+    private val logger = Logger(logBuffer, TAG)
+
+    /**
+     * The current state of ongoing calls.
+     */
+    val ongoingCallState: StateFlow<OngoingCallModel> =
+        activeNotificationsInteractor.ongoingCallNotification
+            .flatMapLatest { notificationModel ->
+                when (notificationModel) {
+                    null -> {
+                        logger.d("No active call notification - hiding chip")
+                        flowOf(OngoingCallModel.NoCall)
+                    }
+
+                    else -> combine(
+                        flowOf(notificationModel),
+                        activityManagerRepository.createIsAppVisibleFlow(
+                            creationUid = notificationModel.uid,
+                            logger = logger,
+                            identifyingLogTag = TAG,
+                        ),
+                    ) { model, isVisible ->
+                        when {
+                            isVisible -> {
+                                logger.d({ "Call app is visible: uid=$int1" }) {
+                                    int1 = model.uid
+                                }
+                                OngoingCallModel.InCallWithVisibleApp
+                            }
+
+                            else -> {
+                                logger.d({ "Active call detected: startTime=$long1 hasIcon=$bool1" }) {
+                                    long1 = model.whenTime
+                                    bool1 = model.statusBarChipIconView != null
+                                }
+                                OngoingCallModel.InCall(
+                                    startTimeMs = model.whenTime,
+                                    notificationIconView = model.statusBarChipIconView,
+                                    intent = model.contentIntent,
+                                )
+                            }
+                        }
+                    }
+                }
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), OngoingCallModel.NoCall)
+
+    companion object {
+        private val TAG = "OngoingCall"
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt
index 34bff80..c2c91b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt
@@ -25,6 +25,12 @@
     data object NoCall : OngoingCallModel
 
     /**
+     * There is an ongoing call but the call app is currently visible, so we don't need to show
+     * the chip.
+     */
+    data object InCallWithVisibleApp : OngoingCallModel
+
+    /**
      * There *is* an ongoing call.
      *
      * @property startTimeMs the time that the phone call started, based on the notification's
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt
index 1e8b016..812e0eb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt
@@ -41,6 +41,7 @@
 import com.android.systemui.statusbar.phone.StatusBarLocation
 import com.android.systemui.statusbar.phone.StatusIconContainer
 import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController
+import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization
 import com.android.systemui.statusbar.phone.ui.DarkIconManager
 import com.android.systemui.statusbar.phone.ui.StatusBarIconController
 import com.android.systemui.statusbar.pipeline.shared.ui.binder.HomeStatusBarViewBinder
@@ -150,12 +151,11 @@
                         )
                     iconController.addIconGroup(darkIconManager)
 
-                    // TODO(b/372657935): This won't be needed once OngoingCallController is
-                    // implemented in recommended architecture
-                    ongoingCallController.setChipView(
-                        phoneStatusBarView.requireViewById(R.id.ongoing_activity_chip_primary)
-                    )
-
+                    if (!StatusBarChipsModernization.isEnabled) {
+                        ongoingCallController.setChipView(
+                            phoneStatusBarView.requireViewById(R.id.ongoing_activity_chip_primary)
+                        )
+                    }
                     // For notifications, first inflate the [NotificationIconContainer]
                     val notificationIconArea =
                         phoneStatusBarView.requireViewById<ViewGroup>(R.id.notification_icon_area)
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 1d32a4f..389b6fb 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
@@ -32,6 +32,7 @@
 import android.service.quickaccesswallet.GetWalletCardsRequest;
 import android.service.quickaccesswallet.QuickAccessWalletClient;
 import android.service.quickaccesswallet.QuickAccessWalletClientImpl;
+import android.service.quickaccesswallet.WalletCard;
 import android.util.Log;
 
 import com.android.systemui.animation.ActivityTransitionAnimator;
@@ -268,6 +269,23 @@
                 });
     }
 
+    /**
+     * Starts the {@link android.app.PendingIntent} for a {@link WalletCard}.
+     *
+     * This should be used to open a selected card from the QuickAccessWallet UI or
+     * the settings tile.
+     *
+     * @param activityStarter an {@link ActivityStarter} to launch the Intent or PendingIntent.
+     * @param animationController an {@link ActivityTransitionAnimator.Controller} to provide a
+     *                            smooth animation for the activity launch.
+     */
+    public void startWalletCardPendingIntent(WalletCard card,
+            ActivityStarter activityStarter,
+            ActivityTransitionAnimator.Controller animationController) {
+        activityStarter.postStartActivityDismissingKeyguard(
+                card.getPendingIntent(), animationController);
+    }
+
     private Intent getSysUiWalletIntent() {
         return new Intent(mContext, WalletActivity.class)
                 .setAction(Intent.ACTION_VIEW);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/data/backup/CommunalBackupHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/communal/data/backup/CommunalBackupHelperTest.kt
index 4ca84c58..50fad3b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/communal/data/backup/CommunalBackupHelperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/data/backup/CommunalBackupHelperTest.kt
@@ -32,6 +32,7 @@
 import com.android.systemui.communal.data.db.CommunalDatabase
 import com.android.systemui.communal.data.db.CommunalWidgetDao
 import com.android.systemui.communal.proto.toCommunalHubState
+import com.android.systemui.communal.shared.model.SpanValue
 import com.android.systemui.lifecycle.InstantTaskExecutorRule
 import com.google.common.truth.Truth.assertThat
 import java.io.File
@@ -120,21 +121,32 @@
                     componentName = "com.android.fakePackage1/fakeWidget1",
                     rank = 0,
                     userSerialNumber = 0,
+                    spanY = SpanValue.Responsive(1),
                 ),
                 FakeWidgetMetadata(
                     widgetId = 12,
                     componentName = "com.android.fakePackage2/fakeWidget2",
                     rank = 1,
                     userSerialNumber = 0,
+                    spanY = SpanValue.Responsive(2),
                 ),
                 FakeWidgetMetadata(
                     widgetId = 13,
                     componentName = "com.android.fakePackage3/fakeWidget3",
                     rank = 2,
                     userSerialNumber = 10,
+                    spanY = SpanValue.Responsive(3),
                 ),
             )
-            .onEach { dao.addWidget(it.widgetId, it.componentName, it.rank, it.userSerialNumber) }
+            .onEach {
+                dao.addWidget(
+                    widgetId = it.widgetId,
+                    componentName = it.componentName,
+                    rank = it.rank,
+                    userSerialNumber = it.userSerialNumber,
+                    spanY = it.spanY,
+                )
+            }
     }
 
     private fun getBackupDataInputStream(): BackupDataInputStream {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/data/backup/CommunalBackupUtilsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/communal/data/backup/CommunalBackupUtilsTest.kt
index edc8c83..d31e466 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/communal/data/backup/CommunalBackupUtilsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/data/backup/CommunalBackupUtilsTest.kt
@@ -23,6 +23,9 @@
 import com.android.systemui.communal.data.db.CommunalDatabase
 import com.android.systemui.communal.data.db.CommunalWidgetDao
 import com.android.systemui.communal.nano.CommunalHubState
+import com.android.systemui.communal.shared.model.SpanValue
+import com.android.systemui.communal.shared.model.toFixed
+import com.android.systemui.communal.shared.model.toResponsive
 import com.android.systemui.lifecycle.InstantTaskExecutorRule
 import com.google.common.truth.Correspondence
 import com.google.common.truth.Truth.assertThat
@@ -71,22 +74,25 @@
                     componentName = "com.android.fakePackage1/fakeWidget1",
                     rank = 0,
                     userSerialNumber = 0,
+                    spanY = SpanValue.Responsive(1),
                 ),
                 FakeWidgetMetadata(
                     widgetId = 12,
                     componentName = "com.android.fakePackage2/fakeWidget2",
                     rank = 1,
                     userSerialNumber = 0,
+                    spanY = SpanValue.Responsive(2),
                 ),
                 FakeWidgetMetadata(
                     widgetId = 13,
                     componentName = "com.android.fakePackage3/fakeWidget3",
                     rank = 2,
                     userSerialNumber = 10,
+                    spanY = SpanValue.Responsive(3),
                 ),
             )
         expectedWidgets.forEach {
-            dao.addWidget(it.widgetId, it.componentName, it.rank, it.userSerialNumber)
+            dao.addWidget(it.widgetId, it.componentName, it.rank, it.userSerialNumber, it.spanY)
         }
 
         // Get communal hub state
@@ -150,6 +156,7 @@
         val componentName: String,
         val rank: Int,
         val userSerialNumber: Int,
+        val spanY: SpanValue,
     )
 
     companion object {
@@ -163,7 +170,9 @@
                     actual?.widgetId == expected?.widgetId &&
                         actual?.componentName == expected?.componentName &&
                         actual?.rank == expected?.rank &&
-                        actual?.userSerialNumber == expected?.userSerialNumber
+                        actual?.userSerialNumber == expected?.userSerialNumber &&
+                        actual?.spanY == expected?.spanY?.toFixed()?.value &&
+                        actual?.spanYNew == expected?.spanY?.toResponsive()?.value
                 },
                 "represents",
             )
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/data/db/CommunalDatabaseMigrationsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/communal/data/db/CommunalDatabaseMigrationsTest.kt
index 7d5a334..1466e32 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/communal/data/db/CommunalDatabaseMigrationsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/data/db/CommunalDatabaseMigrationsTest.kt
@@ -22,6 +22,8 @@
 import androidx.test.filters.SmallTest
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.communal.shared.model.SpanValue
+import com.android.systemui.communal.shared.model.toResponsive
 import com.android.systemui.lifecycle.InstantTaskExecutorRule
 import com.google.common.truth.Truth.assertThat
 import org.junit.Rule
@@ -173,6 +175,49 @@
         databaseV4.verifyWidgetsV4(fakeWidgetsV3.map { it.getV4() })
     }
 
+    @Test
+    fun migrate4To5_addNewSpanYColumn() {
+        val databaseV4 = migrationTestHelper.createDatabase(DATABASE_NAME, version = 4)
+
+        val fakeWidgetsV4 =
+            listOf(
+                FakeCommunalWidgetItemV4(
+                    widgetId = 1,
+                    componentName = "test_widget_1",
+                    itemId = 11,
+                    userSerialNumber = 0,
+                    spanY = 3,
+                ),
+                FakeCommunalWidgetItemV4(
+                    widgetId = 2,
+                    componentName = "test_widget_2",
+                    itemId = 12,
+                    userSerialNumber = 10,
+                    spanY = 6,
+                ),
+                FakeCommunalWidgetItemV4(
+                    widgetId = 3,
+                    componentName = "test_widget_3",
+                    itemId = 13,
+                    userSerialNumber = 0,
+                    spanY = 0,
+                ),
+            )
+        databaseV4.insertWidgetsV4(fakeWidgetsV4)
+
+        databaseV4.verifyWidgetsV4(fakeWidgetsV4)
+
+        val databaseV5 =
+            migrationTestHelper.runMigrationsAndValidate(
+                name = DATABASE_NAME,
+                version = 5,
+                validateDroppedTables = false,
+                CommunalDatabase.MIGRATION_4_5,
+            )
+
+        databaseV5.verifyWidgetsV5(fakeWidgetsV4.map { it.getV5() })
+    }
+
     private fun SupportSQLiteDatabase.insertWidgetsV1(widgets: List<FakeCommunalWidgetItemV1>) {
         widgets.forEach { widget ->
             execSQL(
@@ -198,6 +243,24 @@
         }
     }
 
+    private fun SupportSQLiteDatabase.insertWidgetsV4(widgets: List<FakeCommunalWidgetItemV4>) {
+        widgets.forEach { widget ->
+            execSQL(
+                "INSERT INTO communal_widget_table(" +
+                    "widget_id, " +
+                    "component_name, " +
+                    "item_id, " +
+                    "user_serial_number, " +
+                    "span_y) " +
+                    "VALUES(${widget.widgetId}, " +
+                    "'${widget.componentName}', " +
+                    "${widget.itemId}, " +
+                    "${widget.userSerialNumber}," +
+                    "${widget.spanY})"
+            )
+        }
+    }
+
     private fun SupportSQLiteDatabase.verifyWidgetsV1(widgets: List<FakeCommunalWidgetItemV1>) {
         val cursor = query("SELECT * FROM communal_widget_table")
         assertThat(cursor.moveToFirst()).isTrue()
@@ -270,6 +333,27 @@
         assertThat(cursor.isAfterLast).isTrue()
     }
 
+    private fun SupportSQLiteDatabase.verifyWidgetsV5(widgets: List<FakeCommunalWidgetItemV5>) {
+        val cursor = query("SELECT * FROM communal_widget_table")
+        assertThat(cursor.moveToFirst()).isTrue()
+
+        widgets.forEach { widget ->
+            assertThat(cursor.getInt(cursor.getColumnIndex("widget_id"))).isEqualTo(widget.widgetId)
+            assertThat(cursor.getString(cursor.getColumnIndex("component_name")))
+                .isEqualTo(widget.componentName)
+            assertThat(cursor.getInt(cursor.getColumnIndex("item_id"))).isEqualTo(widget.itemId)
+            assertThat(cursor.getInt(cursor.getColumnIndex("user_serial_number")))
+                .isEqualTo(widget.userSerialNumber)
+            assertThat(cursor.getInt(cursor.getColumnIndex("span_y"))).isEqualTo(widget.spanY)
+            assertThat(cursor.getInt(cursor.getColumnIndex("span_y_new")))
+                .isEqualTo(widget.spanYNew)
+
+            cursor.moveToNext()
+        }
+
+        assertThat(cursor.isAfterLast).isTrue()
+    }
+
     private fun SupportSQLiteDatabase.insertRanks(ranks: List<FakeCommunalItemRank>) {
         ranks.forEach { rank ->
             execSQL("INSERT INTO communal_item_rank_table(rank) VALUES(${rank.rank})")
@@ -334,6 +418,27 @@
         val spanY: Int,
     )
 
+    private fun FakeCommunalWidgetItemV4.getV5(): FakeCommunalWidgetItemV5 {
+        val spanYFixed = SpanValue.Fixed(spanY)
+        return FakeCommunalWidgetItemV5(
+            widgetId = widgetId,
+            componentName = componentName,
+            itemId = itemId,
+            userSerialNumber = userSerialNumber,
+            spanY = spanYFixed.value,
+            spanYNew = spanYFixed.toResponsive().value,
+        )
+    }
+
+    private data class FakeCommunalWidgetItemV5(
+        val widgetId: Int,
+        val componentName: String,
+        val itemId: Int,
+        val userSerialNumber: Int,
+        val spanY: Int,
+        val spanYNew: Int,
+    )
+
     private data class FakeCommunalItemRank(val rank: Int)
 
     companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/data/db/CommunalWidgetDaoTest.kt b/packages/SystemUI/tests/src/com/android/systemui/communal/data/db/CommunalWidgetDaoTest.kt
index 2312bbd..2acb775 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/communal/data/db/CommunalWidgetDaoTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/data/db/CommunalWidgetDaoTest.kt
@@ -22,7 +22,7 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.communal.nano.CommunalHubState
-import com.android.systemui.communal.shared.model.CommunalContentSize
+import com.android.systemui.communal.shared.model.SpanValue
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.lifecycle.InstantTaskExecutorRule
 import com.google.common.truth.Truth.assertThat
@@ -68,12 +68,13 @@
     @Test
     fun addWidget_readValueInDb() =
         testScope.runTest {
-            val (widgetId, provider, rank, userSerialNumber) = widgetInfo1
+            val (widgetId, provider, rank, userSerialNumber, spanY) = widgetInfo1
             communalWidgetDao.addWidget(
                 widgetId = widgetId,
                 provider = provider,
                 rank = rank,
                 userSerialNumber = userSerialNumber,
+                spanY = spanY,
             )
             val entry = communalWidgetDao.getWidgetByIdNow(id = 1)
             assertThat(entry).isEqualTo(communalWidgetItemEntry1)
@@ -82,12 +83,13 @@
     @Test
     fun deleteWidget_notInDb_returnsFalse() =
         testScope.runTest {
-            val (widgetId, provider, rank, userSerialNumber) = widgetInfo1
+            val (widgetId, provider, rank, userSerialNumber, spanY) = widgetInfo1
             communalWidgetDao.addWidget(
                 widgetId = widgetId,
                 provider = provider,
                 rank = rank,
                 userSerialNumber = userSerialNumber,
+                spanY = spanY,
             )
             assertThat(communalWidgetDao.deleteWidgetById(widgetId = 123)).isFalse()
         }
@@ -98,12 +100,13 @@
             val widgetsToAdd = listOf(widgetInfo1, widgetInfo2)
             val widgets = collectLastValue(communalWidgetDao.getWidgets())
             widgetsToAdd.forEach {
-                val (widgetId, provider, rank, userSerialNumber) = it
+                val (widgetId, provider, rank, userSerialNumber, spanY) = it
                 communalWidgetDao.addWidget(
                     widgetId = widgetId,
                     provider = provider,
                     rank = rank,
                     userSerialNumber = userSerialNumber,
+                    spanY = spanY,
                 )
             }
             assertThat(widgets())
@@ -126,11 +129,12 @@
             // Add widgets one by one without specifying rank
             val widgetsToAdd = listOf(widgetInfo1, widgetInfo2, widgetInfo3)
             widgetsToAdd.forEach {
-                val (widgetId, provider, _, userSerialNumber) = it
+                val (widgetId, provider, _, userSerialNumber, spanY) = it
                 communalWidgetDao.addWidget(
                     widgetId = widgetId,
                     provider = provider,
                     userSerialNumber = userSerialNumber,
+                    spanY = spanY,
                 )
             }
 
@@ -153,12 +157,13 @@
             val widgets = collectLastValue(communalWidgetDao.getWidgets())
 
             widgetsToAdd.forEach {
-                val (widgetId, provider, rank, userSerialNumber) = it
+                val (widgetId, provider, rank, userSerialNumber, spanY) = it
                 communalWidgetDao.addWidget(
                     widgetId = widgetId,
                     provider = provider,
                     rank = rank,
                     userSerialNumber = userSerialNumber,
+                    spanY = spanY,
                 )
             }
             assertThat(widgets())
@@ -180,12 +185,13 @@
             val widgets = collectLastValue(communalWidgetDao.getWidgets())
 
             widgetsToAdd.forEach {
-                val (widgetId, provider, rank, userSerialNumber) = it
+                val (widgetId, provider, rank, userSerialNumber, spanY) = it
                 communalWidgetDao.addWidget(
                     widgetId = widgetId,
                     provider = provider,
                     rank = rank,
                     userSerialNumber = userSerialNumber,
+                    spanY = spanY,
                 )
             }
             assertThat(widgets())
@@ -217,12 +223,13 @@
             val widgets = collectLastValue(communalWidgetDao.getWidgets())
 
             existingWidgets.forEach {
-                val (widgetId, provider, rank, userSerialNumber) = it
+                val (widgetId, provider, rank, userSerialNumber, spanY) = it
                 communalWidgetDao.addWidget(
                     widgetId = widgetId,
                     provider = provider,
                     rank = rank,
                     userSerialNumber = userSerialNumber,
+                    spanY = spanY,
                 )
             }
             assertThat(widgets())
@@ -242,6 +249,7 @@
                 provider = ComponentName("pk_name", "cls_name_4"),
                 rank = 1,
                 userSerialNumber = 0,
+                spanY = SpanValue.Responsive(1),
             )
 
             val newRankEntry = CommunalItemRank(uid = 4L, rank = 1)
@@ -253,6 +261,7 @@
                     itemId = 4L,
                     userSerialNumber = 0,
                     spanY = 3,
+                    spanYNew = 1,
                 )
             assertThat(widgets())
                 .containsExactly(
@@ -279,21 +288,21 @@
                 provider = ComponentName("pkg_name", "cls_name_1"),
                 rank = 0,
                 userSerialNumber = 0,
-                spanY = CommunalContentSize.FULL.span,
+                spanY = SpanValue.Responsive(1),
             )
             communalWidgetDao.addWidget(
                 widgetId = 2,
                 provider = ComponentName("pkg_name", "cls_name_2"),
                 rank = 1,
                 userSerialNumber = 0,
-                spanY = CommunalContentSize.HALF.span,
+                spanY = SpanValue.Responsive(2),
             )
             communalWidgetDao.addWidget(
                 widgetId = 3,
                 provider = ComponentName("pkg_name", "cls_name_3"),
                 rank = 2,
                 userSerialNumber = 0,
-                spanY = CommunalContentSize.THIRD.span,
+                spanY = SpanValue.Fixed(3),
             )
 
             // Verify that the widgets have the correct spanY values
@@ -306,7 +315,8 @@
                         componentName = "pkg_name/cls_name_1",
                         itemId = 1L,
                         userSerialNumber = 0,
-                        spanY = CommunalContentSize.FULL.span,
+                        spanY = 3,
+                        spanYNew = 1,
                     ),
                     CommunalItemRank(uid = 2L, rank = 1),
                     CommunalWidgetItem(
@@ -315,7 +325,8 @@
                         componentName = "pkg_name/cls_name_2",
                         itemId = 2L,
                         userSerialNumber = 0,
-                        spanY = CommunalContentSize.HALF.span,
+                        spanY = 6,
+                        spanYNew = 2,
                     ),
                     CommunalItemRank(uid = 3L, rank = 2),
                     CommunalWidgetItem(
@@ -324,7 +335,8 @@
                         componentName = "pkg_name/cls_name_3",
                         itemId = 3L,
                         userSerialNumber = 0,
-                        spanY = CommunalContentSize.THIRD.span,
+                        spanY = 3,
+                        spanYNew = 1,
                     ),
                 )
                 .inOrder()
@@ -352,7 +364,8 @@
                         componentName = fakeWidget.componentName,
                         itemId = rank.uid,
                         userSerialNumber = fakeWidget.userSerialNumber,
-                        spanY = 3,
+                        spanY = fakeWidget.spanY.coerceAtLeast(3),
+                        spanYNew = fakeWidget.spanYNew.coerceAtLeast(1),
                     )
                 expected[rank] = widget
             }
@@ -366,6 +379,7 @@
             provider = metadata.provider,
             rank = rank ?: metadata.rank,
             userSerialNumber = metadata.userSerialNumber,
+            spanY = metadata.spanY,
         )
     }
 
@@ -374,6 +388,7 @@
         val provider: ComponentName,
         val rank: Int,
         val userSerialNumber: Int,
+        val spanY: SpanValue,
     )
 
     companion object {
@@ -383,6 +398,7 @@
                 provider = ComponentName("pk_name", "cls_name_1"),
                 rank = 0,
                 userSerialNumber = 0,
+                spanY = SpanValue.Responsive(1),
             )
         val widgetInfo2 =
             FakeWidgetMetadata(
@@ -390,6 +406,7 @@
                 provider = ComponentName("pk_name", "cls_name_2"),
                 rank = 1,
                 userSerialNumber = 0,
+                spanY = SpanValue.Responsive(1),
             )
         val widgetInfo3 =
             FakeWidgetMetadata(
@@ -397,6 +414,7 @@
                 provider = ComponentName("pk_name", "cls_name_3"),
                 rank = 2,
                 userSerialNumber = 10,
+                spanY = SpanValue.Responsive(1),
             )
         val communalItemRankEntry1 = CommunalItemRank(uid = 1L, rank = widgetInfo1.rank)
         val communalItemRankEntry2 = CommunalItemRank(uid = 2L, rank = widgetInfo2.rank)
@@ -409,6 +427,7 @@
                 itemId = communalItemRankEntry1.uid,
                 userSerialNumber = widgetInfo1.userSerialNumber,
                 spanY = 3,
+                spanYNew = 1,
             )
         val communalWidgetItemEntry2 =
             CommunalWidgetItem(
@@ -418,6 +437,7 @@
                 itemId = communalItemRankEntry2.uid,
                 userSerialNumber = widgetInfo2.userSerialNumber,
                 spanY = 3,
+                spanYNew = 1,
             )
         val communalWidgetItemEntry3 =
             CommunalWidgetItem(
@@ -427,6 +447,7 @@
                 itemId = communalItemRankEntry3.uid,
                 userSerialNumber = widgetInfo3.userSerialNumber,
                 spanY = 3,
+                spanYNew = 1,
             )
         val fakeState =
             CommunalHubState().apply {
@@ -437,12 +458,14 @@
                                 componentName = "pk_name/fake_widget_1"
                                 rank = 1
                                 userSerialNumber = 0
+                                spanY = 3
                             },
                             CommunalHubState.CommunalWidgetItem().apply {
                                 widgetId = 2
                                 componentName = "pk_name/fake_widget_2"
                                 rank = 2
                                 userSerialNumber = 10
+                                spanYNew = 1
                             },
                         )
                         .toTypedArray()
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 d1e4f64..3e24fbe 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
@@ -68,6 +68,7 @@
 import com.android.systemui.statusbar.phone.StatusBarHideIconsForBouncerManager;
 import com.android.systemui.statusbar.phone.fragment.dagger.HomeStatusBarComponent;
 import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
+import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization;
 import com.android.systemui.statusbar.phone.ui.DarkIconManager;
 import com.android.systemui.statusbar.phone.ui.StatusBarIconController;
 import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.FakeHomeStatusBarViewBinder;
@@ -155,9 +156,9 @@
                 any(StatusBarWindowStateListener.class));
     }
 
-    @Test
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void testDisableNone() {
+  @Test
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void testDisableNone() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
@@ -166,9 +167,9 @@
         assertEquals(View.VISIBLE, getClockView().getVisibility());
     }
 
-    @Test
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void testDisableSystemInfo_systemAnimationIdle_doesHide() {
+  @Test
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void testDisableSystemInfo_systemAnimationIdle_doesHide() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_SYSTEM_INFO, 0, false);
@@ -184,9 +185,9 @@
         assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
     }
 
-    @Test
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void testSystemStatusAnimation_startedDisabled_finishedWithAnimator_showsSystemInfo() {
+  @Test
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void testSystemStatusAnimation_startedDisabled_finishedWithAnimator_showsSystemInfo() {
         // GIVEN the status bar hides the system info via disable flags, while there is no event
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
         fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_SYSTEM_INFO, 0, false);
@@ -214,9 +215,9 @@
         assertEquals(1, getEndSideContentView().getAlpha(), 0.01);
     }
 
-    @Test
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void testSystemStatusAnimation_systemInfoDisabled_staysInvisible() {
+  @Test
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void testSystemStatusAnimation_systemInfoDisabled_staysInvisible() {
         // GIVEN the status bar hides the system info via disable flags, while there is no event
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
         fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_SYSTEM_INFO, 0, false);
@@ -231,9 +232,9 @@
         assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
     }
 
-    @Test
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void testSystemStatusAnimation_notDisabled_animatesAlphaZero() {
+  @Test
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void testSystemStatusAnimation_notDisabled_animatesAlphaZero() {
         // GIVEN the status bar is not disabled
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
         assertEquals(1, getEndSideContentView().getAlpha(), 0.01);
@@ -247,9 +248,9 @@
         assertEquals(0, getEndSideContentView().getAlpha(), 0.01);
     }
 
-    @Test
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void testSystemStatusAnimation_notDisabled_animatesBackToAlphaOne() {
+  @Test
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void testSystemStatusAnimation_notDisabled_animatesBackToAlphaOne() {
         // GIVEN the status bar is not disabled
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
         assertEquals(1, getEndSideContentView().getAlpha(), 0.01);
@@ -271,9 +272,9 @@
         assertEquals(1, getEndSideContentView().getAlpha(), 0.01);
     }
 
-    @Test
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void testDisableNotifications() {
+  @Test
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void testDisableNotifications() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NOTIFICATION_ICONS, 0, false);
@@ -307,9 +308,9 @@
         assertEquals(View.VISIBLE, getNotificationAreaView().getVisibility());
     }
 
-    @Test
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void testDisableClock() {
+  @Test
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void testDisableClock() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_CLOCK, 0, false);
@@ -343,10 +344,10 @@
         assertEquals(View.VISIBLE, getClockView().getVisibility());
     }
 
-    @Test
-    @DisableSceneContainer
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void disable_shadeOpenAndShouldHide_everythingHidden() {
+  @Test
+  @DisableSceneContainer
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void disable_shadeOpenAndShouldHide_everythingHidden() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         // WHEN the shade is open and configured to hide the status bar icons
@@ -361,10 +362,10 @@
         assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
     }
 
-    @Test
-    @DisableSceneContainer
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void disable_shadeOpenButNotShouldHide_everythingShown() {
+  @Test
+  @DisableSceneContainer
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void disable_shadeOpenButNotShouldHide_everythingShown() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         // WHEN the shade is open but *not* configured to hide the status bar icons
@@ -379,11 +380,11 @@
         assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
     }
 
-    /** Regression test for b/279790651. */
-    @Test
-    @DisableSceneContainer
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void disable_shadeOpenAndShouldHide_thenShadeNotOpenAndDozingUpdate_everythingShown() {
+  /** Regression test for b/279790651. */
+  @Test
+  @DisableSceneContainer
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void disable_shadeOpenAndShouldHide_thenShadeNotOpenAndDozingUpdate_everythingShown() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         // WHEN the shade is open and configured to hide the status bar icons
@@ -409,9 +410,9 @@
         assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
     }
 
-    @Test
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void disable_notTransitioningToOccluded_everythingShown() {
+  @Test
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void disable_notTransitioningToOccluded_everythingShown() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         mCollapsedStatusBarViewModel.isTransitioningFromLockscreenToOccluded().setValue(false);
@@ -424,10 +425,10 @@
         assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
     }
 
-    @Test
-    @DisableSceneContainer
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void disable_isTransitioningToOccluded_everythingHidden() {
+  @Test
+  @DisableSceneContainer
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void disable_isTransitioningToOccluded_everythingHidden() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         mCollapsedStatusBarViewModel.isTransitioningFromLockscreenToOccluded().setValue(true);
@@ -440,10 +441,10 @@
         assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
     }
 
-    @Test
-    @DisableSceneContainer
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void disable_wasTransitioningToOccluded_transitionFinished_everythingShown() {
+  @Test
+  @DisableSceneContainer
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void disable_wasTransitioningToOccluded_transitionFinished_everythingShown() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         // WHEN the transition is occurring
@@ -472,9 +473,13 @@
         assertEquals(View.GONE, getUserChipView().getVisibility());
     }
 
-    @Test
-    @DisableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarRootModernization.FLAG_NAME})
-    public void disable_noOngoingCall_chipHidden() {
+  @Test
+  @DisableFlags({
+    FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS,
+    StatusBarRootModernization.FLAG_NAME,
+    StatusBarChipsModernization.FLAG_NAME
+  })
+  public void disable_noOngoingCall_chipHidden() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         when(mOngoingCallController.hasOngoingCall()).thenReturn(false);
@@ -484,9 +489,13 @@
         assertEquals(View.GONE, getPrimaryOngoingActivityChipView().getVisibility());
     }
 
-    @Test
-    @DisableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarRootModernization.FLAG_NAME})
-    public void disable_hasOngoingCall_chipDisplayedAndNotificationIconsHidden() {
+  @Test
+  @DisableFlags({
+    FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS,
+    StatusBarRootModernization.FLAG_NAME,
+    StatusBarChipsModernization.FLAG_NAME
+  })
+  public void disable_hasOngoingCall_chipDisplayedAndNotificationIconsHidden() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         when(mOngoingCallController.hasOngoingCall()).thenReturn(true);
@@ -497,9 +506,13 @@
         assertEquals(View.INVISIBLE, getNotificationAreaView().getVisibility());
     }
 
-    @Test
-    @DisableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarRootModernization.FLAG_NAME})
-    public void disable_hasOngoingCallButNotificationIconsDisabled_chipHidden() {
+  @Test
+  @DisableFlags({
+    FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS,
+    StatusBarRootModernization.FLAG_NAME,
+    StatusBarChipsModernization.FLAG_NAME
+  })
+  public void disable_hasOngoingCallButNotificationIconsDisabled_chipHidden() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         when(mOngoingCallController.hasOngoingCall()).thenReturn(true);
@@ -510,9 +523,13 @@
         assertEquals(View.GONE, getPrimaryOngoingActivityChipView().getVisibility());
     }
 
-    @Test
-    @DisableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarRootModernization.FLAG_NAME})
-    public void disable_hasOngoingCallButAlsoHun_chipHidden() {
+  @Test
+  @DisableFlags({
+    FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS,
+    StatusBarRootModernization.FLAG_NAME,
+    StatusBarChipsModernization.FLAG_NAME
+  })
+  public void disable_hasOngoingCallButAlsoHun_chipHidden() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         when(mOngoingCallController.hasOngoingCall()).thenReturn(true);
@@ -523,9 +540,13 @@
         assertEquals(View.GONE, getPrimaryOngoingActivityChipView().getVisibility());
     }
 
-    @Test
-    @DisableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarRootModernization.FLAG_NAME})
-    public void disable_ongoingCallEnded_chipHidden() {
+  @Test
+  @DisableFlags({
+    FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS,
+    StatusBarRootModernization.FLAG_NAME,
+    StatusBarChipsModernization.FLAG_NAME
+  })
+  public void disable_ongoingCallEnded_chipHidden() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         // Ongoing call started
@@ -547,9 +568,13 @@
         assertEquals(View.VISIBLE, getPrimaryOngoingActivityChipView().getVisibility());
     }
 
-    @Test
-    @DisableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarRootModernization.FLAG_NAME})
-    public void disable_hasOngoingCall_hidesNotifsWithoutAnimation() {
+  @Test
+  @DisableFlags({
+    FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS,
+    StatusBarRootModernization.FLAG_NAME,
+    StatusBarChipsModernization.FLAG_NAME
+  })
+  public void disable_hasOngoingCall_hidesNotifsWithoutAnimation() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
         // Enable animations for testing so that we can verify we still aren't animating
         fragment.enableAnimationsForTesting();
@@ -564,9 +589,13 @@
         assertEquals(View.INVISIBLE, getNotificationAreaView().getVisibility());
     }
 
-    @Test
-    @DisableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarRootModernization.FLAG_NAME})
-    public void screenSharingChipsDisabled_ignoresNewCallback() {
+  @Test
+  @DisableFlags({
+    FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS,
+    StatusBarRootModernization.FLAG_NAME,
+    StatusBarChipsModernization.FLAG_NAME
+  })
+  public void screenSharingChipsDisabled_ignoresNewCallback() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         // WHEN there *is* an ongoing call via old callback
@@ -597,10 +626,10 @@
         assertEquals(View.GONE, getSecondaryOngoingActivityChipView().getVisibility());
     }
 
-    @Test
-    @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void noOngoingActivity_chipHidden() {
+  @Test
+  @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void noOngoingActivity_chipHidden() {
         resumeAndGetFragment();
 
         // TODO(b/332662551): We *should* be able to just set a value on
@@ -615,10 +644,10 @@
         assertEquals(View.GONE, getPrimaryOngoingActivityChipView().getVisibility());
     }
 
-    @Test
-    @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void hasPrimaryOngoingActivity_primaryChipDisplayedAndNotificationIconsHidden() {
+  @Test
+  @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void hasPrimaryOngoingActivity_primaryChipDisplayedAndNotificationIconsHidden() {
         resumeAndGetFragment();
 
         mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
@@ -630,12 +659,14 @@
         assertEquals(View.INVISIBLE, getNotificationAreaView().getVisibility());
     }
 
-    @Test
-    @EnableFlags({
-            FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS,
-            StatusBarNotifChips.FLAG_NAME,
-            StatusBarRootModernization.FLAG_NAME})
-    public void hasPrimaryOngoingActivity_viewsUnchangedWhenRootModernizationFlagOn() {
+  @Test
+  @EnableFlags({
+    FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS,
+    StatusBarNotifChips.FLAG_NAME,
+    StatusBarRootModernization.FLAG_NAME,
+    StatusBarChipsModernization.FLAG_NAME
+  })
+  public void hasPrimaryOngoingActivity_viewsUnchangedWhenRootModernizationFlagOn() {
         resumeAndGetFragment();
 
         assertEquals(View.VISIBLE, getPrimaryOngoingActivityChipView().getVisibility());
@@ -658,10 +689,14 @@
         assertEquals(View.VISIBLE, getNotificationAreaView().getVisibility());
     }
 
-    @Test
-    @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
-    @DisableFlags({StatusBarNotifChips.FLAG_NAME, StatusBarRootModernization.FLAG_NAME})
-    public void hasSecondaryOngoingActivity_butNotifsFlagOff_secondaryChipHidden() {
+  @Test
+  @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
+  @DisableFlags({
+    StatusBarNotifChips.FLAG_NAME,
+    StatusBarRootModernization.FLAG_NAME,
+    StatusBarChipsModernization.FLAG_NAME
+  })
+  public void hasSecondaryOngoingActivity_butNotifsFlagOff_secondaryChipHidden() {
         resumeAndGetFragment();
 
         mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
@@ -672,10 +707,10 @@
         assertEquals(View.GONE, getSecondaryOngoingActivityChipView().getVisibility());
     }
 
-    @Test
-    @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void hasSecondaryOngoingActivity_flagOn_secondaryChipShownAndNotificationIconsHidden() {
+  @Test
+  @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void hasSecondaryOngoingActivity_flagOn_secondaryChipShownAndNotificationIconsHidden() {
         resumeAndGetFragment();
 
         mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
@@ -687,10 +722,14 @@
         assertEquals(View.INVISIBLE, getNotificationAreaView().getVisibility());
     }
 
-    @Test
-    @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
-    @DisableFlags({StatusBarNotifChips.FLAG_NAME, StatusBarRootModernization.FLAG_NAME})
-    public void hasOngoingActivityButNotificationIconsDisabled_chipHidden_notifsFlagOff() {
+  @Test
+  @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
+  @DisableFlags({
+    StatusBarNotifChips.FLAG_NAME,
+    StatusBarRootModernization.FLAG_NAME,
+    StatusBarChipsModernization.FLAG_NAME
+  })
+  public void hasOngoingActivityButNotificationIconsDisabled_chipHidden_notifsFlagOff() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
@@ -704,10 +743,10 @@
         assertEquals(View.GONE, getPrimaryOngoingActivityChipView().getVisibility());
     }
 
-    @Test
-    @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void hasOngoingActivitiesButNotificationIconsDisabled_chipsHidden_notifsFlagOn() {
+  @Test
+  @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void hasOngoingActivitiesButNotificationIconsDisabled_chipsHidden_notifsFlagOn() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
@@ -722,10 +761,14 @@
         assertEquals(View.GONE, getSecondaryOngoingActivityChipView().getVisibility());
     }
 
-    @Test
-    @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
-    @DisableFlags({StatusBarNotifChips.FLAG_NAME, StatusBarRootModernization.FLAG_NAME})
-    public void hasOngoingActivityButAlsoHun_chipHidden_notifsFlagOff() {
+  @Test
+  @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
+  @DisableFlags({
+    StatusBarNotifChips.FLAG_NAME,
+    StatusBarRootModernization.FLAG_NAME,
+    StatusBarChipsModernization.FLAG_NAME
+  })
+  public void hasOngoingActivityButAlsoHun_chipHidden_notifsFlagOff() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
@@ -739,10 +782,10 @@
         assertEquals(View.GONE, getPrimaryOngoingActivityChipView().getVisibility());
     }
 
-    @Test
-    @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void hasOngoingActivitiesButAlsoHun_chipsHidden_notifsFlagOn() {
+  @Test
+  @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void hasOngoingActivitiesButAlsoHun_chipsHidden_notifsFlagOn() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         mCollapsedStatusBarViewBinder.getListener().onOngoingActivityStatusChanged(
@@ -757,10 +800,14 @@
         assertEquals(View.GONE, getSecondaryOngoingActivityChipView().getVisibility());
     }
 
-    @Test
-    @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
-    @DisableFlags({StatusBarNotifChips.FLAG_NAME, StatusBarRootModernization.FLAG_NAME})
-    public void primaryOngoingActivityEnded_chipHidden_notifsFlagOff() {
+  @Test
+  @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
+  @DisableFlags({
+    StatusBarNotifChips.FLAG_NAME,
+    StatusBarRootModernization.FLAG_NAME,
+    StatusBarChipsModernization.FLAG_NAME
+  })
+  public void primaryOngoingActivityEnded_chipHidden_notifsFlagOff() {
         resumeAndGetFragment();
 
         // Ongoing activity started
@@ -780,10 +827,10 @@
         assertEquals(View.GONE, getPrimaryOngoingActivityChipView().getVisibility());
     }
 
-    @Test
-    @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void primaryOngoingActivityEnded_chipHidden_notifsFlagOn() {
+  @Test
+  @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void primaryOngoingActivityEnded_chipHidden_notifsFlagOn() {
         resumeAndGetFragment();
 
         // Ongoing activity started
@@ -803,10 +850,10 @@
         assertEquals(View.GONE, getPrimaryOngoingActivityChipView().getVisibility());
     }
 
-    @Test
-    @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void secondaryOngoingActivityEnded_chipHidden() {
+  @Test
+  @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void secondaryOngoingActivityEnded_chipHidden() {
         resumeAndGetFragment();
 
         // Secondary ongoing activity started
@@ -826,10 +873,14 @@
         assertEquals(View.GONE, getSecondaryOngoingActivityChipView().getVisibility());
     }
 
-    @Test
-    @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
-    @DisableFlags({StatusBarNotifChips.FLAG_NAME, StatusBarRootModernization.FLAG_NAME})
-    public void hasOngoingActivity_hidesNotifsWithoutAnimation_notifsFlagOff() {
+  @Test
+  @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
+  @DisableFlags({
+    StatusBarNotifChips.FLAG_NAME,
+    StatusBarRootModernization.FLAG_NAME,
+    StatusBarChipsModernization.FLAG_NAME
+  })
+  public void hasOngoingActivity_hidesNotifsWithoutAnimation_notifsFlagOff() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
         // Enable animations for testing so that we can verify we still aren't animating
         fragment.enableAnimationsForTesting();
@@ -845,10 +896,10 @@
         assertEquals(View.INVISIBLE, getNotificationAreaView().getVisibility());
     }
 
-    @Test
-    @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void hasOngoingActivity_hidesNotifsWithoutAnimation_notifsFlagOn() {
+  @Test
+  @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void hasOngoingActivity_hidesNotifsWithoutAnimation_notifsFlagOn() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
         // Enable animations for testing so that we can verify we still aren't animating
         fragment.enableAnimationsForTesting();
@@ -864,10 +915,14 @@
         assertEquals(View.INVISIBLE, getNotificationAreaView().getVisibility());
     }
 
-    @Test
-    @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
-    @DisableFlags({StatusBarNotifChips.FLAG_NAME, StatusBarRootModernization.FLAG_NAME})
-    public void screenSharingChipsEnabled_ignoresOngoingCallController_notifsFlagOff() {
+  @Test
+  @EnableFlags(FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS)
+  @DisableFlags({
+    StatusBarNotifChips.FLAG_NAME,
+    StatusBarRootModernization.FLAG_NAME,
+    StatusBarChipsModernization.FLAG_NAME
+  })
+  public void screenSharingChipsEnabled_ignoresOngoingCallController_notifsFlagOff() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         // WHEN there *is* an ongoing call via old callback
@@ -897,10 +952,10 @@
         assertEquals(View.VISIBLE, getPrimaryOngoingActivityChipView().getVisibility());
     }
 
-    @Test
-    @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void screenSharingChipsEnabled_ignoresOngoingCallController_notifsFlagOn() {
+  @Test
+  @EnableFlags({FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS, StatusBarNotifChips.FLAG_NAME})
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void screenSharingChipsEnabled_ignoresOngoingCallController_notifsFlagOn() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         // WHEN there *is* an ongoing call via old callback
@@ -931,10 +986,10 @@
         assertEquals(View.VISIBLE, getSecondaryOngoingActivityChipView().getVisibility());
     }
 
-    @Test
-    @EnableSceneContainer
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void isHomeStatusBarAllowedByScene_false_everythingHidden() {
+  @Test
+  @EnableSceneContainer
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void isHomeStatusBarAllowedByScene_false_everythingHidden() {
         resumeAndGetFragment();
 
         mCollapsedStatusBarViewBinder.getListener().onIsHomeStatusBarAllowedBySceneChanged(false);
@@ -945,10 +1000,10 @@
         assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
     }
 
-    @Test
-    @EnableSceneContainer
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void isHomeStatusBarAllowedByScene_true_everythingShown() {
+  @Test
+  @EnableSceneContainer
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void isHomeStatusBarAllowedByScene_true_everythingShown() {
         resumeAndGetFragment();
 
         mCollapsedStatusBarViewBinder.getListener().onIsHomeStatusBarAllowedBySceneChanged(true);
@@ -959,10 +1014,10 @@
         assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
     }
 
-    @Test
-    @EnableSceneContainer
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void disable_isHomeStatusBarAllowedBySceneFalse_disableValuesIgnored() {
+  @Test
+  @EnableSceneContainer
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void disable_isHomeStatusBarAllowedBySceneFalse_disableValuesIgnored() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         // WHEN the scene doesn't allow the status bar
@@ -977,10 +1032,10 @@
         assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
     }
 
-    @Test
-    @EnableSceneContainer
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void disable_isHomeStatusBarAllowedBySceneTrue_disableValuesUsed() {
+  @Test
+  @EnableSceneContainer
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void disable_isHomeStatusBarAllowedBySceneTrue_disableValuesUsed() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         // WHEN the scene does allow the status bar
@@ -995,10 +1050,10 @@
         assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
     }
 
-    @Test
-    @DisableSceneContainer
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void isHomeStatusBarAllowedByScene_sceneContainerDisabled_valueNotUsed() {
+  @Test
+  @DisableSceneContainer
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void isHomeStatusBarAllowedByScene_sceneContainerDisabled_valueNotUsed() {
         resumeAndGetFragment();
 
         // Even if the scene says to hide the home status bar
@@ -1010,9 +1065,9 @@
         assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
     }
 
-    @Test
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void disable_isDozing_clockAndSystemInfoVisible() {
+  @Test
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void disable_isDozing_clockAndSystemInfoVisible() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
         when(mStatusBarStateController.isDozing()).thenReturn(true);
 
@@ -1022,9 +1077,9 @@
         assertEquals(View.VISIBLE, getClockView().getVisibility());
     }
 
-    @Test
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void disable_NotDozing_clockAndSystemInfoVisible() {
+  @Test
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void disable_NotDozing_clockAndSystemInfoVisible() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
         when(mStatusBarStateController.isDozing()).thenReturn(false);
 
@@ -1034,9 +1089,9 @@
         assertEquals(View.VISIBLE, getClockView().getVisibility());
     }
 
-    @Test
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void disable_headsUpShouldBeVisibleTrue_clockDisabled() {
+  @Test
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void disable_headsUpShouldBeVisibleTrue_clockDisabled() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
         when(mHeadsUpAppearanceController.shouldBeVisible()).thenReturn(true);
 
@@ -1045,9 +1100,9 @@
         assertEquals(View.GONE, getClockView().getVisibility());
     }
 
-    @Test
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void disable_headsUpShouldBeVisibleFalse_clockNotDisabled() {
+  @Test
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void disable_headsUpShouldBeVisibleFalse_clockNotDisabled() {
         CollapsedStatusBarFragment fragment = resumeAndGetFragment();
         when(mHeadsUpAppearanceController.shouldBeVisible()).thenReturn(false);
 
@@ -1098,10 +1153,10 @@
         assertFalse(contains);
     }
 
-    @Test
-    @DisableSceneContainer
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void testStatusBarIcons_hiddenThroughoutCameraLaunch() {
+  @Test
+  @DisableSceneContainer
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void testStatusBarIcons_hiddenThroughoutCameraLaunch() {
         final CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         mockSecureCameraLaunch(fragment, true /* launched */);
@@ -1121,10 +1176,10 @@
         assertEquals(View.VISIBLE, getClockView().getVisibility());
     }
 
-    @Test
-    @DisableSceneContainer
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void testStatusBarIcons_hiddenThroughoutLockscreenToDreamTransition() {
+  @Test
+  @DisableSceneContainer
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void testStatusBarIcons_hiddenThroughoutLockscreenToDreamTransition() {
         final CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         // WHEN a transition to dream has started
@@ -1158,9 +1213,9 @@
         assertEquals(View.VISIBLE, getClockView().getVisibility());
     }
 
-    @Test
-    @DisableFlags(StatusBarRootModernization.FLAG_NAME)
-    public void testStatusBarIcons_lockscreenToDreamTransitionButNotDreaming_iconsVisible() {
+  @Test
+  @DisableFlags({StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME})
+  public void testStatusBarIcons_lockscreenToDreamTransitionButNotDreaming_iconsVisible() {
         final CollapsedStatusBarFragment fragment = resumeAndGetFragment();
 
         // WHEN a transition to dream has started but we're *not* dreaming
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
index 153a8be..3e44364 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
@@ -118,6 +118,7 @@
                     android.net.platform.flags.Flags.class,
                     android.os.Flags.class,
                     android.service.controls.flags.Flags.class,
+                    android.service.quickaccesswallet.Flags.class,
                     com.android.internal.telephony.flags.Flags.class,
                     com.android.server.notification.Flags.class,
                     com.android.systemui.Flags.class);
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalWidgetRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalWidgetRepository.kt
index 3b175853de7..1f7f3bc 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalWidgetRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalWidgetRepository.kt
@@ -55,7 +55,7 @@
         rank: Int = 0,
         category: Int = AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD,
         userId: Int = 0,
-        spanY: Int = CommunalContentSize.HALF.span,
+        spanY: Int = CommunalContentSize.FixedSize.HALF.span,
     ) {
         fakeDatabase[appWidgetId] =
             CommunalWidgetContentModel.Available(
@@ -87,7 +87,7 @@
                 componentName = ComponentName.unflattenFromString(componentName)!!,
                 icon = icon,
                 user = UserHandle(userId),
-                spanY = CommunalContentSize.HALF.span,
+                spanY = CommunalContentSize.FixedSize.HALF.span,
             )
         updateListFromDatabase()
     }
@@ -143,7 +143,7 @@
                 appWidgetId = id,
                 providerInfo = providerInfo,
                 rank = rank,
-                spanY = CommunalContentSize.HALF.span,
+                spanY = CommunalContentSize.FixedSize.HALF.span,
             )
         updateListFromDatabase()
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt
index 2bff0c6..1828da5 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/shortcut/KeyboardShortcutHelperKosmos.kt
@@ -160,6 +160,7 @@
 val Kosmos.shortcutHelperViewModel by
     Kosmos.Fixture {
         ShortcutHelperViewModel(
+            applicationContext,
             mockRoleManager,
             userTracker,
             applicationCoroutineScope,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorKosmos.kt
index ace1157..339210c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorKosmos.kt
@@ -38,8 +38,8 @@
             primaryBouncerInteractor = primaryBouncerInteractor,
             selectedUserInteractor = selectedUserInteractor,
             dismissCallbackRegistry = dismissCallbackRegistry,
-            trustRepository = trustRepository,
             alternateBouncerInteractor = alternateBouncerInteractor,
+            trustRepository = trustRepository,
             powerInteractor = powerInteractor,
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapterKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapterKosmos.kt
index a908765..de9f629 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapterKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapterKosmos.kt
@@ -18,6 +18,7 @@
 
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testDispatcher
 import com.android.systemui.util.mockito.mock
 
 val Kosmos.qsTileViewModelAdaperFactory by
@@ -28,6 +29,7 @@
                     applicationCoroutineScope,
                     mock(),
                     qsTileViewModel,
+                    testDispatcher,
                 )
             }
         }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractorKosmos.kt
index fcd14d8..d8d4d2b 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractorKosmos.kt
@@ -20,12 +20,14 @@
 import com.android.systemui.kosmos.applicationCoroutineScope
 import com.android.systemui.statusbar.chips.statusBarChipsLogger
 import com.android.systemui.statusbar.phone.ongoingcall.data.repository.ongoingCallRepository
+import com.android.systemui.statusbar.phone.ongoingcall.domain.interactor.ongoingCallInteractor
 
 val Kosmos.callChipInteractor: CallChipInteractor by
     Kosmos.Fixture {
         CallChipInteractor(
             scope = applicationCoroutineScope,
             repository = ongoingCallRepository,
+            ongoingCallInteractor = ongoingCallInteractor,
             logger = statusBarChipsLogger,
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/model/ActiveNotificationModelBuilder.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/model/ActiveNotificationModelBuilder.kt
index 2ec8016..c6ae15d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/model/ActiveNotificationModelBuilder.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/data/model/ActiveNotificationModelBuilder.kt
@@ -29,7 +29,6 @@
     key: String,
     groupKey: String? = null,
     whenTime: Long = 0L,
-    isPromoted: Boolean = false,
     isAmbient: Boolean = false,
     isRowDismissed: Boolean = false,
     isSilent: Boolean = false,
@@ -53,7 +52,6 @@
         key = key,
         groupKey = groupKey,
         whenTime = whenTime,
-        isPromoted = isPromoted,
         isAmbient = isAmbient,
         isRowDismissed = isRowDismissed,
         isSilent = isSilent,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractorKosmos.kt
index 067193f..f7acae9 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/domain/interactor/RenderNotificationListInteractorKosmos.kt
@@ -19,13 +19,8 @@
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.statusbar.notification.collection.provider.sectionStyleProvider
 import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
-import com.android.systemui.statusbar.notification.promoted.promotedNotificationsProvider
 
 val Kosmos.renderNotificationListInteractor by
     Kosmos.Fixture {
-        RenderNotificationListInteractor(
-            activeNotificationListRepository,
-            sectionStyleProvider,
-            promotedNotificationsProvider,
-        )
+        RenderNotificationListInteractor(activeNotificationListRepository, sectionStyleProvider)
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorKosmos.kt
new file mode 100644
index 0000000..51fb36f
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorKosmos.kt
@@ -0,0 +1,33 @@
+/*
+ * 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.phone.ongoingcall.domain.interactor
+
+import com.android.systemui.activity.data.repository.activityManagerRepository
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.log.logcatLogBuffer
+import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
+
+val Kosmos.ongoingCallInteractor: OngoingCallInteractor by
+    Kosmos.Fixture {
+      OngoingCallInteractor(
+          scope = applicationCoroutineScope,
+          activeNotificationsInteractor = activeNotificationsInteractor,
+          activityManagerRepository = activityManagerRepository,
+          logBuffer = logcatLogBuffer("OngoingCallInteractorKosmos"),
+      )
+    }
diff --git a/packages/Vcn/service-b/Android.bp b/packages/Vcn/service-b/Android.bp
index 26d8397..c1a1ee7 100644
--- a/packages/Vcn/service-b/Android.bp
+++ b/packages/Vcn/service-b/Android.bp
@@ -77,6 +77,7 @@
         "framework-connectivity-t-pre-jarjar",
         "framework-connectivity-b-pre-jarjar",
         "framework-wifi.stubs.module_lib",
+        "keepanno-annotations",
         "modules-utils-statemachine",
         "unsupportedappusage",
     ],
diff --git a/packages/Vcn/service-b/src/com/android/server/ConnectivityServiceInitializerB.java b/packages/Vcn/service-b/src/com/android/server/ConnectivityServiceInitializerB.java
new file mode 100644
index 0000000..02c8ce4
--- /dev/null
+++ b/packages/Vcn/service-b/src/com/android/server/ConnectivityServiceInitializerB.java
@@ -0,0 +1,60 @@
+/*
+ * 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.server;
+
+import android.content.Context;
+import android.util.Log;
+
+import com.android.tools.r8.keepanno.annotations.KeepItemKind;
+import com.android.tools.r8.keepanno.annotations.UsedByReflection;
+
+/**
+ * Service initializer for VCN. This is called by system server to create a new instance of
+ * VcnManagementService.
+ */
+// This class is reflectively invoked from SystemServer and ConnectivityServiceInitializer.
+// Without this annotation, this class will be treated as unused class and be removed during build
+// time.
+@UsedByReflection(kind = KeepItemKind.CLASS_AND_METHODS)
+public final class ConnectivityServiceInitializerB extends SystemService {
+    private static final String TAG = ConnectivityServiceInitializerB.class.getSimpleName();
+    private final VcnManagementService mVcnManagementService;
+
+    public ConnectivityServiceInitializerB(Context context) {
+        super(context);
+        mVcnManagementService = VcnManagementService.create(context);
+    }
+
+    @Override
+    public void onStart() {
+        if (mVcnManagementService != null) {
+            Log.i(TAG, "Registering " + Context.VCN_MANAGEMENT_SERVICE);
+            publishBinderService(
+                    Context.VCN_MANAGEMENT_SERVICE,
+                    mVcnManagementService,
+                    /* allowIsolated= */ false);
+        }
+    }
+
+    @Override
+    public void onBootPhase(int phase) {
+        if (mVcnManagementService != null && phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+            Log.i(TAG, "Starting " + Context.VCN_MANAGEMENT_SERVICE);
+            mVcnManagementService.systemReady();
+        }
+    }
+}
diff --git a/services/Android.bp b/services/Android.bp
index 225304f..fc0bb33 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -294,10 +294,6 @@
         "service-permission.stubs.system_server",
         "service-rkp.stubs.system_server",
         "service-sdksandbox.stubs.system_server",
-
-        // TODO: b/30242953 This is for accessing IVcnManagementService and
-        // can be removed VCN is in mainline
-        "framework-connectivity-b-pre-jarjar",
     ],
 
     soong_config_variables: {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index e50535f..5c1ad74 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1070,8 +1070,11 @@
                                         newValue, restoredFromSdk);
                             }
                         }
+                        // Currently in SUW, the user can't see gesture shortcut option as the
+                        // navigation system is set to button navigation. We'll rely on the
+                        // SettingsBackupAgent to restore the settings since we don't
+                        // need to merge an empty gesture target.
                         case Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
-                             Settings.Secure.ACCESSIBILITY_GESTURE_TARGETS,
                              Settings.Secure.ACCESSIBILITY_QS_TARGETS,
                              Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE ->
                                 restoreShortcutTargets(newValue,
@@ -2256,10 +2259,6 @@
         if (shortcutType == QUICK_SETTINGS && !android.view.accessibility.Flags.a11yQsShortcut()) {
             return;
         }
-        if (shortcutType == HARDWARE
-                && !android.view.accessibility.Flags.restoreA11yShortcutTargetService()) {
-            return;
-        }
 
         synchronized (mLock) {
             final AccessibilityUserState userState = getUserStateLocked(UserHandle.USER_SYSTEM);
@@ -2928,27 +2927,25 @@
         final String builderValue = builder.toString();
         final String settingValue = TextUtils.isEmpty(builderValue)
                 ? defaultEmptyString : builderValue;
-        if (android.view.accessibility.Flags.restoreA11yShortcutTargetService()) {
-            final String currentValue = Settings.Secure.getStringForUser(
-                    mContext.getContentResolver(), settingName, userId);
-            if (Objects.equals(settingValue, currentValue)) {
-                // This logic exists to fix a bug where AccessibilityManagerService was writing
-                // `null` to the ACCESSIBILITY_SHORTCUT_TARGET_SERVICE setting during early boot
-                // during setup, due to a race condition in package scanning making A11yMS think
-                // that the default service was not installed.
-                //
-                // Writing `null` was implicitly causing that Setting to have the default
-                // `DEFAULT_OVERRIDEABLE_BY_RESTORE` property, which was preventing B&R for that
-                // Setting altogether.
-                //
-                // The "quick fix" here is to not write `null` if the existing value is already
-                // `null`. The ideal fix would be use the Settings.Secure#putStringForUser overload
-                // that allows override-by-restore, but the full repercussions of using that here
-                // have not yet been evaluated.
-                // TODO: b/333457719 - Evaluate and fix AccessibilityManagerService's usage of
-                //  "overridable by restore" when writing secure settings.
-                return;
-            }
+        final String currentValue = Settings.Secure.getStringForUser(
+                mContext.getContentResolver(), settingName, userId);
+        if (Objects.equals(settingValue, currentValue)) {
+            // This logic exists to fix a bug where AccessibilityManagerService was writing
+            // `null` to the ACCESSIBILITY_SHORTCUT_TARGET_SERVICE setting during early boot
+            // during setup, due to a race condition in package scanning making A11yMS think
+            // that the default service was not installed.
+            //
+            // Writing `null` was implicitly causing that Setting to have the default
+            // `DEFAULT_OVERRIDEABLE_BY_RESTORE` property, which was preventing B&R for that
+            // Setting altogether.
+            //
+            // The "quick fix" here is to not write `null` if the existing value is already
+            // `null`. The ideal fix would be use the Settings.Secure#putStringForUser overload
+            // that allows override-by-restore, but the full repercussions of using that here
+            // have not yet been evaluated.
+            // TODO: b/333457719 - Evaluate and fix AccessibilityManagerService's usage of
+            //  "overridable by restore" when writing secure settings.
+            return;
         }
         final long identity = Binder.clearCallingIdentity();
         try {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index 8b870db..b7fd09f 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
@@ -832,20 +832,12 @@
                         != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
             }
 
-            boolean hasWindowIgnore = false;
             if (windowCount > 0) {
-                for (int i = 0; i < windowCount; i++) {
-                    final WindowInfo windowInfo = windows.get(i);
-                    final AccessibilityWindowInfo window;
-                    if (mTrackingWindows) {
-                        window = populateReportedWindowLocked(userId, windowInfo, oldWindowsById);
-                        if (window == null) {
-                            hasWindowIgnore = true;
-                        }
-                    } else {
-                        window = null;
-                    }
-                    if (window != null) {
+                if (mTrackingWindows) {
+                    for (int i = 0; i < windowCount; i++) {
+                        final WindowInfo windowInfo = windows.get(i);
+                        final AccessibilityWindowInfo window =
+                                populateReportedWindowLocked(userId, windowInfo, oldWindowsById);
 
                         // Flip layers in list to be consistent with AccessibilityService#getWindows
                         window.setLayer(windowCount - 1 - window.getLayer());
@@ -870,13 +862,6 @@
                     }
                 }
                 final int accessibilityWindowCount = mWindows.size();
-                // Re-order the window layer of all windows in the windows list because there's
-                // window not been added into the windows list.
-                if (hasWindowIgnore) {
-                    for (int i = 0; i < accessibilityWindowCount; i++) {
-                        mWindows.get(i).setLayer(accessibilityWindowCount - 1 - i);
-                    }
-                }
                 if (isTopFocusedDisplay) {
                     if (mTouchInteractionInProgress && activeWindowGone) {
                         mActiveWindowId = mTopFocusedWindowId;
diff --git a/services/autofill/features.aconfig b/services/autofill/features.aconfig
index 80e0e5d..b78d103 100644
--- a/services/autofill/features.aconfig
+++ b/services/autofill/features.aconfig
@@ -2,6 +2,13 @@
 container: "system"
 
 flag {
+  name: "autofill_session_destroyed"
+  namespace: "autofill"
+  description: "Guards against new metrics definitions introduced in W"
+  bug: "342676602"
+}
+
+flag {
   name: "autofill_w_metrics"
   namespace: "autofill"
   description: "Guards against new metrics definitions introduced in W"
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index cd4ace2..5cf96bf 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -61,6 +61,7 @@
 import android.service.autofill.FillEventHistory.Event;
 import android.service.autofill.FillEventHistory.Event.NoSaveReason;
 import android.service.autofill.FillResponse;
+import android.service.autofill.Flags;
 import android.service.autofill.IAutoFillService;
 import android.service.autofill.InlineSuggestionRenderService;
 import android.service.autofill.SaveInfo;
@@ -100,6 +101,7 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.Random;
+
 /**
  * Bridge between the {@code system_server}'s {@link AutofillManagerService} and the
  * app's {@link IAutoFillService} implementation.
@@ -748,6 +750,22 @@
     @GuardedBy("mLock")
     void removeSessionLocked(int sessionId) {
         mSessions.remove(sessionId);
+        if (Flags.autofillSessionDestroyed()) {
+            if (sVerbose) {
+                Slog.v(
+                        TAG,
+                        "removeSessionLocked(): removed " + sessionId);
+            }
+            RemoteFillService remoteService =
+                    new RemoteFillService(
+                            getContext(),
+                            mInfo.getServiceInfo().getComponentName(),
+                            mUserId,
+                            /* callbacks= */ null,
+                            mMaster.isInstantServiceAllowed(),
+                            /* credentialAutofillService= */ null);
+            remoteService.onSessionDestroyed(null);
+        }
     }
 
     /**
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index 07f5dcc..f1e8884 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -34,6 +34,7 @@
 import android.service.autofill.AutofillService;
 import android.service.autofill.ConvertCredentialRequest;
 import android.service.autofill.ConvertCredentialResponse;
+import android.service.autofill.FillEventHistory;
 import android.service.autofill.FillRequest;
 import android.service.autofill.FillResponse;
 import android.service.autofill.IAutoFillService;
@@ -497,6 +498,14 @@
                 }));
     }
 
+    public void onSessionDestroyed(@Nullable FillEventHistory history) {
+        boolean success = run(service -> {
+            service.onSessionDestroyed(history);
+        });
+
+        if (sVerbose) Slog.v(TAG, "called onSessionDestroyed(): " + success);
+    }
+
     void onSavedPasswordCountRequest(IResultReceiver receiver) {
         run(service -> service.onSavedPasswordCountRequest(receiver));
     }
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index a90b693..3025e2e 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -314,8 +314,6 @@
 
     private static final String SERIAL_ID_FILE = "serial_id";
 
-    private static final String SKIP_USER_FACING_PACKAGES = "backup_skip_user_facing_packages";
-
     private final @UserIdInt int mUserId;
     private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
     private final TransportManager mTransportManager;
@@ -3503,40 +3501,6 @@
         }
     }
 
-    /**
-     * We want to skip backup/restore of certain packages if 'backup_skip_user_facing_packages' is
-     * set to true in secure settings. See b/153940088 for details.
-     *
-     * TODO(b/154822946): Remove this logic in the next release.
-     */
-    public List<PackageInfo> filterUserFacingPackages(List<PackageInfo> packages) {
-        if (!shouldSkipUserFacingData()) {
-            return packages;
-        }
-
-        List<PackageInfo> filteredPackages = new ArrayList<>(packages.size());
-        for (PackageInfo packageInfo : packages)  {
-            if (!shouldSkipPackage(packageInfo.packageName)) {
-                filteredPackages.add(packageInfo);
-            } else {
-                Slog.i(TAG, "Will skip backup/restore for " + packageInfo.packageName);
-            }
-        }
-
-        return filteredPackages;
-    }
-
-    @VisibleForTesting
-    public boolean shouldSkipUserFacingData() {
-        return Settings.Secure.getInt(mContext.getContentResolver(), SKIP_USER_FACING_PACKAGES,
-                /* def */ 0) != 0;
-    }
-
-    @VisibleForTesting
-    public boolean shouldSkipPackage(String packageName) {
-        return WALLPAPER_PACKAGE.equals(packageName);
-    }
-
     private void updateStateForTransport(String newTransportName) {
         // Publish the name change
         Settings.Secure.putStringForUser(mContext.getContentResolver(),
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
index 7994948..990c941 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
@@ -272,8 +272,6 @@
             }
         }
 
-        mPackages = backupManagerService.filterUserFacingPackages(mPackages);
-
         Set<String> packageNames = Sets.newHashSet();
         for (PackageInfo pkgInfo : mPackages) {
             packageNames.add(pkgInfo.packageName);
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index dad84c8..ec9d340 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -315,8 +315,6 @@
             }
         }
 
-        mAcceptSet = backupManagerService.filterUserFacingPackages(mAcceptSet);
-
         if (MORE_DEBUG) {
             Slog.v(TAG, "Restore; accept set size is " + mAcceptSet.size());
             for (PackageInfo info : mAcceptSet) {
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 0820615..ffa259b 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -221,6 +221,7 @@
         "securebox",
         "apache-commons-math",
         "battery_saver_flag_lib",
+        "guava",
         "notification_flags_lib",
         "power_hint_flags_lib",
         "biometrics_flags_lib",
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 43774bb..b0dae6a 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -90,6 +90,7 @@
      */
     public static final int RESOLVE_NON_RESOLVER_ONLY = 0x00000002;
 
+    @Deprecated
     @IntDef(value = {
             INTEGRITY_VERIFICATION_ALLOW,
             INTEGRITY_VERIFICATION_REJECT,
@@ -97,18 +98,10 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface IntegrityVerificationResult {}
 
-    /**
-     * Used as the {@code verificationCode} argument for
-     * {@link PackageManagerInternal#setIntegrityVerificationResult(int, int)} to indicate that the
-     * integrity component allows the install to proceed.
-     */
+    @Deprecated
     public static final int INTEGRITY_VERIFICATION_ALLOW = 1;
 
-    /**
-     * Used as the {@code verificationCode} argument for
-     * {@link PackageManagerInternal#setIntegrityVerificationResult(int, int)} to indicate that the
-     * integrity component does not allow install to proceed.
-     */
+    @Deprecated
     public static final int INTEGRITY_VERIFICATION_REJECT = 0;
 
     /**
@@ -1131,17 +1124,13 @@
     public abstract boolean isPermissionUpgradeNeeded(@UserIdInt int userId);
 
     /**
-     * Allows the integrity component to respond to the
-     * {@link Intent#ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION package verification
-     * broadcast} to respond to the package manager. The response must include
-     * the {@code verificationCode} which is one of
-     * {@link #INTEGRITY_VERIFICATION_ALLOW} and {@link #INTEGRITY_VERIFICATION_REJECT}.
+     * Used to allow the integrity component to respond to the
+     * ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION package verification
+     * broadcast to respond to the package manager.
      *
-     * @param verificationId pending package identifier as passed via the
-     *            {@link PackageManager#EXTRA_VERIFICATION_ID} Intent extra.
-     * @param verificationResult either {@link #INTEGRITY_VERIFICATION_ALLOW}
-     *            or {@link #INTEGRITY_VERIFICATION_REJECT}.
+     * Deprecated.
      */
+    @Deprecated
     public abstract void setIntegrityVerificationResult(int verificationId,
             @IntegrityVerificationResult int verificationResult);
 
diff --git a/services/core/java/com/android/server/DockObserver.java b/services/core/java/com/android/server/DockObserver.java
index fb527c1..2412b01 100644
--- a/services/core/java/com/android/server/DockObserver.java
+++ b/services/core/java/com/android/server/DockObserver.java
@@ -19,6 +19,7 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.media.AudioManager;
 import android.media.Ringtone;
@@ -35,6 +36,7 @@
 import android.util.Pair;
 import android.util.Slog;
 
+import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FrameworkStatsLog;
@@ -259,11 +261,19 @@
                     + mReportedDockState);
             final int previousDockState = mPreviousDockState;
             mPreviousDockState = mReportedDockState;
-            // Skip the dock intent if not yet provisioned.
+
             final ContentResolver cr = getContext().getContentResolver();
-            if (!mDeviceProvisionedObserver.isDeviceProvisioned()) {
-                Slog.i(TAG, "Device not provisioned, skipping dock broadcast");
-                return;
+
+            /// If the allow dock rotation before provision is enabled then we allow rotation.
+            final Resources r = getContext().getResources();
+            final boolean allowDockBeforeProvision =
+                    r.getBoolean(R.bool.config_allowDockBeforeProvision);
+            if (!allowDockBeforeProvision) {
+                // Skip the dock intent if not yet provisioned.
+                if (!mDeviceProvisionedObserver.isDeviceProvisioned()) {
+                    Slog.i(TAG, "Device not provisioned, skipping dock broadcast");
+                    return;
+                }
             }
 
             // Pack up the values and broadcast them to everyone
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index d13dd2f..896c9b8 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -885,8 +885,6 @@
                                 ? customModeType
                                 : MODE_NIGHT_CUSTOM_TYPE_UNKNOWN;
                         mNightMode.set(mode);
-                        //deactivates AttentionMode if user toggles DarkTheme
-                        mAttentionModeThemeOverlay = MODE_ATTENTION_THEME_OVERLAY_OFF;
                         resetNightModeOverrideLocked();
                         persistNightMode(user);
                         // on screen off will update configuration instead
@@ -1009,15 +1007,16 @@
 
         @Override
         public boolean setNightModeActivatedForCustomMode(int modeNightCustomType, boolean active) {
-            return setNightModeActivatedForModeInternal(modeNightCustomType, active);
+            return setNightModeActivatedForModeInternal(modeNightCustomType, active, false);
         }
 
         @Override
         public boolean setNightModeActivated(boolean active) {
-            return setNightModeActivatedForModeInternal(mNightModeCustomType, active);
+            return setNightModeActivatedForModeInternal(mNightModeCustomType, active, true);
         }
 
-        private boolean setNightModeActivatedForModeInternal(int modeCustomType, boolean active) {
+        private boolean setNightModeActivatedForModeInternal(int modeCustomType,
+            boolean active, boolean isUserInteraction) {
             if (getContext().checkCallingOrSelfPermission(
                     android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)
                     != PackageManager.PERMISSION_GRANTED) {
@@ -1053,13 +1052,16 @@
                         mOverrideNightModeOn = active;
                         mOverrideNightModeUser = mCurrentUser;
                         persistNightModeOverrides(mCurrentUser);
-                    } else if (mNightMode.get() == UiModeManager.MODE_NIGHT_NO
-                            && active) {
+                    } else if (mNightMode.get() == UiModeManager.MODE_NIGHT_NO && active) {
                         mNightMode.set(UiModeManager.MODE_NIGHT_YES);
-                    } else if (mNightMode.get() == UiModeManager.MODE_NIGHT_YES
-                            && !active) {
+                    } else if (mNightMode.get() == UiModeManager.MODE_NIGHT_YES && !active) {
                         mNightMode.set(UiModeManager.MODE_NIGHT_NO);
                     }
+
+                    if (isUserInteraction) {
+                        // deactivates AttentionMode if user toggles DarkTheme
+                        mAttentionModeThemeOverlay = MODE_ATTENTION_THEME_OVERLAY_OFF;
+                    }
                     updateConfigurationLocked();
                     applyConfigurationExternallyLocked();
                     persistNightMode(mCurrentUser);
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 400ebfd..c27126a 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -1251,12 +1251,10 @@
         }
 
         private static float clampPowerMah(double powerMah, String consumer) {
-            float resultPowerMah = 0;
-            if (powerMah <= Float.MAX_VALUE && powerMah >= Float.MIN_VALUE) {
-                resultPowerMah = (float) powerMah;
-            } else {
-                // Handle overflow appropriately
-                Slog.wtfStack(TAG, consumer + " reported powerMah float overflow: " + powerMah);
+            float resultPowerMah = Double.valueOf(powerMah).floatValue();
+            if (Float.isInfinite(resultPowerMah)) {
+                resultPowerMah = 0;
+                Slog.d(TAG, consumer + " reported powerMah float overflow : " + powerMah);
             }
             return resultPowerMah;
         }
@@ -1361,11 +1359,10 @@
 
             final String powerComponentName = batteryConsumer.getPowerComponentName(componentId);
             final double consumedPowerMah = batteryConsumer.getConsumedPower(key);
-            float powerMah =
+            final float powerMah =
                     clampPowerMah(
-                            consumedPowerMah, "uidConsumer-" + uid + "-" + powerComponentName);
+                            consumedPowerMah, "uid-" + uid + "-" + powerComponentName);
             final long powerComponentDurationMillis = batteryConsumer.getUsageDurationMillis(key);
-
             if (powerMah == 0 && powerComponentDurationMillis == 0) {
                 return true;
             }
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 06c586f..295e044 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -3191,7 +3191,7 @@
                     resolveProxyPackageName, proxyAttributionTag, proxyVirtualDeviceId,
                     Process.INVALID_UID, null, null,
                     Context.DEVICE_ID_DEFAULT, proxyFlags, !isProxyTrusted,
-                    "proxy " + message, shouldCollectMessage);
+                    "proxy " + message, shouldCollectMessage, 1);
             if (proxyReturn.getOpMode() != AppOpsManager.MODE_ALLOWED) {
                 return new SyncNotedAppOp(proxyReturn.getOpMode(), code, proxiedAttributionTag,
                         proxiedPackageName);
@@ -3210,7 +3210,20 @@
         return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
                 proxiedAttributionTag, proxiedVirtualDeviceId, proxyUid, resolveProxyPackageName,
                 proxyAttributionTag, proxyVirtualDeviceId, proxiedFlags, shouldCollectAsyncNotedOp,
-                message, shouldCollectMessage);
+                message, shouldCollectMessage, 1);
+    }
+
+    @Override
+    public void noteOperationsInBatch(Map batchedNoteOps) {
+        for (var entry : ((Map<AppOpsManager.NotedOp, Integer>) batchedNoteOps).entrySet()) {
+            AppOpsManager.NotedOp notedOp = entry.getKey();
+            int notedCount = entry.getValue();
+            mCheckOpsDelegateDispatcher.noteOperation(
+                    notedOp.getOp(), notedOp.getUid(), notedOp.getPackageName(),
+                    notedOp.getAttributionTag(), notedOp.getVirtualDeviceId(),
+                    notedOp.getShouldCollectAsyncNotedOp(), notedOp.getMessage(),
+                    notedOp.getShouldCollectMessage(), notedCount);
+        }
     }
 
     @Override
@@ -3228,7 +3241,7 @@
         }
         return mCheckOpsDelegateDispatcher.noteOperation(code, uid, packageName,
                 attributionTag, Context.DEVICE_ID_DEFAULT, shouldCollectAsyncNotedOp, message,
-                shouldCollectMessage);
+                shouldCollectMessage, 1);
     }
 
     @Override
@@ -3237,13 +3250,12 @@
             String message, boolean shouldCollectMessage) {
         return mCheckOpsDelegateDispatcher.noteOperation(code, uid, packageName,
                 attributionTag, virtualDeviceId, shouldCollectAsyncNotedOp, message,
-                shouldCollectMessage);
+                shouldCollectMessage, 1);
     }
 
     private SyncNotedAppOp noteOperationImpl(int code, int uid, @Nullable String packageName,
-             @Nullable String attributionTag, int virtualDeviceId,
-             boolean shouldCollectAsyncNotedOp, @Nullable String message,
-             boolean shouldCollectMessage) {
+            @Nullable String attributionTag, int virtualDeviceId, boolean shouldCollectAsyncNotedOp,
+            @Nullable String message, boolean shouldCollectMessage, int notedCount) {
         String resolvedPackageName;
         if (!shouldUseNewCheckOp()) {
             verifyIncomingUid(uid);
@@ -3278,14 +3290,14 @@
         return noteOperationUnchecked(code, uid, resolvedPackageName, attributionTag,
                 virtualDeviceId, Process.INVALID_UID, null, null,
                 Context.DEVICE_ID_DEFAULT, AppOpsManager.OP_FLAG_SELF, shouldCollectAsyncNotedOp,
-                message, shouldCollectMessage);
+                message, shouldCollectMessage, notedCount);
     }
 
     private SyncNotedAppOp noteOperationUnchecked(int code, int uid, @NonNull String packageName,
             @Nullable String attributionTag, int virtualDeviceId, int proxyUid,
             String proxyPackageName, @Nullable String proxyAttributionTag, int proxyVirtualDeviceId,
             @OpFlags int flags, boolean shouldCollectAsyncNotedOp, @Nullable String message,
-            boolean shouldCollectMessage) {
+            boolean shouldCollectMessage, int notedCount) {
         PackageVerificationResult pvr;
         try {
             pvr = verifyAndGetBypass(uid, packageName, attributionTag, proxyPackageName);
@@ -3388,11 +3400,11 @@
                     virtualDeviceId, flags, AppOpsManager.MODE_ALLOWED);
 
             attributedOp.accessed(proxyUid, proxyPackageName, proxyAttributionTag,
-                    getPersistentId(proxyVirtualDeviceId), uidState.getState(), flags);
+                    getPersistentId(proxyVirtualDeviceId), uidState.getState(), flags, notedCount);
 
             if (shouldCollectAsyncNotedOp) {
                 collectAsyncNotedOp(uid, packageName, code, attributionTag, flags, message,
-                        shouldCollectMessage);
+                        shouldCollectMessage, notedCount);
             }
 
             return new SyncNotedAppOp(AppOpsManager.MODE_ALLOWED, code, attributionTag,
@@ -3551,7 +3563,7 @@
      */
     private void collectAsyncNotedOp(int uid, @NonNull String packageName, int opCode,
             @Nullable String attributionTag, @OpFlags int flags, @NonNull String message,
-            boolean shouldCollectMessage) {
+            boolean shouldCollectMessage, int notedCount) {
         Objects.requireNonNull(message);
 
         int callingUid = Binder.getCallingUid();
@@ -3559,42 +3571,51 @@
         final long token = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
-                Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
-
-                RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
-                AsyncNotedAppOp asyncNotedOp = new AsyncNotedAppOp(opCode, callingUid,
-                        attributionTag, message, System.currentTimeMillis());
-                final boolean[] wasNoteForwarded = {false};
-
                 if ((flags & (OP_FLAG_SELF | OP_FLAG_TRUSTED_PROXIED)) != 0
                         && shouldCollectMessage) {
                     reportRuntimeAppOpAccessMessageAsyncLocked(uid, packageName, opCode,
                             attributionTag, message);
                 }
 
-                if (callbacks != null) {
+                Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
+                RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
+                if (callbacks == null) {
+                    return;
+                }
+
+                final boolean[] wasNoteForwarded = {false};
+                if (Flags.rateLimitBatchedNoteOpAsyncCallbacksEnabled()) {
+                    notedCount = 1;
+                }
+
+                for (int i = 0; i < notedCount; i++) {
+                    AsyncNotedAppOp asyncNotedOp = new AsyncNotedAppOp(opCode, callingUid,
+                            attributionTag, message, System.currentTimeMillis());
+                    wasNoteForwarded[0] = false;
                     callbacks.broadcast((cb) -> {
                         try {
                             cb.opNoted(asyncNotedOp);
                             wasNoteForwarded[0] = true;
                         } catch (RemoteException e) {
                             Slog.e(TAG,
-                                    "Could not forward noteOp of " + opCode + " to " + packageName
+                                    "Could not forward noteOp of " + opCode + " to "
+                                            + packageName
                                             + "/" + uid + "(" + attributionTag + ")", e);
                         }
                     });
-                }
 
-                if (!wasNoteForwarded[0]) {
-                    ArrayList<AsyncNotedAppOp> unforwardedOps = mUnforwardedAsyncNotedOps.get(key);
-                    if (unforwardedOps == null) {
-                        unforwardedOps = new ArrayList<>(1);
-                        mUnforwardedAsyncNotedOps.put(key, unforwardedOps);
-                    }
+                    if (!wasNoteForwarded[0]) {
+                        ArrayList<AsyncNotedAppOp> unforwardedOps = mUnforwardedAsyncNotedOps.get(
+                                key);
+                        if (unforwardedOps == null) {
+                            unforwardedOps = new ArrayList<>(1);
+                            mUnforwardedAsyncNotedOps.put(key, unforwardedOps);
+                        }
 
-                    unforwardedOps.add(asyncNotedOp);
-                    if (unforwardedOps.size() > MAX_UNFORWARDED_OPS) {
-                        unforwardedOps.remove(0);
+                        unforwardedOps.add(asyncNotedOp);
+                        if (unforwardedOps.size() > MAX_UNFORWARDED_OPS) {
+                            unforwardedOps.remove(0);
+                        }
                     }
                 }
             }
@@ -4026,7 +4047,7 @@
 
         if (shouldCollectAsyncNotedOp && !isRestricted) {
             collectAsyncNotedOp(uid, packageName, code, attributionTag, AppOpsManager.OP_FLAG_SELF,
-                    message, shouldCollectMessage);
+                    message, shouldCollectMessage, 1);
         }
 
         return new SyncNotedAppOp(isRestricted ? MODE_IGNORED : MODE_ALLOWED, code, attributionTag,
@@ -7574,34 +7595,36 @@
 
         public SyncNotedAppOp noteOperation(int code, int uid, String packageName,
                 String attributionTag, int virtualDeviceId, boolean shouldCollectAsyncNotedOp,
-                String message, boolean shouldCollectMessage) {
+                String message, boolean shouldCollectMessage, int notedCount) {
             if (mPolicy != null) {
                 if (mCheckOpsDelegate != null) {
                     return mPolicy.noteOperation(code, uid, packageName, attributionTag,
                             virtualDeviceId, shouldCollectAsyncNotedOp, message,
-                            shouldCollectMessage, this::noteDelegateOperationImpl
+                            shouldCollectMessage, notedCount, this::noteDelegateOperationImpl
                     );
                 } else {
                     return mPolicy.noteOperation(code, uid, packageName, attributionTag,
                             virtualDeviceId, shouldCollectAsyncNotedOp, message,
-                            shouldCollectMessage, AppOpsService.this::noteOperationImpl
+                            shouldCollectMessage, notedCount, AppOpsService.this::noteOperationImpl
                     );
                 }
             } else if (mCheckOpsDelegate != null) {
                 return noteDelegateOperationImpl(code, uid, packageName, attributionTag,
-                        virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage);
+                        virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
+                        notedCount);
             }
             return noteOperationImpl(code, uid, packageName, attributionTag,
-                    virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage);
+                    virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
+                    notedCount);
         }
 
         private SyncNotedAppOp noteDelegateOperationImpl(int code, int uid,
                 @Nullable String packageName, @Nullable String featureId, int virtualDeviceId,
                 boolean shouldCollectAsyncNotedOp, @Nullable String message,
-                boolean shouldCollectMessage) {
+                boolean shouldCollectMessage, int notedCount) {
             return mCheckOpsDelegate.noteOperation(code, uid, packageName, featureId,
                     virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
-                    AppOpsService.this::noteOperationImpl
+                    notedCount, AppOpsService.this::noteOperationImpl
             );
         }
 
diff --git a/services/core/java/com/android/server/appop/AttributedOp.java b/services/core/java/com/android/server/appop/AttributedOp.java
index 314664b..4d114b4 100644
--- a/services/core/java/com/android/server/appop/AttributedOp.java
+++ b/services/core/java/com/android/server/appop/AttributedOp.java
@@ -100,10 +100,12 @@
      * @param proxyDeviceId       The device Id of the proxy
      * @param uidState            UID state of the app noteOp/startOp was called for
      * @param flags               OpFlags of the call
+     * @param accessCount         The number of times the op is accessed
      */
     public void accessed(int proxyUid, @Nullable String proxyPackageName,
             @Nullable String proxyAttributionTag, @Nullable String proxyDeviceId,
-            @AppOpsManager.UidState int uidState, @AppOpsManager.OpFlags int flags) {
+            @AppOpsManager.UidState int uidState, @AppOpsManager.OpFlags int flags,
+            int accessCount) {
         long accessTime = System.currentTimeMillis();
         accessed(accessTime, -1, proxyUid, proxyPackageName, proxyAttributionTag, proxyDeviceId,
                 uidState, flags);
@@ -111,7 +113,7 @@
         mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid,
                 parent.packageName, persistentDeviceId, tag, uidState, flags, accessTime,
                 AppOpsManager.ATTRIBUTION_FLAGS_NONE, AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE,
-                DiscreteRegistry.ACCESS_TYPE_NOTE_OP);
+                DiscreteRegistry.ACCESS_TYPE_NOTE_OP, accessCount);
     }
 
     /**
@@ -255,7 +257,7 @@
         if (isStarted) {
             mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid,
                     parent.packageName, persistentDeviceId, tag, uidState, flags, startTime,
-                    attributionFlags, attributionChainId, DiscreteRegistry.ACCESS_TYPE_START_OP);
+                    attributionFlags, attributionChainId, DiscreteRegistry.ACCESS_TYPE_START_OP, 1);
         }
     }
 
@@ -451,7 +453,7 @@
             mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid,
                     parent.packageName, persistentDeviceId, tag, event.getUidState(),
                     event.getFlags(), startTime, event.getAttributionFlags(),
-                    event.getAttributionChainId(), DiscreteRegistry.ACCESS_TYPE_RESUME_OP);
+                    event.getAttributionChainId(), DiscreteRegistry.ACCESS_TYPE_RESUME_OP, 1);
             if (shouldSendActive) {
                 mAppOpsService.scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid,
                         parent.packageName, tag, event.getVirtualDeviceId(), true,
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index 6b02538..5e67f26 100644
--- a/services/core/java/com/android/server/appop/HistoricalRegistry.java
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -475,7 +475,7 @@
             @NonNull String deviceId, @Nullable String attributionTag, @UidState int uidState,
             @OpFlags int flags, long accessTime,
             @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId,
-            @DiscreteRegistry.AccessType int accessType) {
+            @DiscreteRegistry.AccessType int accessType, int accessCount) {
         synchronized (mInMemoryLock) {
             if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
                 if (!isPersistenceInitializedMLocked()) {
@@ -484,7 +484,7 @@
                 }
                 getUpdatedPendingHistoricalOpsMLocked(
                         System.currentTimeMillis()).increaseAccessCount(op, uid, packageName,
-                        attributionTag, uidState, flags, 1);
+                        attributionTag, uidState, flags, accessCount);
 
                 mDiscreteRegistry.recordDiscreteAccess(uid, packageName, deviceId, op,
                         attributionTag, flags, uidState, accessTime, -1, attributionFlags,
diff --git a/services/core/java/com/android/server/audio/AudioServerPermissionProvider.java b/services/core/java/com/android/server/audio/AudioServerPermissionProvider.java
index 4736918..7502664 100644
--- a/services/core/java/com/android/server/audio/AudioServerPermissionProvider.java
+++ b/services/core/java/com/android/server/audio/AudioServerPermissionProvider.java
@@ -27,6 +27,7 @@
 import static android.Manifest.permission.BYPASS_CONCURRENT_RECORD_AUDIO_RESTRICTION;
 import static android.Manifest.permission.MODIFY_AUDIO_ROUTING;
 import static android.Manifest.permission.MODIFY_AUDIO_SETTINGS;
+import static android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED;
 import static android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS;
 import static android.Manifest.permission.MODIFY_PHONE_STATE;
 import static android.Manifest.permission.RECORD_AUDIO;
@@ -84,6 +85,8 @@
         MONITORED_PERMS[PermissionEnum.BLUETOOTH_CONNECT] = BLUETOOTH_CONNECT;
         MONITORED_PERMS[PermissionEnum.BYPASS_CONCURRENT_RECORD_AUDIO_RESTRICTION] =
                 BYPASS_CONCURRENT_RECORD_AUDIO_RESTRICTION;
+        MONITORED_PERMS[PermissionEnum.MODIFY_AUDIO_SETTINGS_PRIVILEGED] =
+                MODIFY_AUDIO_SETTINGS_PRIVILEGED;
     }
 
     private final Object mLock = new Object();
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index a132876b..0914b7e 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -93,29 +93,6 @@
         mContext = context;
         mPackageManagerInternal = packageManagerInternal;
         mHandler = handler;
-
-        IntentFilter integrityVerificationFilter = new IntentFilter();
-        integrityVerificationFilter.addAction(ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION);
-        try {
-            integrityVerificationFilter.addDataType(PACKAGE_MIME_TYPE);
-        } catch (IntentFilter.MalformedMimeTypeException e) {
-            throw new RuntimeException("Mime type malformed: should never happen.", e);
-        }
-
-        mContext.registerReceiver(
-                new BroadcastReceiver() {
-                    @Override
-                    public void onReceive(Context context, Intent intent) {
-                        if (!ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION.equals(
-                                intent.getAction())) {
-                            return;
-                        }
-                        mHandler.post(() -> handleIntegrityVerification(intent));
-                    }
-                },
-                integrityVerificationFilter,
-                /* broadcastPermission= */ null,
-                mHandler);
     }
 
     @Override
@@ -157,10 +134,4 @@
     public List<String> getWhitelistedRuleProviders() {
         return Collections.emptyList();
     }
-
-    private void handleIntegrityVerification(Intent intent) {
-        int verificationId = intent.getIntExtra(EXTRA_VERIFICATION_ID, -1);
-        mPackageManagerInternal.setIntegrityVerificationResult(
-                verificationId, PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW);
-    }
 }
diff --git a/services/core/java/com/android/server/location/fudger/LocationFudgerCache.java b/services/core/java/com/android/server/location/fudger/LocationFudgerCache.java
index 3670c1f..ce8bec8 100644
--- a/services/core/java/com/android/server/location/fudger/LocationFudgerCache.java
+++ b/services/core/java/com/android/server/location/fudger/LocationFudgerCache.java
@@ -180,7 +180,8 @@
                 Log.e(sTAG, "could not get population density");
             }
         };
-        mPopulationDensityProvider.getCoarsenedS2Cell(latitude, longitude, callback);
+        mPopulationDensityProvider.getCoarsenedS2Cells(latitude, longitude, MAX_CACHE_SIZE - 1,
+                callback);
     }
 
     /**
diff --git a/services/core/java/com/android/server/location/provider/proxy/ProxyPopulationDensityProvider.java b/services/core/java/com/android/server/location/provider/proxy/ProxyPopulationDensityProvider.java
index b0a0f0b..7b454e4 100644
--- a/services/core/java/com/android/server/location/provider/proxy/ProxyPopulationDensityProvider.java
+++ b/services/core/java/com/android/server/location/provider/proxy/ProxyPopulationDensityProvider.java
@@ -96,14 +96,15 @@
 
 
     /** Gets the population density at the requested location. */
-    public void getCoarsenedS2Cell(double latitudeDegrees, double longitudeDegrees,
-              IS2CellIdsCallback callback) {
+    public void getCoarsenedS2Cells(double latitudeDegrees, double longitudeDegrees,
+              int numAdditionalCells, IS2CellIdsCallback callback) {
         mServiceWatcher.runOnBinder(
                 new ServiceWatcher.BinderOperation() {
                     @Override
                     public void run(IBinder binder) throws RemoteException {
                         IPopulationDensityProvider.Stub.asInterface(binder)
-                              .getCoarsenedS2Cell(latitudeDegrees, longitudeDegrees, callback);
+                                .getCoarsenedS2Cells(latitudeDegrees, longitudeDegrees,
+                                      numAdditionalCells, callback);
                     }
 
                     @Override
diff --git a/services/core/java/com/android/server/media/quality/MediaQualityService.java b/services/core/java/com/android/server/media/quality/MediaQualityService.java
index 65d0ab3..4479e9d 100644
--- a/services/core/java/com/android/server/media/quality/MediaQualityService.java
+++ b/services/core/java/com/android/server/media/quality/MediaQualityService.java
@@ -35,6 +35,9 @@
 
 import com.android.server.SystemService;
 
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
+
 import org.json.JSONException;
 import org.json.JSONObject;
 
@@ -43,6 +46,7 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.stream.Collectors;
+import java.util.UUID;
 
 /**
  * This service manage picture profile and sound profile for TV setting. Also communicates with the
@@ -54,10 +58,14 @@
     private static final String TAG = "MediaQualityService";
     private final Context mContext;
     private final MediaQualityDbHelper mMediaQualityDbHelper;
+    private final BiMap<Long, String> mPictureProfileTempIdMap;
+    private final BiMap<Long, String> mSoundProfileTempIdMap;
 
     public MediaQualityService(Context context) {
         super(context);
         mContext = context;
+        mPictureProfileTempIdMap = HashBiMap.create();
+        mSoundProfileTempIdMap = HashBiMap.create();
         mMediaQualityDbHelper = new MediaQualityDbHelper(mContext);
         mMediaQualityDbHelper.setWriteAheadLoggingEnabled(true);
         mMediaQualityDbHelper.setIdleConnectionTimeout(30);
@@ -80,11 +88,14 @@
             values.put(BaseParameters.PARAMETER_NAME, pp.getName());
             values.put(BaseParameters.PARAMETER_PACKAGE, pp.getPackageName());
             values.put(BaseParameters.PARAMETER_INPUT_ID, pp.getInputId());
-            values.put(mMediaQualityDbHelper.SETTINGS, bundleToJson(pp.getParameters()));
+            values.put(mMediaQualityDbHelper.SETTINGS, persistableBundleToJson(pp.getParameters()));
 
             // id is auto-generated by SQLite upon successful insertion of row
-            long id = db.insert(mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME, null, values);
-            return new PictureProfile.Builder(pp).setProfileId(Long.toString(id)).build();
+            Long id = db.insert(mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME,
+                    null, values);
+            populateTempIdMap(mPictureProfileTempIdMap, id);
+            pp.setProfileId(mPictureProfileTempIdMap.get(id));
+            return pp;
         }
 
         @Override
@@ -94,26 +105,27 @@
 
         @Override
         public void removePictureProfile(String id, int userId) {
-            // TODO: implement
+            Long intId = mPictureProfileTempIdMap.inverse().get(id);
+            if (intId != null) {
+                SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase();
+                String selection = BaseParameters.PARAMETER_ID + " = ?";
+                String[] selectionArgs = {Long.toString(intId)};
+                db.delete(mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME, selection,
+                        selectionArgs);
+                mPictureProfileTempIdMap.remove(intId);
+            }
         }
 
         @Override
         public PictureProfile getPictureProfile(int type, String name, int userId) {
-            SQLiteDatabase db = mMediaQualityDbHelper.getReadableDatabase();
-
             String selection = BaseParameters.PARAMETER_TYPE + " = ? AND "
                     + BaseParameters.PARAMETER_NAME + " = ?";
             String[] selectionArguments = {Integer.toString(type), name};
 
             try (
-                    Cursor cursor = db.query(
+                    Cursor cursor = getCursorAfterQuerying(
                             mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME,
-                            getAllPictureProfileColumns(),
-                            selection,
-                            selectionArguments,
-                            /*groupBy=*/ null,
-                            /*having=*/ null,
-                            /*orderBy=*/ null)
+                            getAllMediaProfileColumns(), selection, selectionArguments)
             ) {
                 int count = cursor.getCount();
                 if (count == 0) {
@@ -122,93 +134,19 @@
                 if (count > 1) {
                     Log.wtf(TAG, String.format(Locale.US, "%d entries found for type=%d and name=%s"
                                     + " in %s. Should only ever be 0 or 1.", count, type, name,
-                                    mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME));
+                            mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME));
                     return null;
                 }
                 cursor.moveToFirst();
-                return getPictureProfileFromCursor(cursor);
+                return getPictureProfileWithTempIdFromCursor(cursor);
             }
         }
 
-        private String bundleToJson(PersistableBundle bundle) {
-            JSONObject jsonObject = new JSONObject();
-            if (bundle == null) {
-                return jsonObject.toString();
-            }
-            for (String key : bundle.keySet()) {
-                try {
-                    jsonObject.put(key, bundle.getString(key));
-                } catch (JSONException e) {
-                    Log.e(TAG, "Unable to serialize ", e);
-                }
-            }
-            return jsonObject.toString();
-        }
-
-        private PersistableBundle jsonToBundle(String jsonString) {
-            JSONObject jsonObject = null;
-            PersistableBundle bundle = new PersistableBundle();
-
-            try {
-                jsonObject = new JSONObject(jsonString);
-
-                Iterator<String> keys = jsonObject.keys();
-                while (keys.hasNext()) {
-                    String key = keys.next();
-                    Object value = jsonObject.get(key);
-
-                    if (value instanceof String) {
-                        bundle.putString(key, (String) value);
-                    } else if (value instanceof Integer) {
-                        bundle.putInt(key, (Integer) value);
-                    } else if (value instanceof Boolean) {
-                        bundle.putBoolean(key, (Boolean) value);
-                    } else if (value instanceof Double) {
-                        bundle.putDouble(key, (Double) value);
-                    } else if (value instanceof Long) {
-                        bundle.putLong(key, (Long) value);
-                    }
-                }
-            } catch (JSONException e) {
-                throw new RuntimeException(e);
-            }
-
-            return bundle;
-        }
-
-        private String[] getAllPictureProfileColumns() {
-            return new String[]{
-                    BaseParameters.PARAMETER_ID,
-                    BaseParameters.PARAMETER_TYPE,
-                    BaseParameters.PARAMETER_NAME,
-                    BaseParameters.PARAMETER_INPUT_ID,
-                    BaseParameters.PARAMETER_PACKAGE,
-                    mMediaQualityDbHelper.SETTINGS
-            };
-        }
-
-        private PictureProfile getPictureProfileFromCursor(Cursor cursor) {
-            String returnId = cursor.getString(cursor.getColumnIndexOrThrow(
-                    BaseParameters.PARAMETER_ID));
-            int type = cursor.getInt(cursor.getColumnIndexOrThrow(
-                    BaseParameters.PARAMETER_TYPE));
-            String name = cursor.getString(cursor.getColumnIndexOrThrow(
-                    BaseParameters.PARAMETER_NAME));
-            String inputId = cursor.getString(cursor.getColumnIndexOrThrow(
-                    BaseParameters.PARAMETER_INPUT_ID));
-            String packageName = cursor.getString(cursor.getColumnIndexOrThrow(
-                    BaseParameters.PARAMETER_PACKAGE));
-            String settings = cursor.getString(
-                    cursor.getColumnIndexOrThrow(mMediaQualityDbHelper.SETTINGS));
-            return new PictureProfile(returnId, type, name, inputId,
-                    packageName, jsonToBundle(settings));
-        }
-
         @Override
         public List<PictureProfile> getPictureProfilesByPackage(String packageName, int userId) {
             String selection = BaseParameters.PARAMETER_PACKAGE + " = ?";
             String[] selectionArguments = {packageName};
-            return getPictureProfilesBasedOnConditions(getAllPictureProfileColumns(), selection,
+            return getPictureProfilesBasedOnConditions(getAllMediaProfileColumns(), selection,
                     selectionArguments);
         }
 
@@ -218,37 +156,22 @@
         }
 
         @Override
+        public boolean setDefaultPictureProfile(String profileId, int userId) {
+            // TODO: pass the profile ID to MediaQuality HAL when ready.
+            return false;
+        }
+
+        @Override
         public List<String> getPictureProfilePackageNames(int userId) {
-            String [] column = {BaseParameters.PARAMETER_NAME};
+            String [] column = {BaseParameters.PARAMETER_PACKAGE};
             List<PictureProfile> pictureProfiles = getPictureProfilesBasedOnConditions(column,
                     null, null);
             return pictureProfiles.stream()
-                    .map(PictureProfile::getName)
+                    .map(PictureProfile::getPackageName)
+                    .distinct()
                     .collect(Collectors.toList());
         }
 
-        private List<PictureProfile> getPictureProfilesBasedOnConditions(String[] columns,
-                String selection, String[] selectionArguments) {
-            SQLiteDatabase db = mMediaQualityDbHelper.getReadableDatabase();
-
-            try (
-                    Cursor cursor = db.query(
-                            mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME,
-                            columns,
-                            selection,
-                            selectionArguments,
-                            /*groupBy=*/ null,
-                            /*having=*/ null,
-                            /*orderBy=*/ null)
-            ) {
-                List<PictureProfile> pictureProfiles = new ArrayList<>();
-                while (cursor.moveToNext()) {
-                    pictureProfiles.add(getPictureProfileFromCursor(cursor));
-                }
-                return pictureProfiles;
-            }
-        }
-
         @Override
         public PictureProfileHandle getPictureProfileHandle(String id, int userId) {
             return null;
@@ -259,13 +182,18 @@
             SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase();
 
             ContentValues values = new ContentValues();
+            values.put(BaseParameters.PARAMETER_TYPE, sp.getProfileType());
             values.put(BaseParameters.PARAMETER_NAME, sp.getName());
             values.put(BaseParameters.PARAMETER_PACKAGE, sp.getPackageName());
             values.put(BaseParameters.PARAMETER_INPUT_ID, sp.getInputId());
-            values.put(mMediaQualityDbHelper.SETTINGS, bundleToJson(sp.getParameters()));
+            values.put(mMediaQualityDbHelper.SETTINGS, persistableBundleToJson(sp.getParameters()));
 
-            long id = db.insert(mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME, null, values);
-            return new SoundProfile.Builder(sp).setProfileId(Long.toString(id)).build();
+            // id is auto-generated by SQLite upon successful insertion of row
+            Long id = db.insert(mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME,
+                    null, values);
+            populateTempIdMap(mSoundProfileTempIdMap, id);
+            sp.setProfileId(mSoundProfileTempIdMap.get(id));
+            return sp;
         }
 
         @Override
@@ -275,28 +203,27 @@
 
         @Override
         public void removeSoundProfile(String id, int userId) {
-            SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase();
-            String selection = BaseParameters.PARAMETER_ID + " = ?";
-            String[] selectionArgs = {id};
-            db.delete(mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME, selection, selectionArgs);
+            Long intId = mSoundProfileTempIdMap.inverse().get(id);
+            if (intId != null) {
+                SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase();
+                String selection = BaseParameters.PARAMETER_ID + " = ?";
+                String[] selectionArgs = {Long.toString(intId)};
+                db.delete(mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME, selection,
+                        selectionArgs);
+                mSoundProfileTempIdMap.remove(intId);
+            }
         }
 
         @Override
         public SoundProfile getSoundProfile(int type, String id, int userId) {
-            SQLiteDatabase db = mMediaQualityDbHelper.getReadableDatabase();
-
-            String selection = BaseParameters.PARAMETER_ID + " = ?";
-            String[] selectionArguments = {id};
+            String selection = BaseParameters.PARAMETER_TYPE + " = ? AND "
+                    + BaseParameters.PARAMETER_NAME + " = ?";
+            String[] selectionArguments = {String.valueOf(type), id};
 
             try (
-                    Cursor cursor = db.query(
+                    Cursor cursor = getCursorAfterQuerying(
                             mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME,
-                            getAllSoundProfileColumns(),
-                            selection,
-                            selectionArguments,
-                            /*groupBy=*/ null,
-                            /*having=*/ null,
-                            /*orderBy=*/ null)
+                            getAllMediaProfileColumns(), selection, selectionArguments)
             ) {
                 int count = cursor.getCount();
                 if (count == 0) {
@@ -309,7 +236,7 @@
                     return null;
                 }
                 cursor.moveToFirst();
-                return getSoundProfileFromCursor(cursor);
+                return getSoundProfileWithTempIdFromCursor(cursor);
             }
         }
 
@@ -317,7 +244,7 @@
         public List<SoundProfile> getSoundProfilesByPackage(String packageName, int userId) {
             String selection = BaseParameters.PARAMETER_PACKAGE + " = ?";
             String[] selectionArguments = {packageName};
-            return getSoundProfilesBasedOnConditions(getAllSoundProfileColumns(), selection,
+            return getSoundProfilesBasedOnConditions(getAllMediaProfileColumns(), selection,
                     selectionArguments);
         }
 
@@ -327,18 +254,90 @@
         }
 
         @Override
+        public boolean setDefaultSoundProfile(String profileId, int userId) {
+            // TODO: pass the profile ID to MediaQuality HAL when ready.
+            return false;
+        }
+
+        @Override
         public List<String> getSoundProfilePackageNames(int userId) {
             String [] column = {BaseParameters.PARAMETER_NAME};
             List<SoundProfile> soundProfiles = getSoundProfilesBasedOnConditions(column,
                     null, null);
             return soundProfiles.stream()
-                    .map(SoundProfile::getName)
+                    .map(SoundProfile::getPackageName)
+                    .distinct()
                     .collect(Collectors.toList());
         }
 
-        private String[] getAllSoundProfileColumns() {
+        private void populateTempIdMap(BiMap<Long, String> map, Long id) {
+            if (id != null && map.get(id) == null) {
+                String uuid = UUID.randomUUID().toString();
+                while (map.inverse().containsKey(uuid)) {
+                    uuid = UUID.randomUUID().toString();
+                }
+                map.put(id, uuid);
+            }
+        }
+
+        private String persistableBundleToJson(PersistableBundle bundle) {
+            JSONObject json = new JSONObject();
+            for (String key : bundle.keySet()) {
+                Object value = bundle.get(key);
+                try {
+                    if (value instanceof String) {
+                        json.put(key, bundle.getString(key));
+                    } else if (value instanceof Integer) {
+                        json.put(key, bundle.getInt(key));
+                    } else if (value instanceof Long) {
+                        json.put(key, bundle.getLong(key));
+                    } else if (value instanceof Boolean) {
+                        json.put(key, bundle.getBoolean(key));
+                    } else if (value instanceof Double) {
+                        json.put(key, bundle.getDouble(key));
+                    }
+                } catch (JSONException e) {
+                    Log.e(TAG, "Unable to serialize ", e);
+                }
+            }
+            return json.toString();
+        }
+
+        private PersistableBundle jsonToBundle(String jsonString) {
+            PersistableBundle bundle = new PersistableBundle();
+            if (jsonString != null) {
+                JSONObject jsonObject = null;
+                try {
+                    jsonObject = new JSONObject(jsonString);
+
+                    Iterator<String> keys = jsonObject.keys();
+                    while (keys.hasNext()) {
+                        String key = keys.next();
+                        Object value = jsonObject.get(key);
+
+                        if (value instanceof String) {
+                            bundle.putString(key, (String) value);
+                        } else if (value instanceof Integer) {
+                            bundle.putInt(key, (Integer) value);
+                        } else if (value instanceof Boolean) {
+                            bundle.putBoolean(key, (Boolean) value);
+                        } else if (value instanceof Double) {
+                            bundle.putDouble(key, (Double) value);
+                        } else if (value instanceof Long) {
+                            bundle.putLong(key, (Long) value);
+                        }
+                    }
+                } catch (JSONException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+            return bundle;
+        }
+
+        private String[] getAllMediaProfileColumns() {
             return new String[]{
                     BaseParameters.PARAMETER_ID,
+                    BaseParameters.PARAMETER_TYPE,
                     BaseParameters.PARAMETER_NAME,
                     BaseParameters.PARAMETER_INPUT_ID,
                     BaseParameters.PARAMETER_PACKAGE,
@@ -346,40 +345,92 @@
             };
         }
 
-        private SoundProfile getSoundProfileFromCursor(Cursor cursor) {
-            String returnId = cursor.getString(
-                    cursor.getColumnIndexOrThrow(BaseParameters.PARAMETER_ID));
-            int type = cursor.getInt(
-                    cursor.getColumnIndexOrThrow(BaseParameters.PARAMETER_TYPE));
-            String name = cursor.getString(
-                    cursor.getColumnIndexOrThrow(BaseParameters.PARAMETER_NAME));
-            String inputId = cursor.getString(
-                    cursor.getColumnIndexOrThrow(BaseParameters.PARAMETER_INPUT_ID));
-            String packageName = cursor.getString(
-                    cursor.getColumnIndexOrThrow(BaseParameters.PARAMETER_PACKAGE));
-            String settings = cursor.getString(
-                    cursor.getColumnIndexOrThrow(mMediaQualityDbHelper.SETTINGS));
-            return new SoundProfile(returnId, type, name, inputId, packageName,
-                    jsonToBundle(settings));
+        private PictureProfile getPictureProfileWithTempIdFromCursor(Cursor cursor) {
+            return new PictureProfile(
+                    getTempId(mPictureProfileTempIdMap, cursor),
+                    getType(cursor),
+                    getName(cursor),
+                    getInputId(cursor),
+                    getPackageName(cursor),
+                    jsonToBundle(getSettingsString(cursor))
+            );
+        }
+
+        private SoundProfile getSoundProfileWithTempIdFromCursor(Cursor cursor) {
+            return new SoundProfile(
+                    getTempId(mSoundProfileTempIdMap, cursor),
+                    getType(cursor),
+                    getName(cursor),
+                    getInputId(cursor),
+                    getPackageName(cursor),
+                    jsonToBundle(getSettingsString(cursor))
+            );
+        }
+
+        private String getTempId(BiMap<Long, String> map, Cursor cursor) {
+            int colIndex = cursor.getColumnIndex(BaseParameters.PARAMETER_ID);
+            Long dbId = colIndex != -1 ? cursor.getLong(colIndex) : null;
+            populateTempIdMap(map, dbId);
+            return map.get(dbId);
+        }
+
+        private int getType(Cursor cursor) {
+            int colIndex = cursor.getColumnIndex(BaseParameters.PARAMETER_TYPE);
+            return colIndex != -1 ? cursor.getInt(colIndex) : 0;
+        }
+
+        private String getName(Cursor cursor) {
+            int colIndex = cursor.getColumnIndex(BaseParameters.PARAMETER_NAME);
+            return colIndex != -1 ? cursor.getString(colIndex) : null;
+        }
+
+        private String getInputId(Cursor cursor) {
+            int colIndex = cursor.getColumnIndex(BaseParameters.PARAMETER_INPUT_ID);
+            return colIndex != -1 ? cursor.getString(colIndex) : null;
+        }
+
+        private String getPackageName(Cursor cursor) {
+            int colIndex = cursor.getColumnIndex(BaseParameters.PARAMETER_PACKAGE);
+            return colIndex != -1 ? cursor.getString(colIndex) : null;
+        }
+
+        private String getSettingsString(Cursor cursor) {
+            int colIndex = cursor.getColumnIndex(mMediaQualityDbHelper.SETTINGS);
+            return colIndex != -1 ? cursor.getString(colIndex) : null;
+        }
+
+        private Cursor getCursorAfterQuerying(String table, String[] columns, String selection,
+                String[] selectionArgs) {
+            SQLiteDatabase db = mMediaQualityDbHelper.getReadableDatabase();
+            return db.query(table, columns, selection, selectionArgs,
+                    /*groupBy=*/ null, /*having=*/ null, /*orderBy=*/ null);
+        }
+
+        private List<PictureProfile> getPictureProfilesBasedOnConditions(String[] columns,
+                String selection, String[] selectionArguments) {
+            try (
+                    Cursor cursor = getCursorAfterQuerying(
+                            mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME, columns, selection,
+                            selectionArguments)
+            ) {
+                List<PictureProfile> pictureProfiles = new ArrayList<>();
+                while (cursor.moveToNext()) {
+                    pictureProfiles.add(getPictureProfileWithTempIdFromCursor(cursor));
+                }
+                return pictureProfiles;
+            }
         }
 
         private List<SoundProfile> getSoundProfilesBasedOnConditions(String[] columns,
                 String selection, String[] selectionArguments) {
-            SQLiteDatabase db = mMediaQualityDbHelper.getReadableDatabase();
-
             try (
-                    Cursor cursor = db.query(
-                            mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME,
-                            columns,
-                            selection,
-                            selectionArguments,
-                            /*groupBy=*/ null,
-                            /*having=*/ null,
-                            /*orderBy=*/ null)
+                    Cursor cursor = getCursorAfterQuerying(
+                            mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME, columns, selection,
+                            selectionArguments)
             ) {
                 List<SoundProfile> soundProfiles = new ArrayList<>();
                 while (cursor.moveToNext()) {
-                    soundProfiles.add(getSoundProfileFromCursor(cursor));
+                    soundProfiles.add(getSoundProfileWithTempIdFromCursor(cursor));
                 }
                 return soundProfiles;
             }
diff --git a/services/core/java/com/android/server/pm/PackageHandler.java b/services/core/java/com/android/server/pm/PackageHandler.java
index 0a0882d..4ea4054 100644
--- a/services/core/java/com/android/server/pm/PackageHandler.java
+++ b/services/core/java/com/android/server/pm/PackageHandler.java
@@ -18,7 +18,6 @@
 
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
 
-import static com.android.server.pm.PackageManagerService.CHECK_PENDING_INTEGRITY_VERIFICATION;
 import static com.android.server.pm.PackageManagerService.CHECK_PENDING_VERIFICATION;
 import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
 import static com.android.server.pm.PackageManagerService.DEFAULT_UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD;
@@ -29,7 +28,6 @@
 import static com.android.server.pm.PackageManagerService.ENABLE_ROLLBACK_STATUS;
 import static com.android.server.pm.PackageManagerService.ENABLE_ROLLBACK_TIMEOUT;
 import static com.android.server.pm.PackageManagerService.INSTANT_APP_RESOLUTION_PHASE_TWO;
-import static com.android.server.pm.PackageManagerService.INTEGRITY_VERIFICATION_COMPLETE;
 import static com.android.server.pm.PackageManagerService.PACKAGE_VERIFIED;
 import static com.android.server.pm.PackageManagerService.POST_INSTALL;
 import static com.android.server.pm.PackageManagerService.PRUNE_UNUSED_STATIC_SHARED_LIBRARIES;
@@ -149,42 +147,6 @@
 
                 break;
             }
-            case CHECK_PENDING_INTEGRITY_VERIFICATION: {
-                final int verificationId = msg.arg1;
-                final PackageVerificationState state = mPm.mPendingVerification.get(verificationId);
-
-                if (state != null && !state.isIntegrityVerificationComplete()) {
-                    final VerifyingSession verifyingSession = state.getVerifyingSession();
-                    final Uri originUri = Uri.fromFile(verifyingSession.mOriginInfo.mResolvedFile);
-
-                    String errorMsg = "Integrity verification timed out for " + originUri;
-                    Slog.i(TAG, errorMsg);
-
-                    state.setIntegrityVerificationResult(
-                            getDefaultIntegrityVerificationResponse());
-
-                    if (getDefaultIntegrityVerificationResponse()
-                            == PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW) {
-                        Slog.i(TAG, "Integrity check times out, continuing with " + originUri);
-                    } else {
-                        verifyingSession.setReturnCode(
-                                PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
-                                errorMsg);
-                    }
-
-                    if (state.areAllVerificationsComplete()) {
-                        mPm.mPendingVerification.remove(verificationId);
-                    }
-
-                    Trace.asyncTraceEnd(
-                            TRACE_TAG_PACKAGE_MANAGER,
-                            "integrity_verification",
-                            verificationId);
-
-                    verifyingSession.handleIntegrityVerificationFinished();
-                }
-                break;
-            }
             case PACKAGE_VERIFIED: {
                 final int verificationId = msg.arg1;
 
@@ -205,42 +167,6 @@
 
                 break;
             }
-            case INTEGRITY_VERIFICATION_COMPLETE: {
-                final int verificationId = msg.arg1;
-
-                final PackageVerificationState state = mPm.mPendingVerification.get(verificationId);
-                if (state == null) {
-                    Slog.w(TAG, "Integrity verification with id " + verificationId
-                            + " not found. It may be invalid or overridden by verifier");
-                    break;
-                }
-
-                final int response = (Integer) msg.obj;
-                final VerifyingSession verifyingSession = state.getVerifyingSession();
-                final Uri originUri = Uri.fromFile(verifyingSession.mOriginInfo.mResolvedFile);
-
-                state.setIntegrityVerificationResult(response);
-
-                if (response == PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW) {
-                    Slog.i(TAG, "Integrity check passed for " + originUri);
-                } else {
-                    verifyingSession.setReturnCode(
-                            PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
-                            "Integrity check failed for " + originUri);
-                }
-
-                if (state.areAllVerificationsComplete()) {
-                    mPm.mPendingVerification.remove(verificationId);
-                }
-
-                Trace.asyncTraceEnd(
-                        TRACE_TAG_PACKAGE_MANAGER,
-                        "integrity_verification",
-                        verificationId);
-
-                verifyingSession.handleIntegrityVerificationFinished();
-                break;
-            }
             case INSTANT_APP_RESOLUTION_PHASE_TWO: {
                 InstantAppResolver.doInstantAppResolutionPhaseTwo(mPm.mContext,
                         mPm.snapshotComputer(),
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ab26f02..65bb701 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -923,8 +923,8 @@
     static final int ENABLE_ROLLBACK_TIMEOUT = 22;
     static final int DEFERRED_NO_KILL_POST_DELETE = 23;
     static final int DEFERRED_NO_KILL_INSTALL_OBSERVER = 24;
-    static final int INTEGRITY_VERIFICATION_COMPLETE = 25;
-    static final int CHECK_PENDING_INTEGRITY_VERIFICATION = 26;
+    // static final int UNUSED = 25;
+    // static final int UNUSED = 26;
     static final int DOMAIN_VERIFICATION = 27;
     static final int PRUNE_UNUSED_STATIC_SHARED_LIBRARIES = 28;
     static final int DEFERRED_PENDING_KILL_INSTALL_OBSERVER = 29;
@@ -7124,12 +7124,10 @@
             return mSettings.isPermissionUpgradeNeeded(userId);
         }
 
+        @Deprecated
         @Override
         public void setIntegrityVerificationResult(int verificationId, int verificationResult) {
-            final Message msg = mHandler.obtainMessage(INTEGRITY_VERIFICATION_COMPLETE);
-            msg.arg1 = verificationId;
-            msg.obj = verificationResult;
-            mHandler.sendMessage(msg);
+          // Do nothing.
         }
 
         @Override
diff --git a/services/core/java/com/android/server/pm/PackageVerificationState.java b/services/core/java/com/android/server/pm/PackageVerificationState.java
index 0b6ccc4..63c2ee2 100644
--- a/services/core/java/com/android/server/pm/PackageVerificationState.java
+++ b/services/core/java/com/android/server/pm/PackageVerificationState.java
@@ -43,8 +43,6 @@
 
     private boolean mRequiredVerificationPassed;
 
-    private boolean mIntegrityVerificationComplete;
-
     /**
      * Create a new package verification state where {@code requiredVerifierUid} is the user ID for
      * the package that must reply affirmative before things can continue.
@@ -213,15 +211,7 @@
         return mExtendedTimeoutUids.get(uid, false);
     }
 
-    void setIntegrityVerificationResult(int code) {
-        mIntegrityVerificationComplete = true;
-    }
-
-    boolean isIntegrityVerificationComplete() {
-        return mIntegrityVerificationComplete;
-    }
-
     boolean areAllVerificationsComplete() {
-        return mIntegrityVerificationComplete && isVerificationComplete();
+        return isVerificationComplete();
     }
 }
diff --git a/services/core/java/com/android/server/pm/VerifyingSession.java b/services/core/java/com/android/server/pm/VerifyingSession.java
index f7eb29f..542ae8e 100644
--- a/services/core/java/com/android/server/pm/VerifyingSession.java
+++ b/services/core/java/com/android/server/pm/VerifyingSession.java
@@ -28,7 +28,6 @@
 import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
 
-import static com.android.server.pm.PackageManagerService.CHECK_PENDING_INTEGRITY_VERIFICATION;
 import static com.android.server.pm.PackageManagerService.CHECK_PENDING_VERIFICATION;
 import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
 import static com.android.server.pm.PackageManagerService.DEBUG_VERIFY;
@@ -87,11 +86,6 @@
      * Whether verification is enabled by default.
      */
     private static final boolean DEFAULT_VERIFY_ENABLE = true;
-
-    /**
-     * Whether integrity verification is enabled by default.
-     */
-    private static final boolean DEFAULT_INTEGRITY_VERIFY_ENABLE = true;
     /**
      * The default maximum time to wait for the integrity verification to return in
      * milliseconds.
@@ -129,7 +123,6 @@
     private final boolean mUserActionRequired;
     private final int mUserActionRequiredType;
     private boolean mWaitForVerificationToComplete;
-    private boolean mWaitForIntegrityVerificationToComplete;
     private boolean mWaitForEnableRollbackToComplete;
     private int mRet = PackageManager.INSTALL_SUCCEEDED;
     private String mErrorMessage = null;
@@ -217,7 +210,6 @@
                 new PackageVerificationState(this);
         mPm.mPendingVerification.append(verificationId, verificationState);
 
-        sendIntegrityVerificationRequest(verificationId, pkgLite, verificationState);
         sendPackageVerificationRequest(
                 verificationId, pkgLite, verificationState);
 
@@ -270,89 +262,6 @@
         mPm.mHandler.sendMessageDelayed(msg, rollbackTimeout);
     }
 
-    /**
-     * Send a request to check the integrity of the package.
-     */
-    void sendIntegrityVerificationRequest(
-            int verificationId,
-            PackageInfoLite pkgLite,
-            PackageVerificationState verificationState) {
-        if (!isIntegrityVerificationEnabled()) {
-            // Consider the integrity check as passed.
-            verificationState.setIntegrityVerificationResult(
-                    PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW);
-            return;
-        }
-
-        final Intent integrityVerification =
-                new Intent(Intent.ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION);
-
-        integrityVerification.setDataAndType(Uri.fromFile(new File(mOriginInfo.mResolvedPath)),
-                PACKAGE_MIME_TYPE);
-
-        final int flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
-                | Intent.FLAG_RECEIVER_REGISTERED_ONLY
-                | Intent.FLAG_RECEIVER_FOREGROUND;
-        integrityVerification.addFlags(flags);
-
-        integrityVerification.putExtra(EXTRA_VERIFICATION_ID, verificationId);
-        integrityVerification.putExtra(EXTRA_PACKAGE_NAME, pkgLite.packageName);
-        integrityVerification.putExtra(EXTRA_VERSION_CODE, pkgLite.versionCode);
-        integrityVerification.putExtra(EXTRA_LONG_VERSION_CODE, pkgLite.getLongVersionCode());
-        populateInstallerExtras(integrityVerification);
-
-        // send to integrity component only.
-        integrityVerification.setPackage("android");
-
-        final BroadcastOptions options = BroadcastOptions.makeBasic();
-
-        mPm.mContext.sendOrderedBroadcastAsUser(integrityVerification, UserHandle.SYSTEM,
-                /* receiverPermission= */ null,
-                /* appOp= */ AppOpsManager.OP_NONE,
-                /* options= */ options.toBundle(),
-                new BroadcastReceiver() {
-                    @Override
-                    public void onReceive(Context context, Intent intent) {
-                        final Message msg =
-                                mPm.mHandler.obtainMessage(CHECK_PENDING_INTEGRITY_VERIFICATION);
-                        msg.arg1 = verificationId;
-                        mPm.mHandler.sendMessageDelayed(msg, getIntegrityVerificationTimeout());
-                    }
-                }, /* scheduler= */ null,
-                /* initialCode= */ 0,
-                /* initialData= */ null,
-                /* initialExtras= */ null);
-
-        Trace.asyncTraceBegin(
-                TRACE_TAG_PACKAGE_MANAGER, "integrity_verification", verificationId);
-
-        // stop the copy until verification succeeds.
-        mWaitForIntegrityVerificationToComplete = true;
-    }
-
-
-    /**
-     * Get the integrity verification timeout.
-     *
-     * @return verification timeout in milliseconds
-     */
-    private long getIntegrityVerificationTimeout() {
-        long timeout = Settings.Global.getLong(mPm.mContext.getContentResolver(),
-                Settings.Global.APP_INTEGRITY_VERIFICATION_TIMEOUT,
-                DEFAULT_INTEGRITY_VERIFICATION_TIMEOUT);
-        // The setting can be used to increase the timeout but not decrease it, since that is
-        // equivalent to disabling the integrity component.
-        return Math.max(timeout, DEFAULT_INTEGRITY_VERIFICATION_TIMEOUT);
-    }
-
-    /**
-     * Check whether or not integrity verification has been enabled.
-     */
-    private boolean isIntegrityVerificationEnabled() {
-        // We are not exposing this as a user-configurable setting because we don't want to provide
-        // an easy way to get around the integrity check.
-        return DEFAULT_INTEGRITY_VERIFY_ENABLE;
-    }
 
     /**
      * Send a request to verifier(s) to verify the package if necessary.
@@ -827,11 +736,6 @@
         handleReturnCode();
     }
 
-    void handleIntegrityVerificationFinished() {
-        mWaitForIntegrityVerificationToComplete = false;
-        handleReturnCode();
-    }
-
     void handleRollbackEnabled() {
         // TODO(b/112431924): Consider halting the install if we
         // couldn't enable rollback.
@@ -840,7 +744,7 @@
     }
 
     void handleReturnCode() {
-        if (mWaitForVerificationToComplete || mWaitForIntegrityVerificationToComplete
+        if (mWaitForVerificationToComplete
                 || mWaitForEnableRollbackToComplete) {
             return;
         }
diff --git a/services/core/java/com/android/server/pm/permission/AccessCheckDelegate.java b/services/core/java/com/android/server/pm/permission/AccessCheckDelegate.java
index e9cb279..e989d68 100644
--- a/services/core/java/com/android/server/pm/permission/AccessCheckDelegate.java
+++ b/services/core/java/com/android/server/pm/permission/AccessCheckDelegate.java
@@ -40,7 +40,7 @@
 import com.android.internal.util.function.DodecFunction;
 import com.android.internal.util.function.HexConsumer;
 import com.android.internal.util.function.HexFunction;
-import com.android.internal.util.function.OctFunction;
+import com.android.internal.util.function.NonaFunction;
 import com.android.internal.util.function.QuadFunction;
 import com.android.internal.util.function.TriFunction;
 import com.android.internal.util.function.UndecFunction;
@@ -351,22 +351,22 @@
         @Override
         public SyncNotedAppOp noteOperation(int code, int uid, @Nullable String packageName,
                 @Nullable String featureId, int virtualDeviceId, boolean shouldCollectAsyncNotedOp,
-                @Nullable String message, boolean shouldCollectMessage,
-                @NonNull OctFunction<Integer, Integer, String, String, Integer, Boolean, String,
-                        Boolean, SyncNotedAppOp> superImpl) {
+                @Nullable String message, boolean shouldCollectMessage, int notedCount,
+                @NonNull NonaFunction<Integer, Integer, String, String, Integer, Boolean, String,
+                                        Boolean, Integer, SyncNotedAppOp> superImpl) {
             if (uid == mDelegateAndOwnerUid && isDelegateOp(code)) {
                 final int shellUid = UserHandle.getUid(UserHandle.getUserId(uid),
                         Process.SHELL_UID);
                 final long identity = Binder.clearCallingIdentity();
                 try {
                     return superImpl.apply(code, shellUid, SHELL_PKG, featureId, virtualDeviceId,
-                            shouldCollectAsyncNotedOp, message, shouldCollectMessage);
+                            shouldCollectAsyncNotedOp, message, shouldCollectMessage, notedCount);
                 } finally {
                     Binder.restoreCallingIdentity(identity);
                 }
             }
             return superImpl.apply(code, uid, packageName, featureId, virtualDeviceId,
-                    shouldCollectAsyncNotedOp, message, shouldCollectMessage);
+                    shouldCollectAsyncNotedOp, message, shouldCollectMessage, notedCount);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/policy/AppOpsPolicy.java b/services/core/java/com/android/server/policy/AppOpsPolicy.java
index ecffd38..33210e2 100644
--- a/services/core/java/com/android/server/policy/AppOpsPolicy.java
+++ b/services/core/java/com/android/server/policy/AppOpsPolicy.java
@@ -53,7 +53,7 @@
 import com.android.internal.util.function.DodecFunction;
 import com.android.internal.util.function.HexConsumer;
 import com.android.internal.util.function.HexFunction;
-import com.android.internal.util.function.OctFunction;
+import com.android.internal.util.function.NonaFunction;
 import com.android.internal.util.function.QuadFunction;
 import com.android.internal.util.function.UndecFunction;
 import com.android.server.LocalServices;
@@ -246,11 +246,12 @@
     public SyncNotedAppOp noteOperation(int code, int uid, @Nullable String packageName,
             @Nullable String attributionTag, int virtualDeviceId,
             boolean shouldCollectAsyncNotedOp, @Nullable String message,
-            boolean shouldCollectMessage, @NonNull OctFunction<Integer, Integer, String, String,
-                    Integer, Boolean, String, Boolean, SyncNotedAppOp> superImpl) {
+            boolean shouldCollectMessage, int notedCount,
+            @NonNull NonaFunction<Integer, Integer, String, String,
+                    Integer, Boolean, String, Boolean, Integer, SyncNotedAppOp> superImpl) {
         return superImpl.apply(resolveDatasourceOp(code, uid, packageName, attributionTag),
                 resolveUid(code, uid), packageName, attributionTag, virtualDeviceId,
-                shouldCollectAsyncNotedOp, message, shouldCollectMessage);
+                shouldCollectAsyncNotedOp, message, shouldCollectMessage, notedCount);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/power/hint/HintManagerService.java b/services/core/java/com/android/server/power/hint/HintManagerService.java
index 0f6688f..987a849 100644
--- a/services/core/java/com/android/server/power/hint/HintManagerService.java
+++ b/services/core/java/com/android/server/power/hint/HintManagerService.java
@@ -41,6 +41,7 @@
 import android.hardware.power.IPower;
 import android.hardware.power.SessionConfig;
 import android.hardware.power.SessionTag;
+import android.hardware.power.SupportInfo;
 import android.hardware.power.WorkDuration;
 import android.os.Binder;
 import android.os.CpuHeadroomParamsInternal;
@@ -103,7 +104,6 @@
     // The minimum interval between the headroom calls as rate limiting.
     private static final int DEFAULT_GPU_HEADROOM_INTERVAL_MILLIS = 1000;
     private static final int DEFAULT_CPU_HEADROOM_INTERVAL_MILLIS = 1000;
-    private static final int HEADROOM_INTERVAL_UNSUPPORTED = -1;
 
 
     @VisibleForTesting final long mHintSessionPreferredRate;
@@ -181,6 +181,7 @@
 
     private final IPower mPowerHal;
     private int mPowerHalVersion;
+    private SupportInfo mSupportInfo = null;
     private final PackageManager mPackageManager;
 
     private boolean mUsesFmq;
@@ -248,13 +249,11 @@
 
     @GuardedBy("mCpuHeadroomLock")
     private final HeadroomCache<CpuHeadroomParams, CpuHeadroomResult> mCpuHeadroomCache;
-    private final long mCpuHeadroomIntervalMillis;
 
     private final Object mGpuHeadroomLock = new Object();
 
     @GuardedBy("mGpuHeadroomLock")
     private final HeadroomCache<GpuHeadroomParams, GpuHeadroomResult> mGpuHeadroomCache;
-    private final long mGpuHeadroomIntervalMillis;
 
     // these are set to default values in CpuHeadroomParamsInternal and GpuHeadroomParamsInternal
     private final int mDefaultCpuHeadroomCalculationWindowMillis;
@@ -296,79 +295,40 @@
         mPowerHal = injector.createIPower();
         mPowerHalVersion = 0;
         mUsesFmq = false;
-        long cpuHeadroomIntervalMillis = HEADROOM_INTERVAL_UNSUPPORTED;
-        long gpuHeadroomIntervalMillis = HEADROOM_INTERVAL_UNSUPPORTED;
         if (mPowerHal != null) {
-            try {
-                mPowerHalVersion = mPowerHal.getInterfaceVersion();
-                if (mPowerHal.getInterfaceVersion() >= 6) {
-                    if (SystemProperties.getBoolean(PROPERTY_USE_HAL_HEADROOMS, true)) {
-                        cpuHeadroomIntervalMillis = checkCpuHeadroomSupport();
-                        gpuHeadroomIntervalMillis = checkGpuHeadroomSupport();
-                    }
-                }
-            } catch (RemoteException e) {
-                throw new IllegalStateException("Could not contact PowerHAL!", e);
-            }
+            mSupportInfo = getSupportInfo();
         }
-        mCpuHeadroomIntervalMillis = cpuHeadroomIntervalMillis;
         mDefaultCpuHeadroomCalculationWindowMillis =
                 new CpuHeadroomParamsInternal().calculationWindowMillis;
         mDefaultGpuHeadroomCalculationWindowMillis =
                 new GpuHeadroomParamsInternal().calculationWindowMillis;
-        mGpuHeadroomIntervalMillis = gpuHeadroomIntervalMillis;
-        if (mCpuHeadroomIntervalMillis > 0) {
-            mCpuHeadroomCache = new HeadroomCache<>(2, mCpuHeadroomIntervalMillis);
+        if (mSupportInfo.headroom.isCpuSupported) {
+            mCpuHeadroomCache = new HeadroomCache<>(2, mSupportInfo.headroom.cpuMinIntervalMillis);
         } else {
             mCpuHeadroomCache = null;
         }
-        if (mGpuHeadroomIntervalMillis > 0) {
-            mGpuHeadroomCache = new HeadroomCache<>(2, mGpuHeadroomIntervalMillis);
+        if (mSupportInfo.headroom.isGpuSupported) {
+            mGpuHeadroomCache = new HeadroomCache<>(2, mSupportInfo.headroom.gpuMinIntervalMillis);
         } else {
             mGpuHeadroomCache = null;
         }
     }
 
-    private long checkCpuHeadroomSupport() {
-        final CpuHeadroomParams params = new CpuHeadroomParams();
-        params.tids = new int[]{Process.myPid()};
+    SupportInfo getSupportInfo() {
         try {
-            synchronized (mCpuHeadroomLock) {
-                final CpuHeadroomResult ret = mPowerHal.getCpuHeadroom(params);
-                if (ret != null && ret.getTag() == CpuHeadroomResult.globalHeadroom
-                        && !Float.isNaN(ret.getGlobalHeadroom())) {
-                    return Math.max(
-                            DEFAULT_CPU_HEADROOM_INTERVAL_MILLIS,
-                            mPowerHal.getCpuHeadroomMinIntervalMillis());
-                }
+            mPowerHalVersion = mPowerHal.getInterfaceVersion();
+            if (mPowerHalVersion >= 6) {
+                return mPowerHal.getSupportInfo();
             }
-
-        } catch (UnsupportedOperationException e) {
-            Slog.w(TAG, "getCpuHeadroom HAL API is not supported, params: " + params, e);
         } catch (RemoteException e) {
-            Slog.e(TAG, "getCpuHeadroom HAL API fails, disabling the API, params: " + params, e);
+            throw new IllegalStateException("Could not contact PowerHAL!", e);
         }
-        return HEADROOM_INTERVAL_UNSUPPORTED;
-    }
 
-    private long checkGpuHeadroomSupport() {
-        final GpuHeadroomParams params = new GpuHeadroomParams();
-        try {
-            synchronized (mGpuHeadroomLock) {
-                final GpuHeadroomResult ret = mPowerHal.getGpuHeadroom(params);
-                if (ret != null && ret.getTag() == GpuHeadroomResult.globalHeadroom && !Float.isNaN(
-                        ret.getGlobalHeadroom())) {
-                    return Math.max(
-                            DEFAULT_GPU_HEADROOM_INTERVAL_MILLIS,
-                            mPowerHal.getGpuHeadroomMinIntervalMillis());
-                }
-            }
-        } catch (UnsupportedOperationException e) {
-            Slog.w(TAG, "getGpuHeadroom HAL API is not supported, params: " + params, e);
-        } catch (RemoteException e) {
-            Slog.e(TAG, "getGpuHeadroom HAL API fails, disabling the API, params: " + params, e);
-        }
-        return HEADROOM_INTERVAL_UNSUPPORTED;
+        SupportInfo supportInfo = new SupportInfo();
+        supportInfo.headroom = new SupportInfo.HeadroomSupportInfo();
+        supportInfo.headroom.isCpuSupported = false;
+        supportInfo.headroom.isGpuSupported = false;
+        return supportInfo;
     }
 
     private ServiceThread createCleanUpThread() {
@@ -557,7 +517,7 @@
             return targetDurations;
         }
     }
-    private boolean isHalSupported() {
+    private boolean isHintSessionSupported() {
         return mHintSessionPreferredRate != -1;
     }
 
@@ -1267,7 +1227,7 @@
         public IHintSession createHintSessionWithConfig(@NonNull IBinder token,
                     @SessionTag int tag, SessionCreationConfig creationConfig,
                     SessionConfig config) {
-            if (!isHalSupported()) {
+            if (!isHintSessionSupported()) {
                 throw new UnsupportedOperationException("PowerHAL is not supported!");
             }
 
@@ -1488,14 +1448,13 @@
 
         @Override
         public CpuHeadroomResult getCpuHeadroom(@NonNull CpuHeadroomParamsInternal params) {
-            if (mCpuHeadroomIntervalMillis <= 0) {
+            if (!mSupportInfo.headroom.isCpuSupported) {
                 throw new UnsupportedOperationException();
             }
             final CpuHeadroomParams halParams = new CpuHeadroomParams();
             halParams.tids = new int[]{Binder.getCallingPid()};
             halParams.calculationType = params.calculationType;
             halParams.calculationWindowMillis = params.calculationWindowMillis;
-            halParams.selectionType = params.selectionType;
             if (params.usesDeviceHeadroom) {
                 halParams.tids = new int[]{};
             } else if (params.tids != null && params.tids.length > 0) {
@@ -1544,7 +1503,7 @@
 
         @Override
         public GpuHeadroomResult getGpuHeadroom(@NonNull GpuHeadroomParamsInternal params) {
-            if (mGpuHeadroomIntervalMillis <= 0) {
+            if (!mSupportInfo.headroom.isGpuSupported) {
                 throw new UnsupportedOperationException();
             }
             final GpuHeadroomParams halParams = new GpuHeadroomParams();
@@ -1579,18 +1538,18 @@
 
         @Override
         public long getCpuHeadroomMinIntervalMillis() {
-            if (mCpuHeadroomIntervalMillis <= 0) {
+            if (!mSupportInfo.headroom.isCpuSupported) {
                 throw new UnsupportedOperationException();
             }
-            return mCpuHeadroomIntervalMillis;
+            return mSupportInfo.headroom.cpuMinIntervalMillis;
         }
 
         @Override
         public long getGpuHeadroomMinIntervalMillis() {
-            if (mGpuHeadroomIntervalMillis <= 0) {
+            if (!mSupportInfo.headroom.isGpuSupported) {
                 throw new UnsupportedOperationException();
             }
-            return mGpuHeadroomIntervalMillis;
+            return mSupportInfo.headroom.gpuMinIntervalMillis;
         }
 
         @Override
@@ -1609,7 +1568,7 @@
             }
             pw.println("HintSessionPreferredRate: " + mHintSessionPreferredRate);
             pw.println("MaxGraphicsPipelineThreadsCount: " + MAX_GRAPHICS_PIPELINE_THREADS_COUNT);
-            pw.println("HAL Support: " + isHalSupported());
+            pw.println("HAL Support: " + isHintSessionSupported());
             pw.println("Active Sessions:");
             synchronized (mLock) {
                 for (int i = 0; i < mActiveSessions.size(); i++) {
@@ -1625,20 +1584,13 @@
                     }
                 }
             }
-            pw.println("CPU Headroom Interval: " + mCpuHeadroomIntervalMillis);
-            pw.println("GPU Headroom Interval: " + mGpuHeadroomIntervalMillis);
+            pw.println("CPU Headroom Interval: " + mSupportInfo.headroom.cpuMinIntervalMillis);
+            pw.println("GPU Headroom Interval: " + mSupportInfo.headroom.gpuMinIntervalMillis);
             try {
                 CpuHeadroomParamsInternal params = new CpuHeadroomParamsInternal();
-                params.selectionType = CpuHeadroomParams.SelectionType.ALL;
                 params.usesDeviceHeadroom = true;
                 CpuHeadroomResult ret = getCpuHeadroom(params);
                 pw.println("CPU headroom: " + (ret == null ? "N/A" : ret.getGlobalHeadroom()));
-                params = new CpuHeadroomParamsInternal();
-                params.selectionType = CpuHeadroomParams.SelectionType.PER_CORE;
-                params.usesDeviceHeadroom = true;
-                ret = getCpuHeadroom(params);
-                pw.println("CPU headroom per core: " + (ret == null ? "N/A"
-                        : Arrays.toString(ret.getPerCoreHeadroom())));
             } catch (Exception e) {
                 Slog.d(TAG, "Failed to dump CPU headroom", e);
                 pw.println("CPU headroom: N/A");
diff --git a/services/core/java/com/android/server/vibrator/VendorVibrationSession.java b/services/core/java/com/android/server/vibrator/VendorVibrationSession.java
index 15c3099..1b6ce9d 100644
--- a/services/core/java/com/android/server/vibrator/VendorVibrationSession.java
+++ b/services/core/java/com/android/server/vibrator/VendorVibrationSession.java
@@ -119,6 +119,7 @@
 
     @Override
     public void finishSession() {
+        Slog.d(TAG, "Session finish requested, ending vibration session...");
         // Do not abort session in HAL, wait for ongoing vibration requests to complete.
         // This might take a while to end the session, but it can be aborted by cancelSession.
         requestEndSession(Status.FINISHED, /* shouldAbort= */ false, /* isVendorRequest= */ true);
@@ -126,6 +127,7 @@
 
     @Override
     public void cancelSession() {
+        Slog.d(TAG, "Session cancel requested, aborting vibration session...");
         // Always abort session in HAL while cancelling it.
         // This might be triggered after finishSession was already called.
         requestEndSession(Status.CANCELLED_BY_USER, /* shouldAbort= */ true,
@@ -228,13 +230,14 @@
     @Override
     public void notifySessionCallback() {
         synchronized (mLock) {
+            Slog.d(TAG, "Session callback received, ending vibration session...");
             // If end was not requested then the HAL has cancelled the session.
             maybeSetEndRequestLocked(Status.CANCELLED_BY_UNKNOWN_REASON,
                     /* isVendorRequest= */ false);
             maybeSetStatusToRequestedLocked();
             clearVibrationConductor();
+            mHandler.post(() -> mManagerHooks.onSessionReleased(mSessionId));
         }
-        mHandler.post(() -> mManagerHooks.onSessionReleased(mSessionId));
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index bbef578..415896b 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -50,6 +50,7 @@
 import static com.android.window.flags.Flags.offloadColorExtraction;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.AppGlobals;
@@ -2487,7 +2488,8 @@
     @Override
     public WallpaperInfo getWallpaperInfoWithFlags(@SetWallpaperFlags int which, int userId) {
         if (liveWallpaperContentHandling()) {
-            return getWallpaperInstance(which, userId, false).getInfo();
+            WallpaperInstance instance = getWallpaperInstance(which, userId, false);
+            return (instance != null) ? instance.getInfo() : null;
         }
 
         userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
@@ -2509,7 +2511,7 @@
         return null;
     }
 
-    @NonNull
+    @Nullable
     @Override
     public WallpaperInstance getWallpaperInstance(@SetWallpaperFlags int which, int userId) {
         return getWallpaperInstance(which, userId, true);
@@ -2517,28 +2519,27 @@
 
     private WallpaperInstance getWallpaperInstance(@SetWallpaperFlags int which, int userId,
             boolean requireReadWallpaper) {
-        final WallpaperInstance defaultInstance = new WallpaperInstance(null,
-                new WallpaperDescription.Builder().build());
         userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
                 Binder.getCallingUid(), userId, false, true, "getWallpaperInfo", null);
         synchronized (mLock) {
             WallpaperData wallpaper = (which == FLAG_LOCK) ? mLockWallpaperMap.get(userId)
                     : mWallpaperMap.get(userId);
-            if (wallpaper == null
-                    || wallpaper.connection == null
-                    || wallpaper.connection.mInfo == null) {
-                return defaultInstance;
-            }
+            if (wallpaper == null || wallpaper.connection == null) return null;
 
             WallpaperInfo info = wallpaper.connection.mInfo;
-            boolean canQueryPackage = mPackageManagerInternal.canQueryPackage(
+            boolean canQueryPackage = (info == null) ||  mPackageManagerInternal.canQueryPackage(
                     Binder.getCallingUid(), info.getComponent().getPackageName());
             if (hasPermission(READ_WALLPAPER_INTERNAL)
                     || (canQueryPackage && !requireReadWallpaper)) {
-                return new WallpaperInstance(info, wallpaper.getDescription());
+                // TODO(b/380245309) Remove this when crops are part of the description.
+                WallpaperDescription description =
+                        wallpaper.getDescription().toBuilder().setCropHints(
+                                wallpaper.mCropHints).build();
+                return new WallpaperInstance(info, description);
+            } else {
+                return null;
             }
         }
-        return defaultInstance;
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
index 7fc11e6..3c0e058 100644
--- a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
+++ b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
@@ -150,11 +150,7 @@
     @Override
     public void onWindowInfosChanged(InputWindowHandle[] windowHandles,
             DisplayInfo[] displayInfos) {
-        if (com.android.server.accessibility.Flags.removeOnWindowInfosChangedHandler()) {
-            onWindowInfosChangedInternal(windowHandles, displayInfos);
-        } else {
-            mHandler.post(() -> onWindowInfosChangedInternal(windowHandles, displayInfos));
-        }
+        onWindowInfosChangedInternal(windowHandles, displayInfos);
     }
 
     private void onWindowInfosChangedInternal(InputWindowHandle[] windowHandles,
diff --git a/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java b/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java
index cb95b36..1676bfa 100644
--- a/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java
+++ b/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java
@@ -191,7 +191,9 @@
     }
 
     boolean isCameraRunningAndWindowingModeEligible(@NonNull ActivityRecord activity) {
-        return activity.inFreeformWindowingMode()
+        return  activity.mAppCompatController.getAppCompatCameraOverrides()
+                .shouldApplyFreeformTreatmentForCameraCompat()
+                && activity.inFreeformWindowingMode()
                 && mCameraStateMonitor.isCameraRunningForActivity(activity);
     }
 
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 20481f2..1fc609b7 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -1429,7 +1429,16 @@
         // Commit wallpaper visibility after activity, because usually the wallpaper target token is
         // an activity, and wallpaper's visibility depends on activity's visibility.
         for (int i = mParticipants.size() - 1; i >= 0; --i) {
-            final WallpaperWindowToken wt = mParticipants.valueAt(i).asWallpaperToken();
+            final WindowContainer<?> wc = mParticipants.valueAt(i);
+            WallpaperWindowToken wt = wc.asWallpaperToken();
+            if (!Flags.ensureWallpaperInTransitions()) {
+                if (wt == null) {
+                    final WindowState windowState = wc.asWindowState();
+                    if (windowState != null) {
+                        wt = windowState.mToken.asWallpaperToken();
+                    }
+                }
+            }
             if (wt == null) continue;
             final WindowState target = wt.mDisplayContent.mWallpaperController.getWallpaperTarget();
             final boolean isTargetInvisible = target == null || !target.mToken.isVisible();
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 7e70e75..00ade80 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -7949,43 +7949,46 @@
         @Override
         public void waitForAllWindowsDrawn(Message message, long timeout, int displayId) {
             Objects.requireNonNull(message.getTarget());
-            final WindowContainer<?> container = displayId == INVALID_DISPLAY
-                    ? mRoot : mRoot.getDisplayContent(displayId);
-            if (container == null) {
-                // The waiting container doesn't exist, no need to wait to run the callback. Run and
-                // return;
-                message.sendToTarget();
-                return;
-            }
             boolean allWindowsDrawn = false;
             synchronized (mGlobalLock) {
-                if (displayId == INVALID_DISPLAY
-                        && mRoot.getDefaultDisplay().mDisplayUpdater.waitForTransition(message)) {
-                    // Use the ready-to-play of transition as the signal.
-                    return;
-                }
-                container.waitForAllWindowsDrawn();
-                mWindowPlacerLocked.requestTraversal();
-                mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, container);
-                if (container.mWaitingForDrawn.isEmpty()) {
-                    allWindowsDrawn = true;
-                } else {
-                    if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
-                        for (int i = 0; i < container.mWaitingForDrawn.size(); i++) {
-                            traceStartWaitingForWindowDrawn(container.mWaitingForDrawn.get(i));
-                        }
-                    }
-
-                    mWaitingForDrawnCallbacks.put(container, message);
-                    mH.sendNewMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT, container, timeout);
-                    checkDrawnWindowsLocked();
-                }
+                allWindowsDrawn = waitForAllWindowsDrawnLocked(message, timeout, displayId);
             }
             if (allWindowsDrawn) {
                 message.sendToTarget();
             }
         }
 
+        /** Return {@code true} if all windows have been drawn. */
+        private boolean waitForAllWindowsDrawnLocked(Message message, long timeout, int displayId) {
+            final WindowContainer<?> container = displayId == INVALID_DISPLAY
+                    ? mRoot : mRoot.getDisplayContent(displayId);
+            if (container == null) {
+                // The waiting container doesn't exist, no need to wait. Treat as drawn.
+                return true;
+            }
+            if (displayId == INVALID_DISPLAY
+                    && mRoot.getDefaultDisplay().mDisplayUpdater.waitForTransition(message)) {
+                // Use the ready-to-play of transition as the signal.
+                return false;
+            }
+            container.waitForAllWindowsDrawn();
+            mWindowPlacerLocked.requestTraversal();
+            mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, container);
+            if (container.mWaitingForDrawn.isEmpty()) {
+                return true;
+            }
+            if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
+                for (int i = 0; i < container.mWaitingForDrawn.size(); i++) {
+                    traceStartWaitingForWindowDrawn(container.mWaitingForDrawn.get(i));
+                }
+            }
+
+            mWaitingForDrawnCallbacks.put(container, message);
+            mH.sendNewMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT, container, timeout);
+            checkDrawnWindowsLocked();
+            return false;
+        }
+
         @Override
         public void setForcedDisplaySize(int displayId, int width, int height) {
             WindowManagerService.this.setForcedDisplaySize(displayId, width, height);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index ac1219c..3ccde06 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -9085,11 +9085,13 @@
         }
         CallerIdentity caller = getCallerIdentity(who);
 
-        if (!Flags.setAutoTimeEnabledCoexistence()) {
+        if (Flags.setAutoTimeEnabledCoexistence()) {
+            Preconditions.checkCallAuthorization(hasPermission(SET_TIME, caller.getPackageName()));
+        } else {
             Objects.requireNonNull(who, "ComponentName is null");
-        }
-        Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller)
+            Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller)
                 || isProfileOwnerOfOrganizationOwnedDevice(caller) || isDefaultDeviceOwner(caller));
+        }
 
         return mInjector.settingsGlobalGetInt(Global.AUTO_TIME, 0) > 0;
     }
@@ -9166,10 +9168,7 @@
         }
 
         CallerIdentity caller = getCallerIdentity(who);
-
-        if (!Flags.setAutoTimeZoneEnabledCoexistence()) {
-            Objects.requireNonNull(who, "ComponentName is null");
-        }
+        Objects.requireNonNull(who, "ComponentName is null");
         Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller)
                 || isProfileOwnerOfOrganizationOwnedDevice(caller) || isDefaultDeviceOwner(
                 caller));
@@ -9193,10 +9192,15 @@
         }
 
         CallerIdentity caller = getCallerIdentity(who);
-        Objects.requireNonNull(who, "ComponentName is null");
-        Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller)
+        if (Flags.setAutoTimeZoneEnabledCoexistence()) {
+            Preconditions.checkCallAuthorization(
+                hasPermission(SET_TIME_ZONE, caller.getPackageName()));
+        } else {
+            Objects.requireNonNull(who, "ComponentName is null");
+            Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller)
                 || isProfileOwnerOfOrganizationOwnedDevice(caller) || isDefaultDeviceOwner(
                 caller));
+        }
         return mInjector.settingsGlobalGetInt(Global.AUTO_TIME_ZONE, 0) > 0;
     }
 
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index fde6ce2..aa63c4a 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -429,6 +429,8 @@
             "/apex/com.android.tethering/javalib/service-connectivity.jar";
     private static final String CONNECTIVITY_SERVICE_INITIALIZER_CLASS =
             "com.android.server.ConnectivityServiceInitializer";
+    private static final String CONNECTIVITY_SERVICE_INITIALIZER_B_CLASS =
+            "com.android.server.ConnectivityServiceInitializerB";
     private static final String NETWORK_STATS_SERVICE_INITIALIZER_CLASS =
             "com.android.server.NetworkStatsServiceInitializer";
     private static final String UWB_APEX_SERVICE_JAR_PATH =
@@ -1486,7 +1488,6 @@
         IStorageManager storageManager = null;
         NetworkManagementService networkManagement = null;
         VpnManagerService vpnManager = null;
-        VcnManagementService vcnManagement = null;
         NetworkPolicyManagerService networkPolicy = null;
         WindowManagerService wm = null;
         NetworkTimeUpdateService networkTimeUpdater = null;
@@ -2232,8 +2233,10 @@
 
             t.traceBegin("StartVcnManagementService");
             try {
-                vcnManagement = VcnManagementService.create(context);
-                ServiceManager.addService(Context.VCN_MANAGEMENT_SERVICE, vcnManagement);
+                // TODO: b/375213246 When VCN is in mainline module, load it from the apex path.
+                // Whether VCN will be in apex or in the platform will be gated by a build system
+                // flag.
+                mSystemServiceManager.startService(CONNECTIVITY_SERVICE_INITIALIZER_B_CLASS);
             } catch (Throwable e) {
                 reportWtf("starting VCN Management Service", e);
             }
@@ -3159,7 +3162,6 @@
         final MediaRouterService mediaRouterF = mediaRouter;
         final MmsServiceBroker mmsServiceF = mmsService;
         final VpnManagerService vpnManagerF = vpnManager;
-        final VcnManagementService vcnManagementF = vcnManagement;
         final WindowManagerService windowManagerF = wm;
         final ConnectivityManager connectivityF = (ConnectivityManager)
                 context.getSystemService(Context.CONNECTIVITY_SERVICE);
@@ -3286,15 +3288,6 @@
                 reportWtf("making VpnManagerService ready", e);
             }
             t.traceEnd();
-            t.traceBegin("MakeVcnManagementServiceReady");
-            try {
-                if (vcnManagementF != null) {
-                    vcnManagementF.systemReady();
-                }
-            } catch (Throwable e) {
-                reportWtf("making VcnManagementService ready", e);
-            }
-            t.traceEnd();
             t.traceBegin("MakeNetworkPolicyServiceReady");
             try {
                 if (networkPolicyF != null) {
diff --git a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
index 02e0bbf..eb61a40 100644
--- a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
@@ -30,13 +30,10 @@
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.robolectric.Shadows.shadowOf;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertTrue;
 import static org.testng.Assert.expectThrows;
 
 import android.app.backup.BackupManager;
@@ -90,7 +87,6 @@
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 
 /**
@@ -110,7 +106,6 @@
     private static final String TAG = "BMSTest";
     private static final String PACKAGE_1 = "some.package.1";
     private static final String PACKAGE_2 = "some.package.2";
-    private static final String USER_FACING_PACKAGE = "user.facing.package";
     private static final int USER_ID = 10;
 
     @Mock private TransportManager mTransportManager;
@@ -1213,47 +1208,6 @@
                 eq(packageTrackingReceiver), eq(UserHandle.of(USER_ID)), any(), any(), any());
     }
 
-    @Test
-    public void testFilterUserFacingPackages_shouldSkipUserFacing_filtersUserFacing() {
-        List<PackageInfo> packages = Arrays.asList(getPackageInfo(USER_FACING_PACKAGE),
-                getPackageInfo(PACKAGE_1));
-        UserBackupManagerService backupManagerService = spy(
-                createUserBackupManagerServiceAndRunTasks());
-        when(backupManagerService.shouldSkipUserFacingData()).thenReturn(true);
-        when(backupManagerService.shouldSkipPackage(eq(USER_FACING_PACKAGE))).thenReturn(true);
-
-        List<PackageInfo> filteredPackages = backupManagerService.filterUserFacingPackages(
-                packages);
-
-        assertFalse(containsPackage(filteredPackages, USER_FACING_PACKAGE));
-        assertTrue(containsPackage(filteredPackages, PACKAGE_1));
-    }
-
-    @Test
-    public void testFilterUserFacingPackages_shouldNotSkipUserFacing_doesNotFilterUserFacing() {
-        List<PackageInfo> packages = Arrays.asList(getPackageInfo(USER_FACING_PACKAGE),
-                getPackageInfo(PACKAGE_1));
-        UserBackupManagerService backupManagerService = spy(
-                createUserBackupManagerServiceAndRunTasks());
-        when(backupManagerService.shouldSkipUserFacingData()).thenReturn(false);
-        when(backupManagerService.shouldSkipPackage(eq(USER_FACING_PACKAGE))).thenReturn(true);
-
-        List<PackageInfo> filteredPackages = backupManagerService.filterUserFacingPackages(
-                packages);
-
-        assertTrue(containsPackage(filteredPackages, USER_FACING_PACKAGE));
-        assertTrue(containsPackage(filteredPackages, PACKAGE_1));
-    }
-
-    private static boolean containsPackage(List<PackageInfo> packages, String targetPackage) {
-        for (PackageInfo packageInfo : packages) {
-            if (targetPackage.equals(packageInfo.packageName)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     private UserBackupManagerService createUserBackupManagerServiceAndRunTasks() {
         return BackupManagerServiceTestUtils.createUserBackupManagerServiceAndRunTasks(
                 USER_ID, mContext, mBackupThread, mBaseStateDir, mDataDir, mTransportManager);
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageVerificationStateTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageVerificationStateTest.java
index a93e8ad..97f1bd4 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageVerificationStateTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageVerificationStateTest.java
@@ -574,57 +574,16 @@
         assertTrue(state.isInstallAllowed());
     }
 
-    public void testAreAllVerificationsComplete_onlyVerificationPasses() {
+    public void testAreAllVerificationsComplete() {
         PackageVerificationState state = new PackageVerificationState(null);
         state.addRequiredVerifierUid(REQUIRED_UID_1);
         assertFalse(state.areAllVerificationsComplete());
 
         state.setVerifierResponse(REQUIRED_UID_1, PackageManager.VERIFICATION_ALLOW);
 
-        assertFalse(state.areAllVerificationsComplete());
-    }
-
-    public void testAreAllVerificationsComplete_onlyIntegrityCheckPasses() {
-        PackageVerificationState state = new PackageVerificationState(null);
-        state.addRequiredVerifierUid(REQUIRED_UID_1);
-        assertFalse(state.areAllVerificationsComplete());
-
-        state.setIntegrityVerificationResult(PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW);
-
-        assertFalse(state.areAllVerificationsComplete());
-    }
-
-    public void testAreAllVerificationsComplete_bothPasses() {
-        PackageVerificationState state = new PackageVerificationState(null);
-        state.addRequiredVerifierUid(REQUIRED_UID_1);
-        assertFalse(state.areAllVerificationsComplete());
-
-        state.setIntegrityVerificationResult(PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW);
-        state.setVerifierResponse(REQUIRED_UID_1, PackageManager.VERIFICATION_ALLOW);
-
         assertTrue(state.areAllVerificationsComplete());
     }
 
-    public void testAreAllVerificationsComplete_onlyVerificationFails() {
-        PackageVerificationState state = new PackageVerificationState(null);
-        state.addRequiredVerifierUid(REQUIRED_UID_1);
-        assertFalse(state.areAllVerificationsComplete());
-
-        state.setVerifierResponse(REQUIRED_UID_1, PackageManager.VERIFICATION_REJECT);
-
-        assertFalse(state.areAllVerificationsComplete());
-    }
-
-    public void testAreAllVerificationsComplete_onlyIntegrityCheckFails() {
-        PackageVerificationState state = new PackageVerificationState(null);
-        state.addRequiredVerifierUid(REQUIRED_UID_1);
-        assertFalse(state.areAllVerificationsComplete());
-
-        state.setIntegrityVerificationResult(PackageManagerInternal.INTEGRITY_VERIFICATION_REJECT);
-
-        assertFalse(state.areAllVerificationsComplete());
-    }
-
     private void processOnTimeout(PackageVerificationState state, int code, int uid) {
         // CHECK_PENDING_VERIFICATION handler.
         assertFalse("Verification should not be marked as complete yet",
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/fudger/LocationFudgerCacheTest.java b/services/tests/mockingservicestests/src/com/android/server/location/fudger/LocationFudgerCacheTest.java
index 04b82c4..6b7eda2 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/fudger/LocationFudgerCacheTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/fudger/LocationFudgerCacheTest.java
@@ -20,6 +20,7 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyDouble;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -226,8 +227,8 @@
 
         cache.getCoarseningLevel(POINT_IN_TIMES_SQUARE[0], POINT_IN_TIMES_SQUARE[1]);
 
-        verify(provider).getCoarsenedS2Cell(eq(POINT_IN_TIMES_SQUARE[0]),
-                eq(POINT_IN_TIMES_SQUARE[1]), any());
+        verify(provider).getCoarsenedS2Cells(eq(POINT_IN_TIMES_SQUARE[0]),
+                eq(POINT_IN_TIMES_SQUARE[1]), anyInt(), any());
     }
 
     @Test
@@ -242,8 +243,8 @@
 
         ArgumentCaptor<IS2CellIdsCallback> argumentCaptor = ArgumentCaptor.forClass(
                 IS2CellIdsCallback.class);
-        verify(provider).getCoarsenedS2Cell(eq(POINT_IN_TIMES_SQUARE[0]),
-                eq(POINT_IN_TIMES_SQUARE[1]), argumentCaptor.capture());
+        verify(provider).getCoarsenedS2Cells(eq(POINT_IN_TIMES_SQUARE[0]),
+                eq(POINT_IN_TIMES_SQUARE[1]), anyInt(), argumentCaptor.capture());
 
         // Results from the proxy should set the cache
         int expectedLevel = 4;
@@ -264,10 +265,23 @@
 
         cache.addToCache(TIMES_SQUARE_S2_ID);
 
-        verify(provider, never()).getCoarsenedS2Cell(anyDouble(), anyDouble(), any());
+        verify(provider, never()).getCoarsenedS2Cells(anyDouble(), anyDouble(), anyInt(), any());
     }
 
     @Test
+    public void locationFudgerCache_whenQueryIsCached_askForMaxCacheSizeElems() {
+        ProxyPopulationDensityProvider provider = mock(ProxyPopulationDensityProvider.class);
+        LocationFudgerCache cache = new LocationFudgerCache(provider);
+        int numAdditionalCells = cache.MAX_CACHE_SIZE - 1;
+
+        cache.getCoarseningLevel(POINT_IN_TIMES_SQUARE[0], POINT_IN_TIMES_SQUARE[1]);
+
+        verify(provider).getCoarsenedS2Cells(eq(POINT_IN_TIMES_SQUARE[0]),
+                eq(POINT_IN_TIMES_SQUARE[1]), eq(numAdditionalCells), any());
+    }
+
+
+    @Test
     public void locationFudgerCache_canContainUpToMaxSizeItems() {
         // This test has two sequences of arrange-act-assert.
         // The first checks that the cache correctly store up to MAX_CACHE_SIZE items.
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
index cd19904..6d78def 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
@@ -1448,7 +1448,7 @@
         Location test = new Location("any-provider");
         mManager.getPermittedLocation(test, PERMISSION_COARSE);
 
-        verify(provider, never()).getCoarsenedS2Cell(anyDouble(), anyDouble(), any());
+        verify(provider, never()).getCoarsenedS2Cells(anyDouble(), anyDouble(), anyInt(), any());
     }
 
     @Test
@@ -1472,7 +1472,7 @@
         Location test = new Location("any-provider");
         mManager.getPermittedLocation(test, PERMISSION_COARSE);
 
-        verify(provider, never()).getCoarsenedS2Cell(anyDouble(), anyDouble(), any());
+        verify(provider, never()).getCoarsenedS2Cells(anyDouble(), anyDouble(), anyInt(), any());
     }
 
     @Test
@@ -1499,7 +1499,7 @@
 
         // We can't test that 10.0, 20.0 was passed due to the offset. We only test that a call
         // happened.
-        verify(provider).getCoarsenedS2Cell(anyDouble(), anyDouble(), any());
+        verify(provider).getCoarsenedS2Cells(anyDouble(), anyDouble(), anyInt(), any());
     }
 
     @MediumTest
diff --git a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
index 313c01d..7248833 100644
--- a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
+++ b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
@@ -58,6 +58,7 @@
 import android.hardware.power.IPower;
 import android.hardware.power.SessionConfig;
 import android.hardware.power.SessionTag;
+import android.hardware.power.SupportInfo;
 import android.hardware.power.WorkDuration;
 import android.os.Binder;
 import android.os.CpuHeadroomParamsInternal;
@@ -159,6 +160,7 @@
 
     private HintManagerService mService;
     private ChannelConfig mConfig;
+    private SupportInfo mSupportInfo;
 
     private static Answer<Long> fakeCreateWithConfig(Long ptr, Long sessionId) {
         return new Answer<Long>() {
@@ -179,6 +181,12 @@
         mConfig.eventFlagDescriptor = new MQDescriptor<Byte, Byte>();
         ApplicationInfo applicationInfo = new ApplicationInfo();
         applicationInfo.category = ApplicationInfo.CATEGORY_GAME;
+        mSupportInfo = new SupportInfo();
+        mSupportInfo.headroom = new SupportInfo.HeadroomSupportInfo();
+        mSupportInfo.headroom.isCpuSupported = true;
+        mSupportInfo.headroom.cpuMinIntervalMillis = 2000;
+        mSupportInfo.headroom.isGpuSupported = true;
+        mSupportInfo.headroom.gpuMinIntervalMillis = 2000;
         when(mContext.getPackageManager()).thenReturn(mMockPackageManager);
         when(mMockPackageManager.getNameForUid(anyInt())).thenReturn(TEST_APP_NAME);
         when(mMockPackageManager.getApplicationInfo(eq(TEST_APP_NAME), anyInt()))
@@ -205,6 +213,7 @@
                     SESSION_IDS[2]));
 
         when(mIPowerMock.getInterfaceVersion()).thenReturn(6);
+        when(mIPowerMock.getSupportInfo()).thenReturn(mSupportInfo);
         when(mIPowerMock.getSessionChannel(anyInt(), anyInt())).thenReturn(mConfig);
         LocalServices.removeServiceForTest(ActivityManagerInternal.class);
         LocalServices.addService(ActivityManagerInternal.class, mAmInternalMock);
@@ -1247,28 +1256,22 @@
 
     @Test
     public void testCpuHeadroomCache() throws Exception {
-        when(mIPowerMock.getCpuHeadroomMinIntervalMillis()).thenReturn(2000L);
         CpuHeadroomParamsInternal params1 = new CpuHeadroomParamsInternal();
         CpuHeadroomParams halParams1 = new CpuHeadroomParams();
         halParams1.calculationType = CpuHeadroomParams.CalculationType.MIN;
-        halParams1.selectionType = CpuHeadroomParams.SelectionType.ALL;
         halParams1.tids = new int[]{Process.myPid()};
 
         CpuHeadroomParamsInternal params2 = new CpuHeadroomParamsInternal();
         params2.usesDeviceHeadroom = true;
         params2.calculationType = CpuHeadroomParams.CalculationType.MIN;
-        params2.selectionType = CpuHeadroomParams.SelectionType.PER_CORE;
         CpuHeadroomParams halParams2 = new CpuHeadroomParams();
         halParams2.calculationType = CpuHeadroomParams.CalculationType.MIN;
-        halParams2.selectionType = CpuHeadroomParams.SelectionType.PER_CORE;
         halParams2.tids = new int[]{};
 
         CpuHeadroomParamsInternal params3 = new CpuHeadroomParamsInternal();
         params3.calculationType = CpuHeadroomParams.CalculationType.AVERAGE;
-        params3.selectionType = CpuHeadroomParams.SelectionType.ALL;
         CpuHeadroomParams halParams3 = new CpuHeadroomParams();
         halParams3.calculationType = CpuHeadroomParams.CalculationType.AVERAGE;
-        halParams3.selectionType = CpuHeadroomParams.SelectionType.ALL;
         halParams3.tids = new int[]{Process.myPid()};
 
         // this params should not be cached as the window is not default
@@ -1276,15 +1279,14 @@
         params4.calculationWindowMillis = 123;
         CpuHeadroomParams halParams4 = new CpuHeadroomParams();
         halParams4.calculationType = CpuHeadroomParams.CalculationType.MIN;
-        halParams4.selectionType = CpuHeadroomParams.SelectionType.ALL;
         halParams4.calculationWindowMillis = 123;
         halParams4.tids = new int[]{Process.myPid()};
 
         float headroom1 = 0.1f;
         CpuHeadroomResult halRet1 = CpuHeadroomResult.globalHeadroom(headroom1);
         when(mIPowerMock.getCpuHeadroom(eq(halParams1))).thenReturn(halRet1);
-        float[] headroom2 = new float[] {0.2f, 0.2f};
-        CpuHeadroomResult halRet2 = CpuHeadroomResult.perCoreHeadroom(headroom2);
+        float headroom2 = 0.2f;
+        CpuHeadroomResult halRet2 = CpuHeadroomResult.globalHeadroom(headroom2);
         when(mIPowerMock.getCpuHeadroom(eq(halParams2))).thenReturn(halRet2);
         float headroom3 = 0.3f;
         CpuHeadroomResult halRet3 = CpuHeadroomResult.globalHeadroom(headroom3);
@@ -1296,8 +1298,6 @@
         HintManagerService service = createService();
         clearInvocations(mIPowerMock);
 
-        service.getBinderServiceInstance().getCpuHeadroomMinIntervalMillis();
-        verify(mIPowerMock, times(0)).getCpuHeadroomMinIntervalMillis();
         assertEquals(halRet1, service.getBinderServiceInstance().getCpuHeadroom(params1));
         verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams1));
         assertEquals(halRet2, service.getBinderServiceInstance().getCpuHeadroom(params2));
@@ -1348,7 +1348,6 @@
 
     @Test
     public void testGpuHeadroomCache() throws Exception {
-        when(mIPowerMock.getGpuHeadroomMinIntervalMillis()).thenReturn(2000L);
         GpuHeadroomParamsInternal params1 = new GpuHeadroomParamsInternal();
         GpuHeadroomParams halParams1 = new GpuHeadroomParams();
         halParams1.calculationType = GpuHeadroomParams.CalculationType.MIN;
@@ -1369,8 +1368,6 @@
         HintManagerService service = createService();
         clearInvocations(mIPowerMock);
 
-        service.getBinderServiceInstance().getGpuHeadroomMinIntervalMillis();
-        verify(mIPowerMock, times(0)).getGpuHeadroomMinIntervalMillis();
         assertEquals(halRet1, service.getBinderServiceInstance().getGpuHeadroom(params1));
         assertEquals(halRet2, service.getBinderServiceInstance().getGpuHeadroom(params2));
         verify(mIPowerMock, times(2)).getGpuHeadroom(any());
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
index ac535b3..a2965b3 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
@@ -138,10 +138,12 @@
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.AdditionalAnswers;
 import org.mockito.ArgumentCaptor;
 import org.mockito.ArgumentMatchers;
 import org.mockito.Captor;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 import org.mockito.Spy;
 import org.mockito.internal.util.reflection.FieldReader;
@@ -259,6 +261,11 @@
                 mMockA11yController);
         when(mMockA11yController.isAccessibilityTracingEnabled()).thenReturn(false);
         when(mMockUserManagerInternal.isUserUnlockingOrUnlocked(anyInt())).thenReturn(true);
+        when(mMockSecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(anyInt()))
+                .then(AdditionalAnswers.returnsFirstArg());
+        when(mMockSecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(
+                eq(UserHandle.USER_CURRENT)))
+                .thenReturn(mTestableContext.getUserId());
 
         final ArrayList<Display> displays = new ArrayList<>();
         final Display defaultDisplay = new Display(DisplayManagerGlobal.getInstance(),
@@ -282,14 +289,21 @@
                 mInputFilter,
                 mProxyManager,
                 mFakePermissionEnforcer);
+        mA11yms.switchUser(mTestableContext.getUserId());
+        mTestableLooper.processAllMessages();
 
+        FieldSetter.setField(mA11yms,
+                AccessibilityManagerService.class.getDeclaredField("mHasInputFilter"), true);
+        FieldSetter.setField(mA11yms,
+                AccessibilityManagerService.class.getDeclaredField("mInputFilter"), mInputFilter);
         final AccessibilityUserState userState = new AccessibilityUserState(
-                mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
-        mA11yms.mUserStates.put(mA11yms.getCurrentUserIdLocked(), userState);
+                mTestableContext.getUserId(), mTestableContext, mA11yms);
+        mA11yms.mUserStates.put(userState.mUserId, userState);
         AccessibilityManager am = mTestableContext.getSystemService(AccessibilityManager.class);
         mA11yManagerServiceOnDevice = (IAccessibilityManager) new FieldReader(am,
                 AccessibilityManager.class.getDeclaredField("mService")).read();
         FieldSetter.setField(am, AccessibilityManager.class.getDeclaredField("mService"), mA11yms);
+        Mockito.clearInvocations(mMockMagnificationConnectionManager);
     }
 
     @After
@@ -652,7 +666,6 @@
                 mA11yms.getCurrentUserIdLocked());
         userState.setMagnificationCapabilitiesLocked(
                 ACCESSIBILITY_MAGNIFICATION_MODE_ALL);
-        //userState.setMagnificationSingleFingerTripleTapEnabledLocked(false);
         userState.setMagnificationSingleFingerTripleTapEnabledLocked(false);
 
         // Invokes client change to trigger onUserStateChanged.
@@ -1025,6 +1038,7 @@
         when(mMockSecurityPolicy.canRegisterService(any())).thenReturn(true);
 
         mA11yms.switchUser(mA11yms.getCurrentUserIdLocked() + 1);
+        mTestableLooper.processAllMessages();
 
         assertThat(lockState.get()).containsExactly(false);
     }
@@ -1114,9 +1128,6 @@
     @Test
     public void enableShortcutsForTargets_enableSoftwareShortcut_shortcutTurnedOn()
             throws Exception {
-        // TODO(b/111889696): Remove the user 0 assumption once we support multi-user
-        assumeTrue("The test is setup to run as a user 0",
-                isSameCurrentUser(mA11yms, mTestableContext));
         mFakePermissionEnforcer.grant(Manifest.permission.MANAGE_ACCESSIBILITY);
         setupShortcutTargetServices();
         String target = TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString();
@@ -1135,9 +1146,6 @@
 
     @Test
     public void enableHardwareShortcutsForTargets_shortcutDialogSetting_isShown() {
-        // TODO(b/111889696): Remove the user 0 assumption once we support multi-user
-        assumeTrue("The test is setup to run as a user 0",
-                isSameCurrentUser(mA11yms, mTestableContext));
         Settings.Secure.putInt(
                 mTestableContext.getContentResolver(),
                 Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
@@ -1165,9 +1173,6 @@
     @Test
     public void enableShortcutsForTargets_disableSoftwareShortcut_shortcutTurnedOff()
             throws Exception {
-        // TODO(b/111889696): Remove the user 0 assumption once we support multi-user
-        assumeTrue("The test is setup to run as a user 0",
-                isSameCurrentUser(mA11yms, mTestableContext));
         String target = TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString();
         enableShortcutsForTargets_enableSoftwareShortcut_shortcutTurnedOn();
 
@@ -1185,9 +1190,6 @@
 
     @Test
     public void enableShortcutsForTargets_enableSoftwareShortcutWithMagnification_menuSizeIncreased() {
-        // TODO(b/111889696): Remove the user 0 assumption once we support multi-user
-        assumeTrue("The test is setup to run as a user 0",
-                isSameCurrentUser(mA11yms, mTestableContext));
         mFakePermissionEnforcer.grant(Manifest.permission.MANAGE_ACCESSIBILITY);
 
         mA11yms.enableShortcutsForTargets(
@@ -1231,9 +1233,6 @@
     @Test
     public void enableShortcutsForTargets_enableAlwaysOnServiceSoftwareShortcut_turnsOnAlwaysOnService()
             throws Exception {
-        // TODO(b/111889696): Remove the user 0 assumption once we support multi-user
-        assumeTrue("The test is setup to run as a user 0",
-                isSameCurrentUser(mA11yms, mTestableContext));
         mFakePermissionEnforcer.grant(Manifest.permission.MANAGE_ACCESSIBILITY);
         setupShortcutTargetServices();
 
@@ -1254,9 +1253,6 @@
     @Test
     public void enableShortcutsForTargets_disableAlwaysOnServiceSoftwareShortcut_turnsOffAlwaysOnService()
             throws Exception {
-        // TODO(b/111889696): Remove the user 0 assumption once we support multi-user
-        assumeTrue("The test is setup to run as a user 0",
-                isSameCurrentUser(mA11yms, mTestableContext));
         enableShortcutsForTargets_enableAlwaysOnServiceSoftwareShortcut_turnsOnAlwaysOnService();
 
         mA11yms.enableShortcutsForTargets(
@@ -1296,9 +1292,6 @@
     @Test
     public void enableShortcutsForTargets_disableStandardServiceSoftwareShortcutWithServiceOn_wontTurnOffService()
             throws Exception {
-        // TODO(b/111889696): Remove the user 0 assumption once we support multi-user
-        assumeTrue("The test is setup to run as a user 0",
-                isSameCurrentUser(mA11yms, mTestableContext));
         enableShortcutsForTargets_enableStandardServiceSoftwareShortcut_wontTurnOnService();
         AccessibilityUtils.setAccessibilityServiceState(
                 mTestableContext, TARGET_STANDARD_A11Y_SERVICE, /* enabled= */ true);
@@ -1319,9 +1312,6 @@
 
     @Test
     public void enableShortcutsForTargets_enableTripleTapShortcut_settingUpdated() {
-        // TODO(b/111889696): Remove the user 0 assumption once we support multi-user
-        assumeTrue("The test is setup to run as a user 0",
-                isSameCurrentUser(mA11yms, mTestableContext));
         mFakePermissionEnforcer.grant(Manifest.permission.MANAGE_ACCESSIBILITY);
 
         mA11yms.enableShortcutsForTargets(
@@ -1341,9 +1331,6 @@
 
     @Test
     public void enableShortcutsForTargets_disableTripleTapShortcut_settingUpdated() {
-        // TODO(b/111889696): Remove the user 0 assumption once we support multi-user
-        assumeTrue("The test is setup to run as a user 0",
-                isSameCurrentUser(mA11yms, mTestableContext));
         enableShortcutsForTargets_enableTripleTapShortcut_settingUpdated();
 
         mA11yms.enableShortcutsForTargets(
@@ -1362,9 +1349,6 @@
 
     @Test
     public void enableShortcutsForTargets_enableMultiFingerMultiTapsShortcut_settingUpdated() {
-        // TODO(b/111889696): Remove the user 0 assumption once we support multi-user
-        assumeTrue("The test is setup to run as a user 0",
-                isSameCurrentUser(mA11yms, mTestableContext));
         mFakePermissionEnforcer.grant(Manifest.permission.MANAGE_ACCESSIBILITY);
 
         mA11yms.enableShortcutsForTargets(
@@ -1384,9 +1368,6 @@
 
     @Test
     public void enableShortcutsForTargets_disableMultiFingerMultiTapsShortcut_settingUpdated() {
-        // TODO(b/111889696): Remove the user 0 assumption once we support multi-user
-        assumeTrue("The test is setup to run as a user 0",
-                isSameCurrentUser(mA11yms, mTestableContext));
         enableShortcutsForTargets_enableMultiFingerMultiTapsShortcut_settingUpdated();
 
         mA11yms.enableShortcutsForTargets(
@@ -1406,9 +1387,6 @@
 
     @Test
     public void enableShortcutsForTargets_enableVolumeKeysShortcut_shortcutSet() {
-        // TODO(b/111889696): Remove the user 0 assumption once we support multi-user
-        assumeTrue("The test is setup to run as a user 0",
-                isSameCurrentUser(mA11yms, mTestableContext));
         mFakePermissionEnforcer.grant(Manifest.permission.MANAGE_ACCESSIBILITY);
         setupShortcutTargetServices();
 
@@ -1428,9 +1406,6 @@
 
     @Test
     public void enableShortcutsForTargets_disableVolumeKeysShortcut_shortcutNotSet() {
-        // TODO(b/111889696): Remove the user 0 assumption once we support multi-user
-        assumeTrue("The test is setup to run as a user 0",
-                isSameCurrentUser(mA11yms, mTestableContext));
         enableShortcutsForTargets_enableVolumeKeysShortcut_shortcutSet();
 
         mA11yms.enableShortcutsForTargets(
@@ -1450,9 +1425,6 @@
 
     @Test
     public void enableShortcutsForTargets_enableQuickSettings_shortcutSet() {
-        // TODO(b/111889696): Remove the user 0 assumption once we support multi-user
-        assumeTrue("The test is setup to run as a user 0",
-                isSameCurrentUser(mA11yms, mTestableContext));
         mFakePermissionEnforcer.grant(Manifest.permission.MANAGE_ACCESSIBILITY);
         setupShortcutTargetServices();
 
@@ -1478,9 +1450,6 @@
 
     @Test
     public void enableShortcutsForTargets_disableQuickSettings_shortcutNotSet() {
-        // TODO(b/111889696): Remove the user 0 assumption once we support multi-user
-        assumeTrue("The test is setup to run as a user 0",
-                isSameCurrentUser(mA11yms, mTestableContext));
         enableShortcutsForTargets_enableQuickSettings_shortcutSet();
 
         mA11yms.enableShortcutsForTargets(
@@ -1684,14 +1653,17 @@
     @Test
     @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
     public void restoreShortcutTargets_qs_a11yQsTargetsRestored() {
+        // TODO: remove the assumption when we fix b/381294327
+        assumeTrue("The test is setup to run as a user 0",
+                mTestableContext.getUserId() == UserHandle.USER_SYSTEM);
         String daltonizerTile =
                 AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME.flattenToString();
         String colorInversionTile =
                 AccessibilityShortcutController.COLOR_INVERSION_COMPONENT_NAME.flattenToString();
         final AccessibilityUserState userState = new AccessibilityUserState(
-                UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
+                mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
         userState.updateShortcutTargetsLocked(Set.of(daltonizerTile), QUICK_SETTINGS);
-        mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+        mA11yms.mUserStates.put(userState.mUserId, userState);
 
         broadcastSettingRestored(
                 ShortcutUtils.convertToKey(QUICK_SETTINGS),
@@ -1707,15 +1679,18 @@
     @Test
     @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
     public void restoreShortcutTargets_qs_a11yQsTargetsNotRestored() {
+        // TODO: remove the assumption when we fix b/381294327
+        assumeTrue("The test is setup to run as a user 0",
+                mTestableContext.getUserId() == UserHandle.USER_SYSTEM);
         String daltonizerTile =
                 AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME.flattenToString();
         String colorInversionTile =
                 AccessibilityShortcutController.COLOR_INVERSION_COMPONENT_NAME.flattenToString();
         final AccessibilityUserState userState = new AccessibilityUserState(
-                UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
+                mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
         userState.updateShortcutTargetsLocked(Set.of(daltonizerTile), QUICK_SETTINGS);
         putShortcutSettingForUser(QUICK_SETTINGS, daltonizerTile, userState.mUserId);
-        mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+        mA11yms.mUserStates.put(userState.mUserId, userState);
 
         broadcastSettingRestored(
                 ShortcutUtils.convertToKey(QUICK_SETTINGS),
@@ -1739,13 +1714,13 @@
                 ComponentName::getPackageName).toList().toArray(new String[0]);
 
         PackageMonitor monitor = spy(mA11yms.getPackageMonitor());
-        when(monitor.getChangingUserId()).thenReturn(UserHandle.USER_SYSTEM);
+        when(monitor.getChangingUserId()).thenReturn(userState.mUserId);
         mA11yms.setPackageMonitor(monitor);
 
         assertTrue(mA11yms.getPackageMonitor().onHandleForceStop(
                 new Intent(),
                 packages,
-                UserHandle.USER_SYSTEM,
+                userState.mUserId,
                 false
         ));
     }
@@ -1761,13 +1736,13 @@
                 ComponentName::getPackageName).toList().toArray(new String[0]);
 
         PackageMonitor monitor = spy(mA11yms.getPackageMonitor());
-        when(monitor.getChangingUserId()).thenReturn(UserHandle.USER_SYSTEM);
+        when(monitor.getChangingUserId()).thenReturn(userState.mUserId);
         mA11yms.setPackageMonitor(monitor);
 
         assertFalse(mA11yms.getPackageMonitor().onHandleForceStop(
                 new Intent(),
                 packages,
-                UserHandle.USER_SYSTEM,
+                userState.mUserId,
                 true
         ));
     }
@@ -1775,27 +1750,29 @@
     @Test
     public void onHandleForceStop_dontDoIt_packageNotEnabled_returnsFalse() {
         PackageMonitor monitor = spy(mA11yms.getPackageMonitor());
-        when(monitor.getChangingUserId()).thenReturn(UserHandle.USER_SYSTEM);
+        when(monitor.getChangingUserId()).thenReturn(mA11yms.getCurrentUserIdLocked());
         mA11yms.setPackageMonitor(monitor);
 
         assertFalse(mA11yms.getPackageMonitor().onHandleForceStop(
                 new Intent(),
                 new String[]{"FOO", "BAR"},
-                UserHandle.USER_SYSTEM,
+                mA11yms.getCurrentUserIdLocked(),
                 false
         ));
     }
 
     @Test
-    @EnableFlags(android.view.accessibility.Flags.FLAG_RESTORE_A11Y_SHORTCUT_TARGET_SERVICE)
     public void restoreShortcutTargets_hardware_targetsMerged() {
+        // TODO: remove the assumption when we fix b/381294327
+        assumeTrue("The test is setup to run as a user 0",
+                mTestableContext.getUserId() == UserHandle.USER_SYSTEM);
         mFakePermissionEnforcer.grant(Manifest.permission.MANAGE_ACCESSIBILITY);
         final String servicePrevious = TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString();
         final String otherPrevious = TARGET_MAGNIFICATION;
         final String serviceRestored = TARGET_STANDARD_A11Y_SERVICE_NAME;
         final AccessibilityUserState userState = new AccessibilityUserState(
-                UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
-        mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+                mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
+        mA11yms.mUserStates.put(userState.mUserId, userState);
         setupShortcutTargetServices(userState);
         mA11yms.enableShortcutsForTargets(
                 true, HARDWARE, List.of(servicePrevious, otherPrevious), userState.mUserId);
@@ -1812,18 +1789,20 @@
     }
 
     @Test
-    @EnableFlags(android.view.accessibility.Flags.FLAG_RESTORE_A11Y_SHORTCUT_TARGET_SERVICE)
     public void restoreShortcutTargets_hardware_alreadyHadDefaultService_doesNotClear() {
+        // TODO: remove the assumption when we fix b/381294327
+        assumeTrue("The test is setup to run as a user 0",
+                mTestableContext.getUserId() == UserHandle.USER_SYSTEM);
         final String serviceDefault = TARGET_STANDARD_A11Y_SERVICE_NAME;
         mTestableContext.getOrCreateTestableResources().addOverride(
                 R.string.config_defaultAccessibilityService, serviceDefault);
         final AccessibilityUserState userState = new AccessibilityUserState(
-                UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
-        mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+                mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
+        mA11yms.mUserStates.put(userState.mUserId, userState);
         setupShortcutTargetServices(userState);
 
         // default is present in userState & setting, so it's not cleared
-        putShortcutSettingForUser(HARDWARE, serviceDefault, UserHandle.USER_SYSTEM);
+        putShortcutSettingForUser(HARDWARE, serviceDefault, userState.mUserId);
         userState.updateShortcutTargetsLocked(Set.of(serviceDefault), HARDWARE);
 
         broadcastSettingRestored(
@@ -1838,8 +1817,10 @@
     }
 
     @Test
-    @EnableFlags(android.view.accessibility.Flags.FLAG_RESTORE_A11Y_SHORTCUT_TARGET_SERVICE)
     public void restoreShortcutTargets_hardware_didNotHaveDefaultService_clearsDefaultService() {
+        // TODO: remove the assumption when we fix b/381294327
+        assumeTrue("The test is setup to run as a user 0",
+                mTestableContext.getUserId() == UserHandle.USER_SYSTEM);
         final String serviceDefault = TARGET_STANDARD_A11Y_SERVICE_NAME;
         final String serviceRestored = TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString();
         // Restored value from the broadcast contains both default and non-default service.
@@ -1847,8 +1828,8 @@
         mTestableContext.getOrCreateTestableResources().addOverride(
                 R.string.config_defaultAccessibilityService, serviceDefault);
         final AccessibilityUserState userState = new AccessibilityUserState(
-                UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
-        mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+                mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
+        mA11yms.mUserStates.put(userState.mUserId, userState);
         setupShortcutTargetServices(userState);
 
         broadcastSettingRestored(ShortcutUtils.convertToKey(HARDWARE),
@@ -1863,8 +1844,10 @@
     }
 
     @Test
-    @EnableFlags(Flags.FLAG_CLEAR_DEFAULT_FROM_A11Y_SHORTCUT_TARGET_SERVICE_RESTORE)
     public void restoreShortcutTargets_hardware_nullSetting_clearsDefaultService() {
+        // TODO: remove the assumption when we fix b/381294327
+        assumeTrue("The test is setup to run as a user 0",
+                mTestableContext.getUserId() == UserHandle.USER_SYSTEM);
         final String serviceDefault = TARGET_STANDARD_A11Y_SERVICE_NAME;
         final String serviceRestored = TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString();
         // Restored value from the broadcast contains both default and non-default service.
@@ -1872,13 +1855,13 @@
         mTestableContext.getOrCreateTestableResources().addOverride(
                 R.string.config_defaultAccessibilityService, serviceDefault);
         final AccessibilityUserState userState = new AccessibilityUserState(
-                UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
-        mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+                mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
+        mA11yms.mUserStates.put(userState.mUserId, userState);
         setupShortcutTargetServices(userState);
 
         // UserState has default, but setting is null (this emulates a typical scenario in SUW).
         userState.updateShortcutTargetsLocked(Set.of(serviceDefault), HARDWARE);
-        putShortcutSettingForUser(HARDWARE, null, UserHandle.USER_SYSTEM);
+        putShortcutSettingForUser(HARDWARE, null, userState.mUserId);
 
         broadcastSettingRestored(ShortcutUtils.convertToKey(HARDWARE),
                 /*newValue=*/combinedRestored);
@@ -1896,8 +1879,8 @@
     public void onNavButtonNavigation_migratesGestureTargets() {
         mFakePermissionEnforcer.grant(Manifest.permission.STATUS_BAR_SERVICE);
         final AccessibilityUserState userState = new AccessibilityUserState(
-                UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
-        mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+                mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
+        mA11yms.mUserStates.put(userState.mUserId, userState);
         setupShortcutTargetServices(userState);
         userState.updateShortcutTargetsLocked(
                 Set.of(TARGET_STANDARD_A11Y_SERVICE_NAME), SOFTWARE);
@@ -1920,20 +1903,20 @@
     public void onNavButtonNavigation_gestureTargets_noButtonTargets_navBarButtonMode() {
         mFakePermissionEnforcer.grant(Manifest.permission.STATUS_BAR_SERVICE);
         final AccessibilityUserState userState = new AccessibilityUserState(
-                UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
-        mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+                mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
+        mA11yms.mUserStates.put(userState.mUserId, userState);
         setupShortcutTargetServices(userState);
         userState.updateShortcutTargetsLocked(Set.of(), SOFTWARE);
         userState.updateShortcutTargetsLocked(
                 Set.of(TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString()), GESTURE);
         ShortcutUtils.setButtonMode(
-                mTestableContext, ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU, UserHandle.USER_SYSTEM);
+                mTestableContext, ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU, userState.mUserId);
 
         Settings.Secure.putIntForUser(mTestableContext.getContentResolver(),
                 NAVIGATION_MODE, NAV_BAR_MODE_3BUTTON, userState.mUserId);
         mA11yms.updateShortcutsForCurrentNavigationMode();
 
-        assertThat(ShortcutUtils.getButtonMode(mTestableContext, UserHandle.USER_SYSTEM))
+        assertThat(ShortcutUtils.getButtonMode(mTestableContext, userState.mUserId))
                 .isEqualTo(ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR);
     }
 
@@ -1942,11 +1925,11 @@
     public void onGestureNavigation_floatingMenuMode() {
         mFakePermissionEnforcer.grant(Manifest.permission.STATUS_BAR_SERVICE);
         final AccessibilityUserState userState = new AccessibilityUserState(
-                UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
-        mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+                mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
+        mA11yms.mUserStates.put(userState.mUserId, userState);
         setupShortcutTargetServices(userState);
         ShortcutUtils.setButtonMode(
-                mTestableContext, ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, UserHandle.USER_SYSTEM);
+                mTestableContext, ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, userState.mUserId);
 
         Settings.Secure.putIntForUser(mTestableContext.getContentResolver(),
                 NAVIGATION_MODE, NAV_BAR_MODE_GESTURAL, userState.mUserId);
@@ -1961,8 +1944,8 @@
     public void onNavigation_revertGestureTargets() {
         mFakePermissionEnforcer.grant(Manifest.permission.STATUS_BAR_SERVICE);
         final AccessibilityUserState userState = new AccessibilityUserState(
-                UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
-        mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+                mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
+        mA11yms.mUserStates.put(userState.mUserId, userState);
         setupShortcutTargetServices(userState);
         userState.updateShortcutTargetsLocked(
                 Set.of(TARGET_STANDARD_A11Y_SERVICE_NAME), SOFTWARE);
@@ -1985,8 +1968,8 @@
     public void onNavigation_gestureNavigation_gestureButtonMode_migratesTargetsToGesture() {
         mFakePermissionEnforcer.grant(Manifest.permission.STATUS_BAR_SERVICE);
         final AccessibilityUserState userState = new AccessibilityUserState(
-                UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
-        mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+                mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
+        mA11yms.mUserStates.put(userState.mUserId, userState);
         setupShortcutTargetServices(userState);
         userState.updateShortcutTargetsLocked(Set.of(
                 TARGET_STANDARD_A11Y_SERVICE_NAME,
@@ -1994,7 +1977,7 @@
         userState.updateShortcutTargetsLocked(Set.of(), GESTURE);
 
         ShortcutUtils.setButtonMode(
-                mTestableContext, ACCESSIBILITY_BUTTON_MODE_GESTURE, UserHandle.USER_SYSTEM);
+                mTestableContext, ACCESSIBILITY_BUTTON_MODE_GESTURE, userState.mUserId);
         Settings.Secure.putIntForUser(mTestableContext.getContentResolver(),
                 NAVIGATION_MODE, NAV_BAR_MODE_GESTURAL, userState.mUserId);
         mA11yms.updateShortcutsForCurrentNavigationMode();
@@ -2010,11 +1993,11 @@
     @DisableFlags(android.provider.Flags.FLAG_A11Y_STANDALONE_GESTURE_ENABLED)
     public void onNavigation_gestureNavigation_correctsButtonMode() {
         final AccessibilityUserState userState = new AccessibilityUserState(
-                UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
-        mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+                mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
+        mA11yms.mUserStates.put(userState.mUserId, userState);
         setupShortcutTargetServices(userState);
         ShortcutUtils.setButtonMode(
-                mTestableContext, ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, UserHandle.USER_SYSTEM);
+                mTestableContext, ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, userState.mUserId);
 
         Settings.Secure.putIntForUser(mTestableContext.getContentResolver(),
                 NAVIGATION_MODE, NAV_BAR_MODE_GESTURAL, userState.mUserId);
@@ -2028,11 +2011,11 @@
     @DisableFlags(android.provider.Flags.FLAG_A11Y_STANDALONE_GESTURE_ENABLED)
     public void onNavigation_navBarNavigation_correctsButtonMode() {
         final AccessibilityUserState userState = new AccessibilityUserState(
-                UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
-        mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+                mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
+        mA11yms.mUserStates.put(userState.mUserId, userState);
         setupShortcutTargetServices(userState);
         ShortcutUtils.setButtonMode(
-                mTestableContext, ACCESSIBILITY_BUTTON_MODE_GESTURE, UserHandle.USER_SYSTEM);
+                mTestableContext, ACCESSIBILITY_BUTTON_MODE_GESTURE, userState.mUserId);
 
         Settings.Secure.putIntForUser(mTestableContext.getContentResolver(),
                 NAVIGATION_MODE, NAV_BAR_MODE_3BUTTON, userState.mUserId);
@@ -2046,8 +2029,8 @@
     public void showAccessibilityTargetSelection_navBarNavigationMode_softwareExtra() {
         mFakePermissionEnforcer.grant(Manifest.permission.STATUS_BAR_SERVICE);
         final AccessibilityUserState userState = new AccessibilityUserState(
-                UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
-        mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+                mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
+        mA11yms.mUserStates.put(userState.mUserId, userState);
         Settings.Secure.putIntForUser(mTestableContext.getContentResolver(),
                 NAVIGATION_MODE, NAV_BAR_MODE_3BUTTON, userState.mUserId);
 
@@ -2062,8 +2045,8 @@
     public void showAccessibilityTargetSelection_gestureNavigationMode_softwareExtra() {
         mFakePermissionEnforcer.grant(Manifest.permission.STATUS_BAR_SERVICE);
         final AccessibilityUserState userState = new AccessibilityUserState(
-                UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
-        mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+                mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
+        mA11yms.mUserStates.put(userState.mUserId, userState);
         Settings.Secure.putIntForUser(mTestableContext.getContentResolver(),
                 NAVIGATION_MODE, NAV_BAR_MODE_GESTURAL, userState.mUserId);
 
@@ -2078,8 +2061,8 @@
     public void showAccessibilityTargetSelection_gestureNavigationMode_gestureExtra() {
         mFakePermissionEnforcer.grant(Manifest.permission.STATUS_BAR_SERVICE);
         final AccessibilityUserState userState = new AccessibilityUserState(
-                UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
-        mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+                mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
+        mA11yms.mUserStates.put(userState.mUserId, userState);
         Settings.Secure.putIntForUser(mTestableContext.getContentResolver(),
                 NAVIGATION_MODE, NAV_BAR_MODE_GESTURAL, userState.mUserId);
 
@@ -2113,18 +2096,19 @@
     public void switchUser_callsUserInitializationCompleteCallback() throws RemoteException {
         mA11yms.mUserInitializationCompleteCallbacks.add(mUserInitializationCompleteCallback);
 
-        mA11yms.switchUser(UserHandle.MIN_SECONDARY_USER_ID);
+        int newUserId = mA11yms.getCurrentUserIdLocked() + 1;
+        mA11yms.switchUser(newUserId);
+        mTestableLooper.processAllMessages();
 
-        verify(mUserInitializationCompleteCallback).onUserInitializationComplete(
-                UserHandle.MIN_SECONDARY_USER_ID);
+        verify(mUserInitializationCompleteCallback).onUserInitializationComplete(newUserId);
     }
 
     @Test
     @DisableFlags(android.provider.Flags.FLAG_A11Y_STANDALONE_GESTURE_ENABLED)
     public void getShortcutTypeForGenericShortcutCalls_softwareType() {
         final AccessibilityUserState userState = new AccessibilityUserState(
-                UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
-        mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+                mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
+        mA11yms.mUserStates.put(userState.mUserId, userState);
 
         assertThat(mA11yms.getShortcutTypeForGenericShortcutCalls(userState.mUserId))
                 .isEqualTo(SOFTWARE);
@@ -2134,8 +2118,8 @@
     @EnableFlags(android.provider.Flags.FLAG_A11Y_STANDALONE_GESTURE_ENABLED)
     public void getShortcutTypeForGenericShortcutCalls_gestureNavigationMode_gestureType() {
         final AccessibilityUserState userState = new AccessibilityUserState(
-                UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
-        mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+                mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
+        mA11yms.mUserStates.put(userState.mUserId, userState);
         Settings.Secure.putIntForUser(mTestableContext.getContentResolver(),
                 NAVIGATION_MODE, NAV_BAR_MODE_GESTURAL, userState.mUserId);
 
@@ -2147,8 +2131,8 @@
     @EnableFlags(android.provider.Flags.FLAG_A11Y_STANDALONE_GESTURE_ENABLED)
     public void getShortcutTypeForGenericShortcutCalls_buttonNavigationMode_softwareType() {
         final AccessibilityUserState userState = new AccessibilityUserState(
-                UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
-        mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+                mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
+        mA11yms.mUserStates.put(userState.mUserId, userState);
         Settings.Secure.putIntForUser(mTestableContext.getContentResolver(),
                 NAVIGATION_MODE, NAV_BAR_MODE_3BUTTON, userState.mUserId);
 
@@ -2339,13 +2323,13 @@
     private Set<String> readStringsFromSetting(String setting) {
         final Set<String> result = new ArraySet<>();
         mA11yms.readColonDelimitedSettingToSet(
-                setting, UserHandle.USER_SYSTEM, str -> str, result);
+                setting, mA11yms.getCurrentUserIdLocked(), str -> str, result);
         return result;
     }
 
     private void writeStringsToSetting(Set<String> strings, String setting) {
         mA11yms.persistColonDelimitedSetToSettingLocked(
-                setting, UserHandle.USER_SYSTEM, strings, str -> str);
+                setting, mA11yms.getCurrentUserIdLocked(), strings, str -> str);
     }
 
     private void broadcastSettingRestored(String setting, String newValue) {
@@ -2516,10 +2500,6 @@
         }
     }
 
-    private static boolean isSameCurrentUser(AccessibilityManagerService service, Context context) {
-        return service.getCurrentUserIdLocked() == context.getUserId();
-    }
-
     private void putShortcutSettingForUser(@UserShortcutType int shortcutType,
             String shortcutValue, int userId) {
         Settings.Secure.putStringForUser(
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 9cd3186..605fed0 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
@@ -38,6 +38,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.annotation.UserIdInt;
 import android.app.AppOpsManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -92,6 +93,8 @@
 
     private static final String TEST_OP_PACKAGE_NAME = "test_package";
 
+    private final @UserIdInt int mUserId = UserHandle.getCallingUserId();
+
     private AuthService mAuthService;
 
     @Rule
@@ -257,12 +260,11 @@
         final Binder token = new Binder();
         final PromptInfo promptInfo = new PromptInfo();
         final long sessionId = 0;
-        final int userId = 0;
 
         mAuthService.mImpl.authenticate(
                 token,
                 sessionId,
-                userId,
+                mUserId,
                 mReceiver,
                 TEST_OP_PACKAGE_NAME,
                 promptInfo);
@@ -270,7 +272,7 @@
         verify(mBiometricService).authenticate(
                 eq(token),
                 eq(sessionId),
-                eq(userId),
+                eq(mUserId),
                 eq(mReceiver),
                 eq(TEST_OP_PACKAGE_NAME),
                 eq(promptInfo));
@@ -286,12 +288,11 @@
         final Binder token = new Binder();
         final PromptInfo promptInfo = new PromptInfo();
         final long sessionId = 0;
-        final int userId = 0;
 
         mAuthService.mImpl.authenticate(
                 token,
                 sessionId,
-                userId,
+                mUserId,
                 mReceiver,
                 TEST_OP_PACKAGE_NAME,
                 promptInfo);
@@ -299,7 +300,7 @@
         verify(mBiometricService, never()).authenticate(
                 eq(token),
                 eq(sessionId),
-                eq(userId),
+                eq(mUserId),
                 eq(mReceiver),
                 eq(TEST_OP_PACKAGE_NAME),
                 eq(promptInfo));
@@ -313,12 +314,11 @@
 
         final PromptInfo promptInfo = new PromptInfo();
         final long sessionId = 0;
-        final int userId = 0;
 
         mAuthService.mImpl.authenticate(
                 null /* token */,
                 sessionId,
-                userId,
+                mUserId,
                 mReceiver,
                 TEST_OP_PACKAGE_NAME,
                 promptInfo);
@@ -338,7 +338,7 @@
         mAuthService.mImpl.authenticate(
                 token,
                 0, /* sessionId */
-                0, /* userId */
+                mUserId,
                 mReceiver,
                 TEST_OP_PACKAGE_NAME,
                 new PromptInfo());
@@ -356,7 +356,7 @@
         mAuthService.mImpl.authenticate(
                 token,
                 0, /* sessionId */
-                0, /* userId */
+                mUserId,
                 mReceiver,
                 TEST_OP_PACKAGE_NAME,
                 new PromptInfo());
@@ -414,20 +414,19 @@
         mAuthService = new AuthService(mContext, mInjector);
         mAuthService.onStart();
 
-        final int userId = 0;
         final int expectedResult = BIOMETRIC_SUCCESS;
         final int authenticators = 0;
         when(mBiometricService.canAuthenticate(anyString(), anyInt(), anyInt(), anyInt()))
                 .thenReturn(expectedResult);
 
         final int result = mAuthService.mImpl
-                .canAuthenticate(TEST_OP_PACKAGE_NAME, userId, authenticators);
+                .canAuthenticate(TEST_OP_PACKAGE_NAME, mUserId, authenticators);
 
         assertEquals(expectedResult, result);
         waitForIdle();
         verify(mBiometricService).canAuthenticate(
                 eq(TEST_OP_PACKAGE_NAME),
-                eq(userId),
+                eq(mUserId),
                 eq(UserHandle.getCallingUserId()),
                 eq(authenticators));
     }
@@ -440,18 +439,17 @@
         mAuthService = new AuthService(mContext, mInjector);
         mAuthService.onStart();
 
-        final int userId = 0;
         final boolean expectedResult = true;
         when(mBiometricService.hasEnrolledBiometrics(anyInt(), anyString())).thenReturn(
                 expectedResult);
 
-        final boolean result = mAuthService.mImpl.hasEnrolledBiometrics(userId,
+        final boolean result = mAuthService.mImpl.hasEnrolledBiometrics(mUserId,
                 TEST_OP_PACKAGE_NAME);
 
         assertEquals(expectedResult, result);
         waitForIdle();
         verify(mBiometricService).hasEnrolledBiometrics(
-                eq(userId),
+                eq(mUserId),
                 eq(TEST_OP_PACKAGE_NAME));
     }
 
@@ -528,13 +526,12 @@
         mAuthService = new AuthService(mContext, mInjector);
         mAuthService.onStart();
 
-        final int userId = 0;
         final int authenticators = BiometricManager.Authenticators.BIOMETRIC_STRONG;
 
-        mAuthService.mImpl.getLastAuthenticationTime(userId, authenticators);
+        mAuthService.mImpl.getLastAuthenticationTime(mUserId, authenticators);
 
         waitForIdle();
-        verify(mBiometricService).getLastAuthenticationTime(eq(userId), eq(authenticators));
+        verify(mBiometricService).getLastAuthenticationTime(eq(mUserId), eq(authenticators));
     }
 
     private static void setInternalAndTestBiometricPermissions(
diff --git a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
deleted file mode 100644
index fd22118..0000000
--- a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.integrity;
-
-import static android.content.integrity.AppIntegrityManager.EXTRA_STATUS;
-import static android.content.integrity.AppIntegrityManager.STATUS_FAILURE;
-import static android.content.integrity.AppIntegrityManager.STATUS_SUCCESS;
-import static android.content.integrity.InstallerAllowedByManifestFormula.INSTALLER_CERTIFICATE_NOT_EVALUATED;
-import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ID;
-import static android.content.pm.PackageManager.EXTRA_VERIFICATION_INSTALLER_PACKAGE;
-import static android.content.pm.PackageManager.EXTRA_VERIFICATION_INSTALLER_UID;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.IntentSender;
-import android.content.integrity.AppInstallMetadata;
-import android.content.integrity.AtomicFormula;
-import android.content.integrity.IntegrityFormula;
-import android.content.integrity.Rule;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
-import android.content.pm.ParceledListSlice;
-import android.content.res.Resources;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Message;
-import android.provider.Settings;
-
-import androidx.test.InstrumentationRegistry;
-
-import com.android.internal.R;
-import com.android.server.compat.PlatformCompat;
-import com.android.server.testutils.TestUtils;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.file.Files;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Supplier;
-
-/** Unit test for {@link com.android.server.integrity.AppIntegrityManagerServiceImpl} */
-@RunWith(JUnit4.class)
-public class AppIntegrityManagerServiceImplTest {
-    private static final String TEST_APP_PATH =
-            "AppIntegrityManagerServiceImplTest/AppIntegrityManagerServiceTestApp.apk";
-
-    private static final String TEST_APP_TWO_CERT_PATH =
-            "AppIntegrityManagerServiceImplTest/DummyAppTwoCerts.apk";
-
-    private static final String TEST_APP_SOURCE_STAMP_PATH =
-            "AppIntegrityManagerServiceImplTest/SourceStampTestApk.apk";
-
-    private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
-    private static final String VERSION = "version";
-    private static final String TEST_FRAMEWORK_PACKAGE = "com.android.frameworks.servicestests";
-
-    private static final String PACKAGE_NAME = "com.test.app";
-
-    private static final long VERSION_CODE = 100;
-    private static final String INSTALLER = "com.long.random.test.installer.name";
-
-    // These are obtained by running the test and checking logcat.
-    private static final String APP_CERT =
-            "F14CFECF5070874C05D3D2FA98E046BE20BDE02A0DC74BAF6B59C6A0E4C06850";
-    // We use SHA256 for package names longer than 32 characters.
-    private static final String INSTALLER_SHA256 =
-            "30F41A7CBF96EE736A54DD6DF759B50ED3CC126ABCEF694E167C324F5976C227";
-    private static final String SOURCE_STAMP_CERTIFICATE_HASH =
-            "C6E737809CEF2B08CC6694892215F82A5E8FBC3C2A0F6212770310B90622D2D9";
-
-    private static final String DUMMY_APP_TWO_CERTS_CERT_1 =
-            "C0369C2A1096632429DFA8433068AECEAD00BAC337CA92A175036D39CC9AFE94";
-    private static final String DUMMY_APP_TWO_CERTS_CERT_2 =
-            "94366E0A80F3A3F0D8171A15760B88E228CD6E1101F0414C98878724FBE70147";
-
-    private static final String PLAY_STORE_PKG = "com.android.vending";
-    private static final String ADB_INSTALLER = "adb";
-    private static final String PLAY_STORE_CERT = "play_store_cert";
-
-    @org.junit.Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
-
-    @Mock PackageManagerInternal mPackageManagerInternal;
-    @Mock PlatformCompat mPlatformCompat;
-    @Mock Context mMockContext;
-    @Mock Resources mMockResources;
-    @Mock Handler mHandler;
-
-    private final Context mRealContext = InstrumentationRegistry.getTargetContext();
-
-    private PackageManager mSpyPackageManager;
-    private File mTestApk;
-    private File mTestApkTwoCerts;
-    private File mTestApkSourceStamp;
-
-    // under test
-    private AppIntegrityManagerServiceImpl mService;
-
-    @Before
-    public void setup() throws Exception {
-        mTestApk = File.createTempFile("AppIntegrity", ".apk");
-        try (InputStream inputStream = mRealContext.getAssets().open(TEST_APP_PATH)) {
-            Files.copy(inputStream, mTestApk.toPath(), REPLACE_EXISTING);
-        }
-
-        mTestApkTwoCerts = File.createTempFile("AppIntegrityTwoCerts", ".apk");
-        try (InputStream inputStream = mRealContext.getAssets().open(TEST_APP_TWO_CERT_PATH)) {
-            Files.copy(inputStream, mTestApkTwoCerts.toPath(), REPLACE_EXISTING);
-        }
-
-        mTestApkSourceStamp = File.createTempFile("AppIntegritySourceStamp", ".apk");
-        try (InputStream inputStream = mRealContext.getAssets().open(TEST_APP_SOURCE_STAMP_PATH)) {
-            Files.copy(inputStream, mTestApkSourceStamp.toPath(), REPLACE_EXISTING);
-        }
-
-        mService =
-                new AppIntegrityManagerServiceImpl(
-                        mMockContext,
-                        mPackageManagerInternal,
-                        mHandler);
-
-        mSpyPackageManager = spy(mRealContext.getPackageManager());
-        // setup mocks to prevent NPE
-        when(mMockContext.getPackageManager()).thenReturn(mSpyPackageManager);
-        when(mMockContext.getResources()).thenReturn(mMockResources);
-        when(mMockResources.getStringArray(anyInt())).thenReturn(new String[] {});
-        // These are needed to override the Settings.Global.get result.
-        when(mMockContext.getContentResolver()).thenReturn(mRealContext.getContentResolver());
-        setIntegrityCheckIncludesRuleProvider(true);
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        mTestApk.delete();
-        mTestApkTwoCerts.delete();
-        mTestApkSourceStamp.delete();
-    }
-
-    @Test
-    public void broadcastReceiverRegistration() throws Exception {
-        allowlistUsAsRuleProvider();
-        makeUsSystemApp();
-        ArgumentCaptor<IntentFilter> intentFilterCaptor =
-                ArgumentCaptor.forClass(IntentFilter.class);
-
-        verify(mMockContext).registerReceiver(any(), intentFilterCaptor.capture(), any(), any());
-        assertEquals(1, intentFilterCaptor.getValue().countActions());
-        assertEquals(
-                Intent.ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION,
-                intentFilterCaptor.getValue().getAction(0));
-        assertEquals(1, intentFilterCaptor.getValue().countDataTypes());
-        assertEquals(PACKAGE_MIME_TYPE, intentFilterCaptor.getValue().getDataType(0));
-    }
-
-    @Test
-    public void handleBroadcast_allow() throws Exception {
-        allowlistUsAsRuleProvider();
-        makeUsSystemApp();
-        ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
-                ArgumentCaptor.forClass(BroadcastReceiver.class);
-        verify(mMockContext)
-                .registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
-        Intent intent = makeVerificationIntent();
-
-        broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent);
-        runJobInHandler();
-
-        verify(mPackageManagerInternal)
-                .setIntegrityVerificationResult(
-                        1, PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW);
-    }
-
-    private void allowlistUsAsRuleProvider() {
-        Resources mockResources = mock(Resources.class);
-        when(mockResources.getStringArray(R.array.config_integrityRuleProviderPackages))
-                .thenReturn(new String[] {TEST_FRAMEWORK_PACKAGE});
-        when(mMockContext.getResources()).thenReturn(mockResources);
-    }
-
-    private void runJobInHandler() {
-        ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
-        // sendMessageAtTime is the first non-final method in the call chain when "post" is invoked.
-        verify(mHandler).sendMessageAtTime(messageCaptor.capture(), anyLong());
-        messageCaptor.getValue().getCallback().run();
-    }
-
-    private void makeUsSystemApp() throws Exception {
-        makeUsSystemApp(true);
-    }
-
-    private void makeUsSystemApp(boolean isSystemApp) throws Exception {
-        PackageInfo packageInfo =
-                mRealContext.getPackageManager().getPackageInfo(TEST_FRAMEWORK_PACKAGE, 0);
-        if (isSystemApp) {
-            packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
-        } else {
-            packageInfo.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;
-        }
-        doReturn(packageInfo)
-                .when(mSpyPackageManager)
-                .getPackageInfo(eq(TEST_FRAMEWORK_PACKAGE), anyInt());
-        when(mMockContext.getPackageManager()).thenReturn(mSpyPackageManager);
-    }
-
-    private Intent makeVerificationIntent() throws Exception {
-        PackageInfo packageInfo =
-                mRealContext
-                        .getPackageManager()
-                        .getPackageInfo(
-                                TEST_FRAMEWORK_PACKAGE, PackageManager.GET_SIGNING_CERTIFICATES);
-        doReturn(packageInfo).when(mSpyPackageManager).getPackageInfo(eq(INSTALLER), anyInt());
-        doReturn(1).when(mSpyPackageManager).getPackageUid(eq(INSTALLER), anyInt());
-        doReturn(new String[]{INSTALLER}).when(mSpyPackageManager).getPackagesForUid(anyInt());
-        return makeVerificationIntent(INSTALLER);
-    }
-
-    private Intent makeVerificationIntent(String installer) throws Exception {
-        Intent intent = new Intent();
-        intent.setDataAndType(Uri.fromFile(mTestApk), PACKAGE_MIME_TYPE);
-        intent.setAction(Intent.ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION);
-        intent.putExtra(EXTRA_VERIFICATION_ID, 1);
-        intent.putExtra(Intent.EXTRA_PACKAGE_NAME, PACKAGE_NAME);
-        intent.putExtra(EXTRA_VERIFICATION_INSTALLER_PACKAGE, installer);
-        intent.putExtra(
-                EXTRA_VERIFICATION_INSTALLER_UID,
-                mMockContext.getPackageManager().getPackageUid(installer, /* flags= */ 0));
-        intent.putExtra(Intent.EXTRA_LONG_VERSION_CODE, VERSION_CODE);
-        return intent;
-    }
-
-    private void setIntegrityCheckIncludesRuleProvider(boolean shouldInclude) throws Exception {
-        int value = shouldInclude ? 1 : 0;
-        Settings.Global.putInt(
-                mRealContext.getContentResolver(),
-                Settings.Global.INTEGRITY_CHECK_INCLUDES_RULE_PROVIDER,
-                value);
-        assertThat(
-                        Settings.Global.getInt(
-                                        mRealContext.getContentResolver(),
-                                        Settings.Global.INTEGRITY_CHECK_INCLUDES_RULE_PROVIDER,
-                                        -1)
-                                == 1)
-                .isEqualTo(shouldInclude);
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java b/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java
index fac5c1f..27486b7 100644
--- a/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java
@@ -40,11 +40,13 @@
 import android.content.IntentFilter;
 import android.content.pm.ShortcutInfo;
 import android.content.pm.ShortcutManager.ShareShortcutInfo;
+import android.content.res.Resources;
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.provider.DeviceConfig;
 import android.util.Range;
 
+import com.android.internal.R;
 import com.android.internal.app.ChooserActivity;
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
 import com.android.server.people.data.ConversationInfo;
@@ -87,6 +89,7 @@
     private static final IntentFilter INTENT_FILTER = IntentFilter.create("SEND", "text/plain");
 
     @Mock private Context mContext;
+    @Mock private Resources mResources;
     @Mock private DataManager mDataManager;
     @Mock private Consumer<List<AppTarget>> mUpdatePredictionsMethod;
     @Mock private PackageData mPackageData1;
@@ -116,11 +119,14 @@
         when(mDataManager.getShareShortcuts(any(), anyInt())).thenReturn(mShareShortcuts);
         when(mDataManager.getPackage(PACKAGE_1, USER_ID)).thenReturn(mPackageData1);
         when(mDataManager.getPackage(PACKAGE_2, USER_ID)).thenReturn(mPackageData2);
-        when(mContext.createContextAsUser(any(), any())).thenReturn(mContext);
+        when(mContext.createContextAsUser(any(), anyInt())).thenReturn(mContext);
         when(mContext.getSystemServiceName(AppPredictionManager.class)).thenReturn(
                 Context.APP_PREDICTION_SERVICE);
         when(mContext.getSystemService(AppPredictionManager.class))
                 .thenReturn(new AppPredictionManager(mContext));
+        when(mContext.getResources()).thenReturn(mResources);
+        when(mResources.getString(R.string.config_chooserActivity))
+                .thenReturn("com.android.intentresolver/.ChooserActivity");
 
         Bundle bundle = new Bundle();
         bundle.putObject(ChooserActivity.APP_PREDICTION_INTENT_FILTER_KEY, INTENT_FILTER);
diff --git a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
index 3b0cb4a..0404b82 100644
--- a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
@@ -1460,9 +1460,12 @@
         verify(mInjector).startDreamWhenDockedIfAppropriate(mContext);
     }
 
-    private void testAttentionModeThemeOverlay(boolean modeNight) throws RemoteException {
+    // Test the attention mode overlay with all the possible attention modes and the initial night
+    // mode state. Also tests if the attention mode is turned off when the night mode is toggled by
+    // the user.
+    private void testAttentionModeThemeOverlay(boolean initialNightMode) throws RemoteException {
         //setup
-        if (modeNight) {
+        if (initialNightMode) {
             mService.setNightMode(MODE_NIGHT_YES);
             assertTrue(mUiManagerService.getConfiguration().isNightModeActive());
         } else {
@@ -1472,21 +1475,29 @@
 
         // attention modes with expected night modes
         Map<Integer, Boolean> modes = Map.of(
-                MODE_ATTENTION_THEME_OVERLAY_OFF, modeNight,
+                MODE_ATTENTION_THEME_OVERLAY_OFF, initialNightMode,
                 MODE_ATTENTION_THEME_OVERLAY_DAY, false,
                 MODE_ATTENTION_THEME_OVERLAY_NIGHT, true
         );
 
         // test
-        for (int aMode : modes.keySet()) {
+        for (int attentionMode : modes.keySet()) {
             try {
-                mService.setAttentionModeThemeOverlay(aMode);
+                mService.setAttentionModeThemeOverlay(attentionMode);
 
                 int appliedAMode = mService.getAttentionModeThemeOverlay();
-                boolean nMode = modes.get(aMode);
+                boolean expectedNightMode = modes.get(attentionMode);
 
-                assertEquals(aMode, appliedAMode);
-                assertEquals(isNightModeActivated(), nMode);
+                assertEquals(attentionMode, appliedAMode);
+                assertEquals(expectedNightMode, isNightModeActivated());
+
+                // If attentionMode is active, flip the night mode and assets
+                // the attention mode is disabled
+                if (attentionMode != MODE_ATTENTION_THEME_OVERLAY_OFF) {
+                    mService.setNightModeActivated(!expectedNightMode);
+                    assertEquals(MODE_ATTENTION_THEME_OVERLAY_OFF,
+                            mService.getAttentionModeThemeOverlay());
+                }
             } catch (RemoteException e) {
                 fail("Error communicating with server: " + e.getMessage());
             }
diff --git a/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java
index c427583..2ceff62 100644
--- a/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java
@@ -62,6 +62,7 @@
 import android.graphics.Rect;
 import android.hardware.camera2.CameraManager;
 import android.os.Handler;
+import android.platform.test.annotations.DisableFlags;
 import android.platform.test.annotations.EnableFlags;
 import android.platform.test.annotations.Presubmit;
 import android.view.DisplayInfo;
@@ -143,6 +144,58 @@
     }
 
     @Test
+    @DisableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
+    public void testIsCameraRunningAndWindowingModeEligible_featureDisabled_returnsFalse() {
+        configureActivity(SCREEN_ORIENTATION_PORTRAIT);
+
+        mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
+
+        assertFalse(mCameraCompatFreeformPolicy.isCameraRunningAndWindowingModeEligible(mActivity));
+    }
+
+    @Test
+    @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+    public void testIsCameraRunningAndWindowingModeEligible_overrideDisabled_returnsFalse() {
+        configureActivity(SCREEN_ORIENTATION_PORTRAIT);
+
+        mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
+
+        assertFalse(mCameraCompatFreeformPolicy.isCameraRunningAndWindowingModeEligible(mActivity));
+    }
+
+    @Test
+    @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
+    public void testIsCameraRunningAndWindowingModeEligible_cameraNotRunning_returnsFalse() {
+        configureActivity(SCREEN_ORIENTATION_PORTRAIT);
+
+        assertFalse(mCameraCompatFreeformPolicy.isCameraRunningAndWindowingModeEligible(mActivity));
+    }
+
+    @Test
+    @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
+    public void testIsCameraRunningAndWindowingModeEligible_notFreeformWindowing_returnsFalse() {
+        configureActivity(SCREEN_ORIENTATION_PORTRAIT, WINDOWING_MODE_FULLSCREEN);
+
+        mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
+
+        assertFalse(mCameraCompatFreeformPolicy.isCameraRunningAndWindowingModeEligible(mActivity));
+    }
+
+    @Test
+    @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
+    public void testIsCameraRunningAndWindowingModeEligible_optInFreeformCameraRunning_true() {
+        configureActivity(SCREEN_ORIENTATION_PORTRAIT);
+
+        mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
+
+        assertTrue(mCameraCompatFreeformPolicy.isCameraRunningAndWindowingModeEligible(mActivity));
+    }
+
+    @Test
     @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
     @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
     public void testFullscreen_doesNotActivateCameraCompatMode() {
@@ -444,7 +497,8 @@
         doReturn(mActivity).when(mDisplayContent).topRunningActivity(anyBoolean());
         doReturn(naturalOrientation).when(mDisplayContent).getNaturalOrientation();
 
-        doReturn(true).when(mActivity).inFreeformWindowingMode();
+        doReturn(windowingMode == WINDOWING_MODE_FREEFORM).when(mActivity)
+                .inFreeformWindowingMode();
     }
 
     private void assertInCameraCompatMode(@CameraCompatTaskInfo.FreeformCameraCompatMode int mode) {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 024d7f5..65a52da 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -19636,7 +19636,7 @@
      * Android assigns each carrier with a canonical integer a.k.a. carrier id.
      * The carrier ID is an Android platform-wide identifier for a carrier.
      * AOSP maintains carrier ID assignments in
-     * <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/latest_carrier_id/carrier_list.textpb">here</a>
+     * <a href="https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/main/assets/latest_carrier_id/carrier_list.textpb">here</a>
      *
      * @param carrierIdentifier {@link CarrierIdentifier}
      *
diff --git a/tests/graphics/SilkFX/AndroidManifest.xml b/tests/graphics/SilkFX/AndroidManifest.xml
index 25092b5..c293589 100644
--- a/tests/graphics/SilkFX/AndroidManifest.xml
+++ b/tests/graphics/SilkFX/AndroidManifest.xml
@@ -23,13 +23,12 @@
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
 
     <application android:label="SilkFX"
-         android:theme="@style/Theme.UsefulDefault">
+         android:theme="@android:style/Theme.Material">
 
         <activity android:name=".Main"
              android:label="SilkFX Demos"
              android:banner="@drawable/background1"
-             android:exported="true"
-             android:theme="@style/Theme.UsefulDefault">
+             android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
                 <category android:name="android.intent.category.DEFAULT"/>
diff --git a/tests/graphics/SilkFX/res/layout/activity_background_blur.xml b/tests/graphics/SilkFX/res/layout/activity_background_blur.xml
index f13c088..27eca82 100644
--- a/tests/graphics/SilkFX/res/layout/activity_background_blur.xml
+++ b/tests/graphics/SilkFX/res/layout/activity_background_blur.xml
@@ -13,161 +13,168 @@
   ~ 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.
-  -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+-->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
-    android:id="@+id/background"
-    android:layout_width="390dp"
-    android:layout_height="wrap_content"
-    android:layout_gravity="center"
-    android:padding="15dp"
-    android:orientation="vertical"
+    android:fitsSystemWindows="true"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
     tools:context=".materials.BackgroundBlurActivity">
 
-    <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:gravity="center_horizontal"
-        android:padding="10dp"
-        android:textColor="#ffffffff"
-        android:text="Hello blurry world!"/>
-
     <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="horizontal">
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_weight="1"
-            android:textColor="#ffffffff"
-            android:text="Background blur"/>
-
-        <SeekBar
-            android:id="@+id/set_background_blur"
-            android:min="0"
-            android:max="300"
-            android:layout_width="160dp"
-            android:layout_height="wrap_content"/>
-        <TextView
-            android:id="@+id/background_blur_radius"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:textColor="#ffffffff"
-            android:ems="3"
-            android:gravity="center"
-            android:paddingLeft="10dp"
-            android:paddingRight="10dp"
-            android:text="TODO"/>
-    </LinearLayout>
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="horizontal">
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_weight="1"
-            android:textColor="#ffffffff"
-            android:text="Background alpha"/>
-
-        <SeekBar
-            android:id="@+id/set_background_alpha"
-            android:min="0"
-            android:max="100"
-            android:layout_width="160dp"
-            android:layout_height="wrap_content" />
-        <TextView
-            android:id="@+id/background_alpha"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:textColor="#ffffffff"
-            android:ems="3"
-            android:gravity="center"
-            android:paddingLeft="10dp"
-            android:paddingRight="10dp"
-            android:text="TODO"/>
-    </LinearLayout>
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="horizontal">
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_weight="1"
-            android:textColor="#ffffffff"
-            android:text="Blur behind"/>
-
-        <SeekBar
-            android:id="@+id/set_blur_behind"
-            android:min="0"
-            android:max="300"
-            android:layout_width="160dp"
-            android:layout_height="wrap_content" />
-        <TextView
-            android:id="@+id/blur_behind_radius"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:gravity="center"
-            android:textColor="#ffffffff"
-            android:paddingLeft="10dp"
-            android:paddingRight="10dp"
-            android:ems="3"
-            android:text="TODO"/>
-    </LinearLayout>
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="horizontal">
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_weight="1"
-            android:textColor="#ffffffff"
-            android:text="Dim amount"/>
-
-        <SeekBar
-            android:id="@+id/set_dim_amount"
-            android:min="0"
-            android:max="100"
-            android:layout_width="160dp"
-            android:layout_height="wrap_content" />
-        <TextView
-            android:id="@+id/dim_amount"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:gravity="center"
-            android:textColor="#ffffffff"
-            android:paddingLeft="10dp"
-            android:paddingRight="10dp"
-            android:ems="3"
-            android:text="TODO"/>
-    </LinearLayout>
-
-    <LinearLayout
-        android:layout_width="match_parent"
+        android:id="@+id/background"
+        android:layout_width="390dp"
         android:layout_height="wrap_content"
         android:layout_gravity="center"
-        android:layout_marginTop="5dp"
-        android:orientation="vertical"
-        android:gravity="center">
+        android:padding="15dp"
+        android:orientation="vertical">
 
-        <Button
-            android:id="@+id/toggle_blur_enabled"
+        <TextView
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:text="Disable blur"
-            android:onClick="toggleForceBlurDisabled"/>
+            android:gravity="center_horizontal"
+            android:padding="10dp"
+            android:textColor="#ffffffff"
+            android:text="Hello blurry world!"/>
 
-        <Button
-            android:id="@+id/toggle_battery_saving_mode"
+        <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:text="TODO"
-            android:onClick="toggleBatterySavingMode"/>
+            android:orientation="horizontal">
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:textColor="#ffffffff"
+                android:text="Background blur"/>
+
+            <SeekBar
+                android:id="@+id/set_background_blur"
+                android:min="0"
+                android:max="300"
+                android:layout_width="160dp"
+                android:layout_height="wrap_content"/>
+            <TextView
+                android:id="@+id/background_blur_radius"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textColor="#ffffffff"
+                android:ems="3"
+                android:gravity="center"
+                android:paddingLeft="10dp"
+                android:paddingRight="10dp"
+                android:text="TODO"/>
+        </LinearLayout>
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal">
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:textColor="#ffffffff"
+                android:text="Background alpha"/>
+
+            <SeekBar
+                android:id="@+id/set_background_alpha"
+                android:min="0"
+                android:max="100"
+                android:layout_width="160dp"
+                android:layout_height="wrap_content" />
+            <TextView
+                android:id="@+id/background_alpha"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textColor="#ffffffff"
+                android:ems="3"
+                android:gravity="center"
+                android:paddingLeft="10dp"
+                android:paddingRight="10dp"
+                android:text="TODO"/>
+        </LinearLayout>
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal">
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:textColor="#ffffffff"
+                android:text="Blur behind"/>
+
+            <SeekBar
+                android:id="@+id/set_blur_behind"
+                android:min="0"
+                android:max="300"
+                android:layout_width="160dp"
+                android:layout_height="wrap_content" />
+            <TextView
+                android:id="@+id/blur_behind_radius"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:gravity="center"
+                android:textColor="#ffffffff"
+                android:paddingLeft="10dp"
+                android:paddingRight="10dp"
+                android:ems="3"
+                android:text="TODO"/>
+        </LinearLayout>
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal">
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:textColor="#ffffffff"
+                android:text="Dim amount"/>
+
+            <SeekBar
+                android:id="@+id/set_dim_amount"
+                android:min="0"
+                android:max="100"
+                android:layout_width="160dp"
+                android:layout_height="wrap_content" />
+            <TextView
+                android:id="@+id/dim_amount"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:gravity="center"
+                android:textColor="#ffffffff"
+                android:paddingLeft="10dp"
+                android:paddingRight="10dp"
+                android:ems="3"
+                android:text="TODO"/>
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:layout_marginTop="5dp"
+            android:orientation="vertical"
+            android:gravity="center">
+
+            <Button
+                android:id="@+id/toggle_blur_enabled"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="Disable blur"
+                android:onClick="toggleForceBlurDisabled"/>
+
+            <Button
+                android:id="@+id/toggle_battery_saving_mode"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="TODO"
+                android:onClick="toggleBatterySavingMode"/>
+        </LinearLayout>
+        <requestFocus/>
+
     </LinearLayout>
-    <requestFocus/>
-
-</LinearLayout>
+</FrameLayout>
diff --git a/tests/graphics/SilkFX/res/layout/activity_glass.xml b/tests/graphics/SilkFX/res/layout/activity_glass.xml
index aa09f27..d591fc4 100644
--- a/tests/graphics/SilkFX/res/layout/activity_glass.xml
+++ b/tests/graphics/SilkFX/res/layout/activity_glass.xml
@@ -19,6 +19,7 @@
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
     tools:context=".MainActivity">
 
     <ImageView
@@ -300,4 +301,4 @@
     </androidx.constraintlayout.widget.ConstraintLayout>
 
 
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/tests/graphics/SilkFX/res/layout/color_mode_controls.xml b/tests/graphics/SilkFX/res/layout/color_mode_controls.xml
index c0c0bab..9b2b0c8 100644
--- a/tests/graphics/SilkFX/res/layout/color_mode_controls.xml
+++ b/tests/graphics/SilkFX/res/layout/color_mode_controls.xml
@@ -19,6 +19,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
+    android:layout_margin="8dp"
     android:orientation="vertical">
 
     <TextView
@@ -61,4 +62,4 @@
 
     </LinearLayout>
 
-</com.android.test.silkfx.common.ColorModeControls>
\ No newline at end of file
+</com.android.test.silkfx.common.ColorModeControls>
diff --git a/tests/graphics/SilkFX/res/layout/common_base.xml b/tests/graphics/SilkFX/res/layout/common_base.xml
index c0eaf9b..ce6d850 100644
--- a/tests/graphics/SilkFX/res/layout/common_base.xml
+++ b/tests/graphics/SilkFX/res/layout/common_base.xml
@@ -18,6 +18,7 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
     android:orientation="vertical">
 
     <include layout="@layout/color_mode_controls" />
@@ -26,4 +27,4 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent" />
 
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/tests/graphics/SilkFX/res/layout/hdr_glows.xml b/tests/graphics/SilkFX/res/layout/hdr_glows.xml
index b6050645..f1e553a 100644
--- a/tests/graphics/SilkFX/res/layout/hdr_glows.xml
+++ b/tests/graphics/SilkFX/res/layout/hdr_glows.xml
@@ -18,6 +18,7 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
     android:orientation="vertical">
 
     <include layout="@layout/color_mode_controls" />
@@ -48,4 +49,4 @@
         android:layout_height="50dp"
         android:layout_margin="8dp" />
 
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/tests/graphics/SilkFX/res/values/style.xml b/tests/graphics/SilkFX/res/values/style.xml
index 4dd626d..7550697 100644
--- a/tests/graphics/SilkFX/res/values/style.xml
+++ b/tests/graphics/SilkFX/res/values/style.xml
@@ -16,21 +16,16 @@
   -->
 <!-- Styles for immersive actions UI. -->
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
-    <style name="Theme.BackgroundBlurTheme" parent= "Theme.AppCompat.Dialog">
+    <style name="Theme.BackgroundBlurTheme" parent="Theme.AppCompat.Dialog">
         <item name="android:windowIsTranslucent">true</item>
         <item name="android:windowBlurBehindEnabled">true</item>
         <item name="android:backgroundDimEnabled">false</item>
         <item name="android:windowElevation">0dp</item>
         <item name="buttonStyle">@style/AppTheme.Button</item>
         <item name="colorAccent">#bbffffff</item>
-        <item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>
     </style>
     <style name="AppTheme.Button" parent="Widget.AppCompat.Button">
         <item name="android:textColor">#ffffffff</item>
     </style>
 
-    <style name="Theme.UsefulDefault" parent="android:Theme.Material">
-        <item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>
-    </style>
-
 </resources>
diff --git a/tests/graphics/SilkFX/src/com/android/test/silkfx/Main.kt b/tests/graphics/SilkFX/src/com/android/test/silkfx/Main.kt
index 6b6d3b8..ad7cde4 100644
--- a/tests/graphics/SilkFX/src/com/android/test/silkfx/Main.kt
+++ b/tests/graphics/SilkFX/src/com/android/test/silkfx/Main.kt
@@ -72,6 +72,7 @@
         super.onCreate(savedInstanceState)
 
         val list = ExpandableListView(this)
+        list.setFitsSystemWindows(true)
 
         setContentView(list)