Merge "[KTF integration] Fix AodAlphaViewModel" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index ab2b110..ab5d503 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -76,7 +76,6 @@
         "android.widget.flags-aconfig-java",
         "backstage_power_flags_lib",
         "backup_flags_lib",
-        "bluetooth_exported_flags_java_lib",
         "camera_platform_flags_core_java_lib",
         "com.android.hardware.input-aconfig-java",
         "com.android.input.flags-aconfig-java",
diff --git a/Android.bp b/Android.bp
index af312bf..d6b303f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -425,7 +425,6 @@
         "sounddose-aidl-java",
         "modules-utils-expresslog",
         "perfetto_trace_javastream_protos_jarjar",
-        "libaconfig_java_proto_nano",
     ],
 }
 
diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java
index 76d6547..746ec2e 100644
--- a/core/java/android/app/AutomaticZenRule.java
+++ b/core/java/android/app/AutomaticZenRule.java
@@ -843,6 +843,15 @@
             return this;
         }
 
+        /**
+         * Sets the package that owns this rule
+         * @hide
+         */
+        public @NonNull Builder setPackage(@NonNull String pkg) {
+            mPkg = pkg;
+            return this;
+        }
+
         public @NonNull AutomaticZenRule build() {
             AutomaticZenRule rule = new AutomaticZenRule(mName, mOwner, mConfigurationActivity,
                     mConditionId, mPolicy, mInterruptionFilter, mEnabled);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index e3380e0..3b9a5d3 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -19,6 +19,7 @@
 import static android.content.pm.PackageManager.PERMISSION_DENIED;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.os.StrictMode.vmIncorrectContextUseEnabled;
+import static android.permission.flags.Flags.shouldRegisterAttributionSource;
 import static android.view.WindowManager.LayoutParams.WindowType;
 
 import android.Manifest;
@@ -3157,7 +3158,8 @@
             int deviceId = vdm.getDeviceIdForDisplayId(displayId);
             if (deviceId != mDeviceId) {
                 mDeviceId = deviceId;
-                mAttributionSource = mAttributionSource.withDeviceId(mDeviceId);
+                mAttributionSource =
+                        createAttributionSourceWithDeviceId(mAttributionSource, mDeviceId);
                 notifyOnDeviceChangedListeners(mDeviceId);
             }
         }
@@ -3180,6 +3182,7 @@
 
         if (mDeviceId != updatedDeviceId) {
             mDeviceId = updatedDeviceId;
+            mAttributionSource = createAttributionSourceWithDeviceId(mAttributionSource, mDeviceId);
             notifyOnDeviceChangedListeners(updatedDeviceId);
         }
     }
@@ -3548,8 +3551,22 @@
                 deviceId, nextAttributionSource);
         // If we want to access protected data on behalf of another app we need to
         // tell the OS that we opt in to participate in the attribution chain.
-        if (nextAttributionSource != null || shouldRegister) {
-            attributionSource = getSystemService(PermissionManager.class)
+        return registerAttributionSourceIfNeeded(attributionSource, shouldRegister);
+    }
+
+    private @NonNull AttributionSource createAttributionSourceWithDeviceId(
+            @NonNull AttributionSource oldSource, int deviceId) {
+        boolean shouldRegister = false;
+        if (shouldRegisterAttributionSource()) {
+            shouldRegister = mParams.shouldRegisterAttributionSource();
+        }
+        return registerAttributionSourceIfNeeded(oldSource.withDeviceId(deviceId), shouldRegister);
+    }
+
+    private @NonNull AttributionSource registerAttributionSourceIfNeeded(
+            @NonNull AttributionSource attributionSource, boolean shouldRegister) {
+        if (shouldRegister || attributionSource.getNext() != null) {
+            return getSystemService(PermissionManager.class)
                     .registerAttributionSource(attributionSource);
         }
         return attributionSource;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index d8f03b1..dfae48b 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -8725,6 +8725,12 @@
          * <p>The messages should be added in chronologic order, i.e. the oldest first,
          * the newest last.
          *
+         * <p>Multiple Messages in a row with the same timestamp and sender may be grouped as a
+         * single message. This means an app should represent a message that has both an image and
+         * text as two Message objects, one with the image (and fallback text), and the other with
+         * the message text. For consistency, a text message (if any) should be provided after Uri
+         * content.
+         *
          * @param message The {@link Message} to be displayed
          * @return this object for method chaining
          */
@@ -9359,6 +9365,15 @@
             }
         }
 
+        /*
+         * An object representing a simple message or piece of media within a mixed-media message.
+         *
+         * This object can only represent text or a single binary piece of media. For apps which
+         * support mixed-media messages (e.g. text + image), multiple Messages should be used, one
+         * to represent each piece of the message, and they should all be given the same timestamp.
+         * For consistency, a text message should be added last of all Messages with the same
+         * timestamp.
+         */
         public static final class Message {
             /** @hide */
             public static final String KEY_TEXT = "text";
@@ -9447,8 +9462,9 @@
 
             /**
              * Sets a binary blob of data and an associated MIME type for a message. In the case
-             * where the platform doesn't support the MIME type, the original text provided in the
-             * constructor will be used.
+             * where the platform or the UI state doesn't support the MIME type, the original text
+             * provided in the constructor will be used.  When this data can be presented to the
+             * user, the original text will only be used as accessibility text.
              * @param dataMimeType The MIME type of the content. See
              * {@link android.graphics.ImageDecoder#isMimeTypeSupported(String)} for a list of
              * supported image MIME types.
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 4512180..8aa2c35 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -36,6 +36,8 @@
 import android.util.Slog;
 import android.view.View;
 
+import com.android.internal.ravenwood.RavenwoodEnvironment;
+
 import dalvik.system.VMRuntime;
 
 import java.util.ArrayList;
@@ -49,6 +51,10 @@
  */
 @RavenwoodKeepWholeClass
 public class Build {
+    static {
+        // Set up the default system properties.
+        RavenwoodEnvironment.ensureRavenwoodInitialized();
+    }
     private static final String TAG = "Build";
 
     /** Value used for when a build property is unknown. */
diff --git a/core/java/android/view/DragEvent.java b/core/java/android/view/DragEvent.java
index 1898407..b65e3eb 100644
--- a/core/java/android/view/DragEvent.java
+++ b/core/java/android/view/DragEvent.java
@@ -156,6 +156,13 @@
     private float mOffsetX;
     private float mOffsetY;
 
+    /**
+     * The View#DRAG_FLAG_* flags used to start the current drag, only provided if the target window
+     * has the {@link WindowManager.LayoutParams#PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP} flag
+     * and is only sent with {@link #ACTION_DRAG_STARTED} and {@link #ACTION_DROP}.
+     */
+    private int mFlags;
+
     private DragEvent mNext;
     private RuntimeException mRecycledLocation;
     private boolean mRecycled;
@@ -290,7 +297,7 @@
     private DragEvent() {
     }
 
-    private void init(int action, float x, float y, float offsetX, float offsetY,
+    private void init(int action, float x, float y, float offsetX, float offsetY, int flags,
             ClipDescription description, ClipData data, SurfaceControl dragSurface,
             IDragAndDropPermissions dragAndDropPermissions, Object localState, boolean result) {
         mAction = action;
@@ -298,6 +305,7 @@
         mY = y;
         mOffsetX = offsetX;
         mOffsetY = offsetY;
+        mFlags = flags;
         mClipDescription = description;
         mClipData = data;
         mDragSurface = dragSurface;
@@ -307,19 +315,19 @@
     }
 
     static DragEvent obtain() {
-        return DragEvent.obtain(0, 0f, 0f, 0f, 0f, null, null, null, null, null, false);
+        return DragEvent.obtain(0, 0f, 0f, 0f, 0f, 0, null, null, null, null, null, false);
     }
 
     /** @hide */
     public static DragEvent obtain(int action, float x, float y, float offsetX, float offsetY,
-            Object localState, ClipDescription description, ClipData data,
+            int flags, Object localState, ClipDescription description, ClipData data,
             SurfaceControl dragSurface, IDragAndDropPermissions dragAndDropPermissions,
             boolean result) {
         final DragEvent ev;
         synchronized (gRecyclerLock) {
             if (gRecyclerTop == null) {
                 ev = new DragEvent();
-                ev.init(action, x, y, offsetX, offsetY, description, data, dragSurface,
+                ev.init(action, x, y, offsetX, offsetY, flags, description, data, dragSurface,
                         dragAndDropPermissions, localState, result);
                 return ev;
             }
@@ -331,7 +339,7 @@
         ev.mRecycled = false;
         ev.mNext = null;
 
-        ev.init(action, x, y, offsetX, offsetY, description, data, dragSurface,
+        ev.init(action, x, y, offsetX, offsetY, flags, description, data, dragSurface,
                 dragAndDropPermissions, localState, result);
 
         return ev;
@@ -341,8 +349,8 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public static DragEvent obtain(DragEvent source) {
         return obtain(source.mAction, source.mX, source.mY, source.mOffsetX, source.mOffsetY,
-                source.mLocalState, source.mClipDescription, source.mClipData, source.mDragSurface,
-                source.mDragAndDropPermissions, source.mDragResult);
+                source.mFlags, source.mLocalState, source.mClipDescription, source.mClipData,
+                source.mDragSurface, source.mDragAndDropPermissions, source.mDragResult);
     }
 
     /**
@@ -424,6 +432,11 @@
     }
 
     /** @hide */
+    public int getDragFlags() {
+        return mFlags;
+    }
+
+    /** @hide */
     public IDragAndDropPermissions getDragAndDropPermissions() {
         return mDragAndDropPermissions;
     }
@@ -571,6 +584,7 @@
         dest.writeFloat(mY);
         dest.writeFloat(mOffsetX);
         dest.writeFloat(mOffsetY);
+        dest.writeInt(mFlags);
         dest.writeInt(mDragResult ? 1 : 0);
         if (mClipData == null) {
             dest.writeInt(0);
@@ -610,6 +624,7 @@
             event.mY = in.readFloat();
             event.mOffsetX = in.readFloat();
             event.mOffsetY = in.readFloat();
+            event.mFlags = in.readInt();
             event.mDragResult = (in.readInt() != 0);
             if (in.readInt() != 0) {
                 event.mClipData = ClipData.CREATOR.createFromParcel(in);
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 3743035..f628c21 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -68,7 +68,8 @@
     /**
      * Called when this window retrieved control over a specified set of insets sources.
      */
-    void insetsControlChanged(in InsetsState insetsState, in InsetsSourceControl[] activeControls);
+    void insetsControlChanged(in InsetsState insetsState,
+            in InsetsSourceControl.Array activeControls);
 
     /**
      * Called when a set of insets source window should be shown by policy.
diff --git a/core/java/android/view/ImeBackAnimationController.java b/core/java/android/view/ImeBackAnimationController.java
index 8c14de6..fc1852d 100644
--- a/core/java/android/view/ImeBackAnimationController.java
+++ b/core/java/android/view/ImeBackAnimationController.java
@@ -255,10 +255,11 @@
 
     private boolean isBackAnimationAllowed() {
         // back animation is allowed in all cases except when softInputMode is adjust_resize AND
-        // there is no app-registered WindowInsetsAnimationCallback.
+        // there is no app-registered WindowInsetsAnimationCallback AND edge-to-edge is not enabled.
         return (mViewRoot.mWindowAttributes.softInputMode & SOFT_INPUT_MASK_ADJUST)
                 != SOFT_INPUT_ADJUST_RESIZE
-                || (mViewRoot.mView != null && mViewRoot.mView.hasWindowInsetsAnimationCallback());
+                || (mViewRoot.mView != null && mViewRoot.mView.hasWindowInsetsAnimationCallback())
+                || mViewRoot.mAttachInfo.mContentOnApplyWindowInsetsListener == null;
     }
 
     private boolean isAdjustPan() {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 0715474..8e2b7f1 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -10234,7 +10234,7 @@
             // force DRAG_EXITED_EVENT if appropriate
             DragEvent event = DragEvent.obtain(
                     isExiting ? DragEvent.ACTION_DRAG_EXITED : DragEvent.ACTION_DRAG_LOCATION,
-                    x, y, 0 /* offsetX */, 0 /* offsetY */, null/* localState */,
+                    x, y, 0 /* offsetX */, 0 /* offsetY */, 0 /* flags */, null/* localState */,
                     null/* description */, null /* data */, null /* dragSurface */,
                     null /* dragAndDropPermissions */, false /* result */);
             dispatchDragEvent(event);
@@ -11258,10 +11258,10 @@
 
         @Override
         public void insetsControlChanged(InsetsState insetsState,
-                InsetsSourceControl[] activeControls) {
+                InsetsSourceControl.Array activeControls) {
             final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
-                viewAncestor.dispatchInsetsControlChanged(insetsState, activeControls);
+                viewAncestor.dispatchInsetsControlChanged(insetsState, activeControls.get());
             }
         }
 
diff --git a/core/java/android/view/autofill/AutofillFeatureFlags.java b/core/java/android/view/autofill/AutofillFeatureFlags.java
index 5cdcf0a..46b41ae 100644
--- a/core/java/android/view/autofill/AutofillFeatureFlags.java
+++ b/core/java/android/view/autofill/AutofillFeatureFlags.java
@@ -532,7 +532,7 @@
         return DeviceConfig.getBoolean(
                 DeviceConfig.NAMESPACE_AUTOFILL,
                 DEVICE_CONFIG_IGNORE_VIEW_STATE_RESET_TO_EMPTY,
-                false);
+                true);
     }
 
     /** @hide */
diff --git a/core/java/android/window/BackProgressAnimator.java b/core/java/android/window/BackProgressAnimator.java
index 6fe0784..94d7811 100644
--- a/core/java/android/window/BackProgressAnimator.java
+++ b/core/java/android/window/BackProgressAnimator.java
@@ -33,7 +33,7 @@
  *
  * @hide
  */
-public class BackProgressAnimator {
+public class BackProgressAnimator implements DynamicAnimation.OnAnimationUpdateListener {
     /**
      *  A factor to scale the input progress by, so that it works better with the spring.
      *  We divide the output progress by this value before sending it to apps, so that apps
@@ -43,6 +43,7 @@
     private final SpringAnimation mSpring;
     private ProgressCallback mCallback;
     private float mProgress = 0;
+    private float mVelocity = 0;
     private BackMotionEvent mLastBackEvent;
     private boolean mBackAnimationInProgress = false;
     @Nullable
@@ -67,7 +68,6 @@
                 @Override
                 public void setValue(BackProgressAnimator animator, float value) {
                     animator.setProgress(value);
-                    animator.updateProgressValue(value);
                 }
 
                 @Override
@@ -76,6 +76,11 @@
                 }
             };
 
+    @Override
+    public void onAnimationUpdate(DynamicAnimation animation, float value, float velocity) {
+        updateProgressValue(value, velocity);
+    }
+
 
     /** A callback to be invoked when there's a progress value update from the animator. */
     public interface ProgressCallback {
@@ -85,6 +90,7 @@
 
     public BackProgressAnimator() {
         mSpring = new SpringAnimation(this, PROGRESS_PROP);
+        mSpring.addUpdateListener(this);
         mSpring.setSpring(new SpringForce()
                 .setStiffness(SpringForce.STIFFNESS_MEDIUM)
                 .setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY));
@@ -117,7 +123,7 @@
         mLastBackEvent = event;
         mCallback = callback;
         mBackAnimationInProgress = true;
-        updateProgressValue(0);
+        updateProgressValue(0, 0);
     }
 
     /**
@@ -126,7 +132,7 @@
     public void reset() {
         if (mBackCancelledFinishRunnable != null) {
             // Ensure that last progress value that apps see is 0
-            updateProgressValue(0);
+            updateProgressValue(0, 0);
             invokeBackCancelledRunnable();
         }
         mSpring.animateToFinalPosition(0);
@@ -167,7 +173,15 @@
         return mBackAnimationInProgress;
     }
 
-    private void updateProgressValue(float progress) {
+    /**
+     * @return The last recorded velocity. Unit: change in progress per second
+     */
+    public float getVelocity() {
+        return mVelocity / SCALE_FACTOR;
+    }
+
+    private void updateProgressValue(float progress, float velocity) {
+        mVelocity = velocity;
         if (mLastBackEvent == null || mCallback == null || !mBackAnimationInProgress) {
             return;
         }
diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig
index ef55cc0..5e0107e 100644
--- a/core/java/android/window/flags/windowing_sdk.aconfig
+++ b/core/java/android/window/flags/windowing_sdk.aconfig
@@ -140,4 +140,14 @@
     metadata {
         purpose: PURPOSE_FEATURE
     }
+}
+
+flag {
+    namespace: "windowing_sdk"
+    name: "insets_control_changed_item"
+    description: "Pass insetsControlChanged through ClientTransaction to fix the racing"
+    bug: "339380439"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
 }
\ No newline at end of file
diff --git a/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java b/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java
deleted file mode 100644
index f306b0b..0000000
--- a/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java
+++ /dev/null
@@ -1,244 +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.internal.pm.pkg.component;
-
-import static com.android.internal.pm.pkg.parsing.ParsingUtils.ANDROID_RES_NAMESPACE;
-
-import android.aconfig.nano.Aconfig;
-import android.aconfig.nano.Aconfig.parsed_flag;
-import android.aconfig.nano.Aconfig.parsed_flags;
-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;
-import android.util.Slog;
-import android.util.Xml;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.modules.utils.TypedXmlPullParser;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A class that manages a cache of all device feature flags and their default + override values.
- * This class performs a very similar job to the one in {@code SettingsProvider}, with an important
- * difference: this is a part of system server and is available for the server startup. Package
- * parsing happens at the startup when {@code SettingsProvider} isn't available yet, so we need an
- * own copy of the code here.
- * @hide
- */
-public class AconfigFlags {
-    private static final String LOG_TAG = "AconfigFlags";
-
-    private static final List<String> sTextProtoFilesOnDevice = List.of(
-            "/system/etc/aconfig_flags.pb",
-            "/system_ext/etc/aconfig_flags.pb",
-            "/product/etc/aconfig_flags.pb",
-            "/vendor/etc/aconfig_flags.pb");
-
-    private final ArrayMap<String, Boolean> mFlagValues = new ArrayMap<>();
-
-    public AconfigFlags() {
-        if (!Flags.manifestFlagging()) {
-            Slog.v(LOG_TAG, "Feature disabled, skipped all loading");
-            return;
-        }
-        for (String fileName : sTextProtoFilesOnDevice) {
-            try (var inputStream = new FileInputStream(fileName)) {
-                loadAconfigDefaultValues(inputStream.readAllBytes());
-            } catch (IOException e) {
-                Slog.e(LOG_TAG, "Failed to read Aconfig values from " + fileName, e);
-            }
-        }
-        if (Process.myUid() == Process.SYSTEM_UID) {
-            // Server overrides are only accessible to the system, no need to even try loading them
-            // in user processes.
-            loadServerOverrides();
-        }
-    }
-
-    private void loadServerOverrides() {
-        // Reading the proto files is enough for READ_ONLY flags but if it's a READ_WRITE flag
-        // (which you can check with `flag.getPermission() == flag_permission.READ_WRITE`) then we
-        // also need to check if there is a value pushed from the server in the file
-        // `/data/system/users/0/settings_config.xml`. It will be in a <setting> node under the
-        // root <settings> node with "name" attribute == "flag_namespace/flag_package.flag_name".
-        // The "value" attribute will be true or false.
-        //
-        // The "name" attribute could also be "<namespace>/flag_namespace?flag_package.flag_name"
-        // (prefixed with "staged/" or "device_config_overrides/" and a different separator between
-        // namespace and name). This happens when a flag value is overridden either with a pushed
-        // one from the server, or from the local command.
-        // When the device reboots during package parsing, the staged value will still be there and
-        // only later it will become a regular/non-staged value after SettingsProvider is
-        // initialized.
-        //
-        // In all cases, when there is more than one value, the priority is:
-        //      device_config_overrides > staged > default
-        //
-
-        final var settingsFile = new File(Environment.getUserSystemDirectory(0),
-                "settings_config.xml");
-        try (var inputStream = new FileInputStream(settingsFile)) {
-            TypedXmlPullParser parser = Xml.resolvePullParser(inputStream);
-            if (parser.next() != XmlPullParser.END_TAG && "settings".equals(parser.getName())) {
-                final var flagPriority = new ArrayMap<String, Integer>();
-                final int outerDepth = parser.getDepth();
-                int type;
-                while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                        && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-                    if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                        continue;
-                    }
-                    if (!"setting".equals(parser.getName())) {
-                        continue;
-                    }
-                    String name = parser.getAttributeValue(null, "name");
-                    final String value = parser.getAttributeValue(null, "value");
-                    if (name == null || value == null) {
-                        continue;
-                    }
-                    // A non-boolean setting is definitely not an Aconfig flag value.
-                    if (!"false".equalsIgnoreCase(value) && !"true".equalsIgnoreCase(value)) {
-                        continue;
-                    }
-                    final var overridePrefix = "device_config_overrides/";
-                    final var stagedPrefix = "staged/";
-                    String separator = "/";
-                    String prefix = "default";
-                    int priority = 0;
-                    if (name.startsWith(overridePrefix)) {
-                        prefix = overridePrefix;
-                        name = name.substring(overridePrefix.length());
-                        separator = ":";
-                        priority = 20;
-                    } else if (name.startsWith(stagedPrefix)) {
-                        prefix = stagedPrefix;
-                        name = name.substring(stagedPrefix.length());
-                        separator = "*";
-                        priority = 10;
-                    }
-                    final String flagPackageAndName = parseFlagPackageAndName(name, separator);
-                    if (flagPackageAndName == null) {
-                        continue;
-                    }
-                    // We ignore all settings that aren't for flags. We'll know they are for flags
-                    // if they correspond to flags read from the proto files.
-                    if (!mFlagValues.containsKey(flagPackageAndName)) {
-                        continue;
-                    }
-                    Slog.d(LOG_TAG, "Found " + prefix
-                            + " Aconfig flag value for " + flagPackageAndName + " = " + value);
-                    final Integer currentPriority = flagPriority.get(flagPackageAndName);
-                    if (currentPriority != null && currentPriority >= priority) {
-                        Slog.i(LOG_TAG, "Skipping " + prefix + " flag " + flagPackageAndName
-                                + " because of the existing one with priority " + currentPriority);
-                        continue;
-                    }
-                    flagPriority.put(flagPackageAndName, priority);
-                    mFlagValues.put(flagPackageAndName, Boolean.parseBoolean(value));
-                }
-            }
-        } catch (IOException | XmlPullParserException e) {
-            Slog.e(LOG_TAG, "Failed to read Aconfig values from settings_config.xml", e);
-        }
-    }
-
-    private static String parseFlagPackageAndName(String fullName, String separator) {
-        int index = fullName.indexOf(separator);
-        if (index < 0) {
-            return null;
-        }
-        return fullName.substring(index + 1);
-    }
-
-    private void loadAconfigDefaultValues(byte[] fileContents) throws IOException {
-        parsed_flags parsedFlags = parsed_flags.parseFrom(fileContents);
-        for (parsed_flag flag : parsedFlags.parsedFlag) {
-            String flagPackageAndName = flag.package_ + "." + flag.name;
-            boolean flagValue = (flag.state == Aconfig.ENABLED);
-            Slog.v(LOG_TAG, "Read Aconfig default flag value "
-                    + flagPackageAndName + " = " + flagValue);
-            mFlagValues.put(flagPackageAndName, flagValue);
-        }
-    }
-
-    /**
-     * Get the flag value, or null if the flag doesn't exist.
-     * @param flagPackageAndName Full flag name formatted as 'package.flag'
-     * @return the current value of the given Aconfig flag, or null if there is no such flag
-     */
-    @Nullable
-    public Boolean getFlagValue(@NonNull String flagPackageAndName) {
-        Boolean value = mFlagValues.get(flagPackageAndName);
-        Slog.d(LOG_TAG, "Aconfig flag value for " + flagPackageAndName + " = " + value);
-        return value;
-    }
-
-    /**
-     * Check if the element in {@code parser} should be skipped because of the feature flag.
-     * @param parser XML parser object currently parsing an element
-     * @return true if the element is disabled because of its feature flag
-     */
-    public boolean skipCurrentElement(@NonNull XmlResourceParser parser) {
-        if (!Flags.manifestFlagging()) {
-            return false;
-        }
-        String featureFlag = parser.getAttributeValue(ANDROID_RES_NAMESPACE, "featureFlag");
-        if (featureFlag == null) {
-            return false;
-        }
-        featureFlag = featureFlag.strip();
-        boolean negated = false;
-        if (featureFlag.startsWith("!")) {
-            negated = true;
-            featureFlag = featureFlag.substring(1).strip();
-        }
-        final Boolean flagValue = getFlagValue(featureFlag);
-        if (flagValue == null) {
-            Slog.w(LOG_TAG, "Skipping element " + parser.getName()
-                    + " due to unknown feature flag " + featureFlag);
-            return true;
-        }
-        // Skip if flag==false && attr=="flag" OR flag==true && attr=="!flag" (negated)
-        if (flagValue == negated) {
-            Slog.v(LOG_TAG, "Skipping element " + parser.getName()
-                    + " behind feature flag " + featureFlag + " = " + flagValue);
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Add Aconfig flag values for testing flagging of manifest entries.
-     * @param flagValues A map of flag name -> value.
-     */
-    @VisibleForTesting
-    public void addFlagValuesForTesting(@NonNull Map<String, Boolean> flagValues) {
-        mFlagValues.putAll(flagValues);
-    }
-}
diff --git a/core/java/com/android/internal/pm/pkg/component/ComponentParseUtils.java b/core/java/com/android/internal/pm/pkg/component/ComponentParseUtils.java
index 8858f94..db08005 100644
--- a/core/java/com/android/internal/pm/pkg/component/ComponentParseUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ComponentParseUtils.java
@@ -61,9 +61,6 @@
             if (type != XmlPullParser.START_TAG) {
                 continue;
             }
-            if (ParsingPackageUtils.getAconfigFlags().skipCurrentElement(parser)) {
-                continue;
-            }
 
             final ParseResult result;
             if ("meta-data".equals(parser.getName())) {
diff --git a/core/java/com/android/internal/pm/pkg/component/InstallConstraintsTagParser.java b/core/java/com/android/internal/pm/pkg/component/InstallConstraintsTagParser.java
index bb01581..0b04591 100644
--- a/core/java/com/android/internal/pm/pkg/component/InstallConstraintsTagParser.java
+++ b/core/java/com/android/internal/pm/pkg/component/InstallConstraintsTagParser.java
@@ -27,7 +27,6 @@
 
 import com.android.internal.R;
 import com.android.internal.pm.pkg.parsing.ParsingPackage;
-import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -81,9 +80,6 @@
                 }
                 return input.success(prefixes);
             } else if (type == XmlPullParser.START_TAG) {
-                if (ParsingPackageUtils.getAconfigFlags().skipCurrentElement(parser)) {
-                    continue;
-                }
                 if (parser.getName().equals(TAG_FINGERPRINT_PREFIX)) {
                     ParseResult<String> parsedPrefix =
                             readFingerprintPrefixValue(input, res, parser);
diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedActivityUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedActivityUtils.java
index 55baa53..9f71d88 100644
--- a/core/java/com/android/internal/pm/pkg/component/ParsedActivityUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedActivityUtils.java
@@ -393,9 +393,6 @@
             if (type != XmlPullParser.START_TAG) {
                 continue;
             }
-            if (ParsingPackageUtils.getAconfigFlags().skipCurrentElement(parser)) {
-                continue;
-            }
 
             final ParseResult result;
             if (parser.getName().equals("intent-filter")) {
diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoUtils.java
index da48b23..05728ee 100644
--- a/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoUtils.java
@@ -99,9 +99,6 @@
             if (type != XmlPullParser.START_TAG) {
                 continue;
             }
-            if (ParsingPackageUtils.getAconfigFlags().skipCurrentElement(parser)) {
-                continue;
-            }
 
             final ParseResult result;
             String nodeName = parser.getName();
@@ -200,9 +197,6 @@
             if (type != XmlPullParser.START_TAG) {
                 continue;
             }
-            if (ParsingPackageUtils.getAconfigFlags().skipCurrentElement(parser)) {
-                continue;
-            }
 
             final ParseResult result;
             String nodeName = parser.getName();
diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedProviderUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedProviderUtils.java
index 6af2a29..12aff1c 100644
--- a/core/java/com/android/internal/pm/pkg/component/ParsedProviderUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedProviderUtils.java
@@ -36,7 +36,6 @@
 
 import com.android.internal.R;
 import com.android.internal.pm.pkg.parsing.ParsingPackage;
-import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
 import com.android.internal.pm.pkg.parsing.ParsingUtils;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -174,9 +173,6 @@
             if (type != XmlPullParser.START_TAG) {
                 continue;
             }
-            if (ParsingPackageUtils.getAconfigFlags().skipCurrentElement(parser)) {
-                continue;
-            }
 
             String name = parser.getName();
             final ParseResult result;
diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedServiceUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedServiceUtils.java
index c68ea2d..4ac542f8 100644
--- a/core/java/com/android/internal/pm/pkg/component/ParsedServiceUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedServiceUtils.java
@@ -34,7 +34,6 @@
 
 import com.android.internal.R;
 import com.android.internal.pm.pkg.parsing.ParsingPackage;
-import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
 import com.android.internal.pm.pkg.parsing.ParsingUtils;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -138,9 +137,6 @@
             if (type != XmlPullParser.START_TAG) {
                 continue;
             }
-            if (ParsingPackageUtils.getAconfigFlags().skipCurrentElement(parser)) {
-                continue;
-            }
 
             final ParseResult parseResult;
             switch (parser.getName()) {
diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
index 44fedb1..1dcd893 100644
--- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
@@ -90,7 +90,6 @@
 import com.android.internal.os.ClassLoaderFactory;
 import com.android.internal.pm.parsing.pkg.ParsedPackage;
 import com.android.internal.pm.permission.CompatibilityPermissionInfo;
-import com.android.internal.pm.pkg.component.AconfigFlags;
 import com.android.internal.pm.pkg.component.ComponentMutateUtils;
 import com.android.internal.pm.pkg.component.ComponentParseUtils;
 import com.android.internal.pm.pkg.component.InstallConstraintsTagParser;
@@ -293,7 +292,6 @@
     @NonNull
     private final List<PermissionManager.SplitPermissionInfo> mSplitPermissionInfos;
     private final Callback mCallback;
-    private static final AconfigFlags sAconfigFlags = new AconfigFlags();
 
     public ParsingPackageUtils(String[] separateProcesses, DisplayMetrics displayMetrics,
             @NonNull List<PermissionManager.SplitPermissionInfo> splitPermissions,
@@ -763,9 +761,6 @@
             if (outerDepth + 1 < parser.getDepth() || type != XmlPullParser.START_TAG) {
                 continue;
             }
-            if (sAconfigFlags.skipCurrentElement(parser)) {
-                continue;
-            }
 
             final ParseResult result;
             String tagName = parser.getName();
@@ -842,9 +837,6 @@
             if (type != XmlPullParser.START_TAG) {
                 continue;
             }
-            if (sAconfigFlags.skipCurrentElement(parser)) {
-                continue;
-            }
 
             ParsedMainComponent mainComponent = null;
 
@@ -988,9 +980,6 @@
             if (type != XmlPullParser.START_TAG) {
                 continue;
             }
-            if (sAconfigFlags.skipCurrentElement(parser)) {
-                continue;
-            }
 
             String tagName = parser.getName();
             final ParseResult result;
@@ -1610,9 +1599,6 @@
             if (type != XmlPullParser.START_TAG) {
                 continue;
             }
-            if (sAconfigFlags.skipCurrentElement(parser)) {
-                continue;
-            }
 
             final String innerTagName = parser.getName();
             if (innerTagName.equals("uses-feature")) {
@@ -1853,9 +1839,6 @@
             if (type != XmlPullParser.START_TAG) {
                 continue;
             }
-            if (sAconfigFlags.skipCurrentElement(parser)) {
-                continue;
-            }
             if (parser.getName().equals("intent")) {
                 ParseResult<ParsedIntentInfoImpl> result = ParsedIntentInfoUtils.parseIntentInfo(
                         null /*className*/, pkg, res, parser, true /*allowGlobs*/,
@@ -2202,9 +2185,6 @@
             if (type != XmlPullParser.START_TAG) {
                 continue;
             }
-            if (sAconfigFlags.skipCurrentElement(parser)) {
-                continue;
-            }
 
             final ParseResult result;
             String tagName = parser.getName();
@@ -2793,9 +2773,6 @@
             if (type != XmlPullParser.START_TAG) {
                 continue;
             }
-            if (sAconfigFlags.skipCurrentElement(parser)) {
-                continue;
-            }
 
             final String nodeName = parser.getName();
             if (nodeName.equals("additional-certificate")) {
@@ -3481,11 +3458,4 @@
 
         @NonNull Set<String> getInstallConstraintsAllowlist();
     }
-
-    /**
-     * Getter for the flags object
-     */
-    public static AconfigFlags getAconfigFlags() {
-        return sAconfigFlags;
-    }
 }
diff --git a/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java b/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java
index 4a3dfbe..1494425 100644
--- a/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java
+++ b/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java
@@ -15,14 +15,23 @@
  */
 package com.android.internal.ravenwood;
 
+import android.ravenwood.annotation.RavenwoodNativeSubstitutionClass;
+
 /**
  * Class to interact with the Ravenwood environment.
  */
 @android.ravenwood.annotation.RavenwoodKeepWholeClass
-public class RavenwoodEnvironment {
+@RavenwoodNativeSubstitutionClass(
+        "com.android.platform.test.ravenwood.nativesubstitution.RavenwoodEnvironment_host")
+public final class RavenwoodEnvironment {
+    public static final String TAG = "RavenwoodEnvironment";
+
     private static RavenwoodEnvironment sInstance = new RavenwoodEnvironment();
 
     private RavenwoodEnvironment() {
+        if (isRunningOnRavenwood()) {
+            ensureRavenwoodInitializedInternal();
+        }
     }
 
     /**
@@ -33,6 +42,21 @@
     }
 
     /**
+     * Initialize the ravenwood environment if it hasn't happened already, if running on Ravenwood.
+     *
+     * No-op if called on the device side.
+     */
+    public static void ensureRavenwoodInitialized() {
+    }
+
+    private static void ensureRavenwoodInitialized$ravenwood() {
+        getInstance(); // This is enough to initialize the environment.
+    }
+
+    /** Initialize the ravenwood environment */
+    private static native void ensureRavenwoodInitializedInternal();
+
+    /**
      * USE IT SPARINGLY! Returns true if it's running on Ravenwood, hostside test environment.
      *
      * <p>Using this allows code to behave differently on a real device and on Ravenwood, but
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 3fc4fff..7f896ff 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -64,7 +64,7 @@
 
     @Override
     public void insetsControlChanged(InsetsState insetsState,
-            InsetsSourceControl[] activeControls) {
+            InsetsSourceControl.Array activeControls) {
     }
 
     @Override
diff --git a/core/tests/coretests/src/android/view/ImeBackAnimationControllerTest.java b/core/tests/coretests/src/android/view/ImeBackAnimationControllerTest.java
index 5917cc1..58e5be2 100644
--- a/core/tests/coretests/src/android/view/ImeBackAnimationControllerTest.java
+++ b/core/tests/coretests/src/android/view/ImeBackAnimationControllerTest.java
@@ -99,6 +99,8 @@
             } catch (WindowManager.BadTokenException e) {
                 // activity isn't running, we will ignore BadTokenException.
             }
+            mViewRoot.setOnContentApplyWindowInsetsListener(
+                    mock(Window.OnContentApplyWindowInsetsListener.class));
             mBackAnimationController = new ImeBackAnimationController(mViewRoot, mInsetsController);
 
             when(mWindowInsetsAnimationController.getHiddenStateInsets()).thenReturn(Insets.NONE);
@@ -132,6 +134,19 @@
     }
 
     @Test
+    public void testAdjustResizeWithEdgeToEdgePlaysAnim() {
+        // set OnContentApplyWindowInsetsListener to null (to simulate edge-to-edge enabled) and
+        // softInputMode=adjustResize
+        mViewRoot.mWindowAttributes.softInputMode = SOFT_INPUT_ADJUST_RESIZE;
+        mViewRoot.setOnContentApplyWindowInsetsListener(null);
+        // start back gesture
+        mBackAnimationController.onBackStarted(new BackEvent(0f, 0f, 0f, EDGE_LEFT));
+        // verify that ImeBackAnimationController takes control over IME insets
+        verify(mInsetsController, times(1)).controlWindowInsetsAnimation(anyInt(), any(), any(),
+                anyBoolean(), anyLong(), any(), anyInt(), anyBoolean());
+    }
+
+    @Test
     public void testAdjustResizeWithoutAppWindowInsetsListenerNotPlayingAnim() {
         // setup ViewRoot with softInputMode=adjustResize
         mViewRoot.mWindowAttributes.softInputMode = SOFT_INPUT_ADJUST_RESIZE;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt
index c988c2f..71fc8c3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt
@@ -41,6 +41,9 @@
 import android.window.BackNavigationInfo
 import android.window.BackProgressAnimator
 import android.window.IOnBackInvokedCallback
+import com.android.internal.dynamicanimation.animation.FloatValueHolder
+import com.android.internal.dynamicanimation.animation.SpringAnimation
+import com.android.internal.dynamicanimation.animation.SpringForce
 import com.android.internal.jank.Cuj
 import com.android.internal.policy.ScreenDecorationsUtils
 import com.android.internal.protolog.common.ProtoLog
@@ -70,6 +73,7 @@
 
     protected val backAnimRect = Rect()
     private val cropRect = Rect()
+    private val tempRectF = RectF()
 
     private var cornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context)
 
@@ -98,6 +102,12 @@
     private var rightLetterboxLayer: SurfaceControl? = null
     private var letterboxColor: Int = 0
 
+    private val postCommitFlingScale = FloatValueHolder(SPRING_SCALE)
+    private var lastPostCommitFlingScale = SPRING_SCALE
+    private val postCommitFlingSpring = SpringForce(SPRING_SCALE)
+            .setStiffness(SpringForce.STIFFNESS_LOW)
+            .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
+
     /** Background color to be used during the animation, also see [getBackgroundColor] */
     protected var customizedBackgroundColor = 0
 
@@ -231,7 +241,7 @@
         return deltaY
     }
 
-    protected open fun onGestureCommitted() {
+    protected open fun onGestureCommitted(velocity: Float) {
         if (
             closingTarget?.leash == null ||
                 enteringTarget?.leash == null ||
@@ -242,6 +252,14 @@
             return
         }
 
+        // kick off spring animation with the current velocity from the pre-commit phase, this
+        // affects the scaling of the closing activity during post-commit
+        val flingAnimation = SpringAnimation(postCommitFlingScale, SPRING_SCALE)
+            .setStartVelocity(min(0f, -velocity * SPRING_SCALE))
+            .setStartValue(SPRING_SCALE)
+            .setSpring(postCommitFlingSpring)
+        flingAnimation.start()
+
         val valueAnimator = ValueAnimator.ofFloat(1f, 0f).setDuration(POST_COMMIT_DURATION)
         valueAnimator.addUpdateListener { animation: ValueAnimator ->
             val progress = animation.animatedFraction
@@ -291,6 +309,7 @@
         removeLetterbox()
         isLetterboxed = false
         enteringHasSameLetterbox = false
+        lastPostCommitFlingScale = SPRING_SCALE
     }
 
     protected fun applyTransform(
@@ -300,7 +319,15 @@
         baseTransformation: Transformation? = null
     ) {
         if (leash == null || !leash.isValid) return
-        val scale = rect.width() / backAnimRect.width()
+        tempRectF.set(rect)
+        if (leash == closingTarget?.leash) {
+            lastPostCommitFlingScale = (postCommitFlingScale.value / SPRING_SCALE).coerceIn(
+                    minimumValue = MAX_FLING_SCALE, maximumValue = lastPostCommitFlingScale
+            )
+            // apply an additional scale to the closing target to account for fling velocity
+            tempRectF.scaleCentered(lastPostCommitFlingScale)
+        }
+        val scale = tempRectF.width() / backAnimRect.width()
         val matrix = baseTransformation?.matrix ?: transformMatrix.apply { reset() }
         val scalePivotX =
             if (isLetterboxed && enteringHasSameLetterbox) {
@@ -309,7 +336,7 @@
                 0f
             }
         matrix.postScale(scale, scale, scalePivotX, 0f)
-        matrix.postTranslate(rect.left, rect.top)
+        matrix.postTranslate(tempRectF.left, tempRectF.top)
         transaction
             .setAlpha(leash, keepMinimumAlpha(alpha))
             .setMatrix(leash, matrix, tmpFloat9)
@@ -461,7 +488,7 @@
 
         override fun onBackInvoked() {
             progressAnimator.reset()
-            onGestureCommitted()
+            onGestureCommitted(progressAnimator.velocity)
         }
     }
 
@@ -497,6 +524,8 @@
         private const val MAX_SCRIM_ALPHA_DARK = 0.8f
         private const val MAX_SCRIM_ALPHA_LIGHT = 0.2f
         private const val POST_COMMIT_DURATION = 300L
+        private const val SPRING_SCALE = 100f
+        private const val MAX_FLING_SCALE = 0.6f
     }
 }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/DefaultCrossActivityBackAnimation.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/back/DefaultCrossActivityBackAnimation.kt
index f33c5b9..d6c5349 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/DefaultCrossActivityBackAnimation.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/DefaultCrossActivityBackAnimation.kt
@@ -56,7 +56,7 @@
         targetEnteringRect.scaleCentered(MAX_SCALE)
     }
 
-    override fun onGestureCommitted() {
+    override fun onGestureCommitted(velocity: Float) {
         // We enter phase 2 of the animation, the starting coordinates for phase 2 are the current
         // coordinate of the gesture driven phase. Let's update the start and target rects and kick
         // off the animator in the superclass
@@ -65,7 +65,7 @@
         targetEnteringRect.set(backAnimRect)
         targetClosingRect.set(backAnimRect)
         targetClosingRect.offset(currentClosingRect.left + enteringStartOffset, 0f)
-        super.onGestureCommitted()
+        super.onGestureCommitted(velocity)
     }
 
     override fun onPostCommitProgress(linearProgress: Float) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
index da414cc..ef33b38 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
@@ -353,7 +353,7 @@
 
         @Override
         public void insetsControlChanged(InsetsState insetsState,
-                InsetsSourceControl[] activeControls) {}
+                InsetsSourceControl.Array activeControls) {}
 
         @Override
         public void showInsets(int types, boolean fromIme, @Nullable ImeTracker.Token statsToken) {}
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 165feec..7e70d6a 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
@@ -316,7 +316,8 @@
                 }
                 // TODO(b/290391688): Also update the session data with task stack changes
                 pd.dragSession = new DragSession(ActivityTaskManager.getInstance(),
-                        mDisplayController.getDisplayLayout(displayId), event.getClipData());
+                        mDisplayController.getDisplayLayout(displayId), event.getClipData(),
+                        event.getDragFlags());
                 pd.dragSession.update();
                 pd.activeDragCount++;
                 pd.dragLayout.prepare(pd.dragSession, mLogger.logStart(pd.dragSession));
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java
index 8f1bc59..0addd43 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java
@@ -40,6 +40,7 @@
 public class DragSession {
     private final ActivityTaskManager mActivityTaskManager;
     private final ClipData mInitialDragData;
+    private final int mInitialDragFlags;
 
     final DisplayLayout displayLayout;
     // The activity info associated with the activity in the appData or the launchableIntent
@@ -62,9 +63,10 @@
     boolean dragItemSupportsSplitscreen;
 
     DragSession(ActivityTaskManager activityTaskManager,
-            DisplayLayout dispLayout, ClipData data) {
+            DisplayLayout dispLayout, ClipData data, int dragFlags) {
         mActivityTaskManager = activityTaskManager;
         mInitialDragData = data;
+        mInitialDragFlags = dragFlags;
         displayLayout = dispLayout;
     }
 
@@ -94,6 +96,6 @@
         dragItemSupportsSplitscreen = activityInfo == null
                 || ActivityInfo.isResizeableMode(activityInfo.resizeMode);
         appData = mInitialDragData.getItemAt(0).getIntent();
-        launchableIntent = DragUtils.getLaunchIntent(mInitialDragData);
+        launchableIntent = DragUtils.getLaunchIntent(mInitialDragData, mInitialDragFlags);
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragUtils.java
index 24f8e18..e215870 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragUtils.java
@@ -24,6 +24,7 @@
 import android.content.ClipData;
 import android.content.ClipDescription;
 import android.view.DragEvent;
+import android.view.View;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -67,14 +68,18 @@
      */
     @Nullable
     public static PendingIntent getLaunchIntent(@NonNull DragEvent dragEvent) {
-        return getLaunchIntent(dragEvent.getClipData());
+        return getLaunchIntent(dragEvent.getClipData(), dragEvent.getDragFlags());
     }
 
     /**
      * Returns a launchable intent in the given `ClipData` or `null` if there is none.
      */
     @Nullable
-    public static PendingIntent getLaunchIntent(@NonNull ClipData data) {
+    public static PendingIntent getLaunchIntent(@NonNull ClipData data, int dragFlags) {
+        if ((dragFlags & View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG) == 0) {
+            // Disallow launching the intent if the app does not want to delegate it to the system
+            return null;
+        }
         for (int i = 0; i < data.getItemCount(); i++) {
             final ClipData.Item item = data.getItemAt(i);
             if (item.getIntentSender() != null) {
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 a7829c9..3a266d9 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
@@ -402,6 +402,11 @@
             }
         }
 
+        /**
+         * Cleans up the recents transition.  This should generally not be called directly
+         * to cancel a transition after it has started, instead callers should call one of
+         * the cancel() methods to ensure that Launcher is notified.
+         */
         void cleanUp() {
             ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
                     "[%d] RecentsController.cleanup", mInstanceId);
@@ -438,7 +443,8 @@
             if (mListener == null || mTransition == null) {
                 Slog.e(TAG, "Missing listener or transition, hasListener=" + (mListener != null) +
                         " hasTransition=" + (mTransition != null));
-                cleanUp();
+                cancel("No listener (" + (mListener == null)
+                        + ") or no transition (" + (mTransition == null) + ")");
                 return false;
             }
             // First see if this is a valid recents transition.
@@ -462,7 +468,7 @@
             if (mRecentsTask == null && !hasPausingTasks) {
                 // Recents is already running apparently, so this is a no-op.
                 Slog.e(TAG, "Tried to start recents while it is already running.");
-                cleanUp();
+                cancel("No recents task and no pausing tasks");
                 return false;
             }
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
index 5dd9d8a..6e72e8d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java
@@ -66,6 +66,7 @@
 import android.os.RemoteException;
 import android.view.DisplayInfo;
 import android.view.DragEvent;
+import android.view.View;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
@@ -115,6 +116,7 @@
     private DragAndDropPolicy mPolicy;
 
     private ClipData mActivityClipData;
+    private PendingIntent mLaunchableIntentPendingIntent;
     private ClipData mLaunchableIntentClipData;
     private ClipData mNonResizeableActivityClipData;
     private ClipData mTaskClipData;
@@ -151,7 +153,10 @@
 
         mPolicy = spy(new DragAndDropPolicy(mContext, mSplitScreenStarter, mSplitScreenStarter));
         mActivityClipData = createAppClipData(MIMETYPE_APPLICATION_ACTIVITY);
-        mLaunchableIntentClipData = createIntentClipData();
+        mLaunchableIntentPendingIntent = mock(PendingIntent.class);
+        when(mLaunchableIntentPendingIntent.getCreatorUserHandle())
+                .thenReturn(android.os.Process.myUserHandle());
+        mLaunchableIntentClipData = createIntentClipData(mLaunchableIntentPendingIntent);
         mNonResizeableActivityClipData = createAppClipData(MIMETYPE_APPLICATION_ACTIVITY);
         setClipDataResizeable(mNonResizeableActivityClipData, false);
         mTaskClipData = createAppClipData(MIMETYPE_APPLICATION_TASK);
@@ -202,16 +207,13 @@
     /**
      * Creates an intent-based clip data that is by default resizeable.
      */
-    private ClipData createIntentClipData() {
+    private ClipData createIntentClipData(PendingIntent intent) {
         ClipDescription clipDescription = new ClipDescription("Intent",
                 new String[] { MIMETYPE_TEXT_INTENT });
-        PendingIntent intent = mock(PendingIntent.class);
-        when(intent.getCreatorUserHandle()).thenReturn(android.os.Process.myUserHandle());
         ClipData.Item item = new ClipData.Item.Builder()
                 .setIntentSender(intent.getIntentSender())
                 .build();
         ClipData data = new ClipData(clipDescription, item);
-        when(DragUtils.getLaunchIntent((ClipData) any())).thenReturn(intent);
         return data;
     }
 
@@ -259,16 +261,22 @@
 
     @Test
     public void testDragIntentOverFullscreenHome_expectOnlyFullscreenTarget() {
+        when(DragUtils.getLaunchIntent((ClipData) any(), anyInt())).thenReturn(
+                mLaunchableIntentPendingIntent);
         dragOverFullscreenHome_expectOnlyFullscreenTarget(mLaunchableIntentClipData);
     }
 
     @Test
     public void testDragIntentOverFullscreenApp_expectSplitScreenTargets() {
+        when(DragUtils.getLaunchIntent((ClipData) any(), anyInt())).thenReturn(
+                mLaunchableIntentPendingIntent);
         dragOverFullscreenApp_expectSplitScreenTargets(mLaunchableIntentClipData);
     }
 
     @Test
     public void testDragIntentOverFullscreenAppPhone_expectVerticalSplitScreenTargets() {
+        when(DragUtils.getLaunchIntent((ClipData) any(), anyInt())).thenReturn(
+                mLaunchableIntentPendingIntent);
         dragOverFullscreenAppPhone_expectVerticalSplitScreenTargets(mLaunchableIntentClipData);
     }
 
@@ -276,7 +284,7 @@
         doReturn(true).when(mSplitScreenStarter).isLeftRightSplit();
         setRunningTask(mHomeTask);
         DragSession dragSession = new DragSession(mActivityTaskManager,
-                mLandscapeDisplayLayout, data);
+                mLandscapeDisplayLayout, data, 0 /* dragFlags */);
         dragSession.update();
         mPolicy.start(dragSession, mLoggerSessionId);
         ArrayList<Target> targets = assertExactTargetTypes(
@@ -291,7 +299,7 @@
         doReturn(true).when(mSplitScreenStarter).isLeftRightSplit();
         setRunningTask(mFullscreenAppTask);
         DragSession dragSession = new DragSession(mActivityTaskManager,
-                mLandscapeDisplayLayout, data);
+                mLandscapeDisplayLayout, data, 0 /* dragFlags */);
         dragSession.update();
         mPolicy.start(dragSession, mLoggerSessionId);
         ArrayList<Target> targets = assertExactTargetTypes(
@@ -311,7 +319,7 @@
         doReturn(false).when(mSplitScreenStarter).isLeftRightSplit();
         setRunningTask(mFullscreenAppTask);
         DragSession dragSession = new DragSession(mActivityTaskManager,
-                mPortraitDisplayLayout, data);
+                mPortraitDisplayLayout, data, 0 /* dragFlags */);
         dragSession.update();
         mPolicy.start(dragSession, mLoggerSessionId);
         ArrayList<Target> targets = assertExactTargetTypes(
@@ -331,7 +339,7 @@
     public void testTargetHitRects() {
         setRunningTask(mFullscreenAppTask);
         DragSession dragSession = new DragSession(mActivityTaskManager,
-                mLandscapeDisplayLayout, mActivityClipData);
+                mLandscapeDisplayLayout, mActivityClipData, 0 /* dragFlags */);
         dragSession.update();
         mPolicy.start(dragSession, mLoggerSessionId);
         ArrayList<Target> targets = mPolicy.getTargets(mInsets);
@@ -345,6 +353,11 @@
         }
     }
 
+    @Test
+    public void testDisallowLaunchIntentWithoutDelegationFlag() {
+        assertTrue(DragUtils.getLaunchIntent(mLaunchableIntentClipData, 0) == null);
+    }
+
     private Target filterTargetByType(ArrayList<Target> targets, int type) {
         for (Target t : targets) {
             if (type == t.type) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/GlobalDragListenerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/GlobalDragListenerTest.kt
index e731b06..d410151 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/GlobalDragListenerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/GlobalDragListenerTest.kt
@@ -74,7 +74,7 @@
     @Test
     fun onUnhandledDrop_noListener_expectNotifyUnhandled() {
         // Simulate an unhandled drop
-        val dropEvent = DragEvent.obtain(ACTION_DROP, 0f, 0f, 0f, 0f, null, null, null,
+        val dropEvent = DragEvent.obtain(ACTION_DROP, 0f, 0f, 0f, 0f, 0, null, null, null,
             null, null, false)
         val wmCallback = mock<IUnhandledDragCallback>()
         mController.onUnhandledDrop(dropEvent, wmCallback)
@@ -98,7 +98,7 @@
 
         // Simulate an unhandled drop
         val dragSurface = mock<SurfaceControl>()
-        val dropEvent = DragEvent.obtain(ACTION_DROP, 0f, 0f, 0f, 0f, null, null, null,
+        val dropEvent = DragEvent.obtain(ACTION_DROP, 0f, 0f, 0f, 0f, 0, null, null, null,
             dragSurface, null, false)
         val wmCallback = mock<IUnhandledDragCallback>()
         mController.onUnhandledDrop(dropEvent, wmCallback)
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt
index 36e396fb..3b84333 100644
--- a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt
@@ -79,8 +79,6 @@
     suspend fun setMuted(audioStream: AudioStream, isMuted: Boolean): Boolean
 
     suspend fun setRingerMode(audioStream: AudioStream, mode: RingerMode)
-
-    suspend fun isAffectedByMute(audioStream: AudioStream): Boolean
 }
 
 class AudioRepositoryImpl(
@@ -152,8 +150,9 @@
             minVolume = getMinVolume(audioStream),
             maxVolume = audioManager.getStreamMaxVolume(audioStream.value),
             volume = audioManager.getStreamVolume(audioStream.value),
+            isAffectedByMute = audioManager.isStreamAffectedByMute(audioStream.value),
             isAffectedByRingerMode = audioManager.isStreamAffectedByRingerMode(audioStream.value),
-            isMuted = audioManager.isStreamMute(audioStream.value)
+            isMuted = audioManager.isStreamMute(audioStream.value),
         )
     }
 
@@ -187,12 +186,6 @@
         withContext(backgroundCoroutineContext) { audioManager.ringerMode = mode.value }
     }
 
-    override suspend fun isAffectedByMute(audioStream: AudioStream): Boolean {
-        return withContext(backgroundCoroutineContext) {
-            audioManager.isStreamAffectedByMute(audioStream.value)
-        }
-    }
-
     private fun getMinVolume(stream: AudioStream): Int =
         try {
             audioManager.getStreamMinVolume(stream.value)
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/domain/interactor/AudioVolumeInteractor.kt b/packages/SettingsLib/src/com/android/settingslib/volume/domain/interactor/AudioVolumeInteractor.kt
index 0e5ebda..202ff40 100644
--- a/packages/SettingsLib/src/com/android/settingslib/volume/domain/interactor/AudioVolumeInteractor.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/volume/domain/interactor/AudioVolumeInteractor.kt
@@ -50,11 +50,13 @@
     suspend fun setVolume(audioStream: AudioStream, volume: Int) {
         val streamModel = getAudioStream(audioStream).first()
         val oldVolume = streamModel.volume
-        audioRepository.setVolume(audioStream, volume)
-        when {
-            volume == streamModel.minVolume -> setMuted(audioStream, true)
-            oldVolume == streamModel.minVolume && volume > streamModel.minVolume ->
-                setMuted(audioStream, false)
+        if (volume != oldVolume) {
+            audioRepository.setVolume(audioStream, volume)
+            when {
+                volume == streamModel.minVolume -> setMuted(audioStream, true)
+                oldVolume == streamModel.minVolume && volume > streamModel.minVolume ->
+                    setMuted(audioStream, false)
+            }
         }
     }
 
@@ -90,9 +92,6 @@
         }
     }
 
-    suspend fun isAffectedByMute(audioStream: AudioStream): Boolean =
-        audioRepository.isAffectedByMute(audioStream)
-
     private suspend fun processVolume(
         audioStreamModel: AudioStreamModel,
         ringerMode: RingerMode,
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/shared/model/AudioStreamModel.kt b/packages/SettingsLib/src/com/android/settingslib/volume/shared/model/AudioStreamModel.kt
index c1be1ee..2c26af1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/volume/shared/model/AudioStreamModel.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/volume/shared/model/AudioStreamModel.kt
@@ -22,6 +22,7 @@
     val volume: Int,
     val minVolume: Int,
     val maxVolume: Int,
+    val isAffectedByMute: Boolean,
     val isAffectedByRingerMode: Boolean,
     val isMuted: Boolean,
 )
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/AudioRepositoryTest.kt b/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/AudioRepositoryTest.kt
index 9860cd8..8700680 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/AudioRepositoryTest.kt
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/AudioRepositoryTest.kt
@@ -173,6 +173,7 @@
                         volume = 50,
                         minVolume = MIN_VOLUME,
                         maxVolume = MAX_VOLUME,
+                        isAffectedByMute = false,
                         isAffectedByRingerMode = false,
                         isMuted = false,
                     )
@@ -201,6 +202,7 @@
                         volume = 0,
                         minVolume = MIN_VOLUME,
                         maxVolume = MAX_VOLUME,
+                        isAffectedByMute = false,
                         isAffectedByRingerMode = false,
                         isMuted = true,
                     )
@@ -230,6 +232,7 @@
                         volume = 0,
                         minVolume = MIN_VOLUME,
                         maxVolume = MAX_VOLUME,
+                        isAffectedByMute = false,
                         isAffectedByRingerMode = false,
                         isMuted = false,
                     )
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index f3e2272..a2d7b2f 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -977,6 +977,13 @@
 }
 
 flag {
+  name: "new_touchpad_gestures_tutorial"
+  namespace: "systemui"
+  description: "Enables new interactive tutorial for learning touchpad gestures"
+  bug: "309928033"
+}
+
+flag {
    name: "register_wallpaper_notifier_background"
    namespace: "systemui"
    description: "Decide whether to register wallpaper change broadcast receiver on background executor."
diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/LockscreenSceneModule.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/LockscreenSceneModule.kt
index f5dc154..bd5b795a 100644
--- a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/LockscreenSceneModule.kt
+++ b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/LockscreenSceneModule.kt
@@ -19,11 +19,14 @@
 import android.view.View
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyguard.KeyguardViewConfigurator
+import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
 import com.android.systemui.keyguard.qualifiers.KeyguardRootView
 import com.android.systemui.keyguard.shared.model.LockscreenSceneBlueprint
+import com.android.systemui.keyguard.ui.composable.LockscreenContent
 import com.android.systemui.keyguard.ui.composable.LockscreenScene
 import com.android.systemui.keyguard.ui.composable.LockscreenSceneBlueprintModule
 import com.android.systemui.keyguard.ui.composable.blueprint.ComposableLockscreenSceneBlueprint
+import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
 import com.android.systemui.scene.shared.model.Scene
 import dagger.Binds
 import dagger.Module
@@ -60,5 +63,14 @@
         ): Set<LockscreenSceneBlueprint> {
             return blueprints
         }
+
+        @Provides
+        fun providesLockscreenContent(
+            viewModel: LockscreenContentViewModel,
+            blueprints: Set<@JvmSuppressWildcards ComposableLockscreenSceneBlueprint>,
+            clockInteractor: KeyguardClockInteractor,
+        ): LockscreenContent {
+            return LockscreenContent(viewModel, blueprints, clockInteractor)
+        }
     }
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
index ca4ff83..99f7d0f 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt
@@ -36,9 +36,7 @@
  * This is separate from the [LockscreenScene] because it's meant to support usage of this UI from
  * outside the scene container framework.
  */
-class LockscreenContent
-@Inject
-constructor(
+class LockscreenContent(
     private val viewModel: LockscreenContentViewModel,
     private val blueprints: Set<@JvmSuppressWildcards ComposableLockscreenSceneBlueprint>,
     private val clockInteractor: KeyguardClockInteractor,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/StatusBarSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/StatusBarSection.kt
index d996d25..166aa70 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/StatusBarSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/StatusBarSection.kt
@@ -54,12 +54,19 @@
         @SuppressLint("InflateParams")
         val view =
             remember(context) {
-                LayoutInflater.from(context)
-                    .inflate(
-                        R.layout.keyguard_status_bar,
-                        null,
-                        false,
-                    ) as KeyguardStatusBarView
+                (LayoutInflater.from(context)
+                        .inflate(
+                            R.layout.keyguard_status_bar,
+                            null,
+                            false,
+                        ) as KeyguardStatusBarView)
+                    .also {
+                        it.layoutParams =
+                            ViewGroup.LayoutParams(
+                                ViewGroup.LayoutParams.MATCH_PARENT,
+                                ViewGroup.LayoutParams.WRAP_CONTENT
+                            )
+                    }
             }
         val viewController =
             remember(view) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt
index 1c675e3..e17a146 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt
@@ -26,11 +26,14 @@
 import com.android.compose.animation.scene.UserAction
 import com.android.compose.animation.scene.UserActionResult
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.ui.composable.LockscreenContent
 import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeSceneViewModel
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.scene.ui.composable.ComposableScene
 import com.android.systemui.shade.ui.composable.OverlayShade
 import com.android.systemui.shade.ui.viewmodel.OverlayShadeViewModel
+import dagger.Lazy
+import java.util.Optional
 import javax.inject.Inject
 import kotlinx.coroutines.flow.StateFlow
 
@@ -40,6 +43,7 @@
 constructor(
     viewModel: NotificationsShadeSceneViewModel,
     private val overlayShadeViewModel: OverlayShadeViewModel,
+    private val lockscreenContent: Lazy<Optional<LockscreenContent>>,
 ) : ComposableScene {
 
     override val key = Scenes.NotificationsShade
@@ -55,6 +59,7 @@
             viewModel = overlayShadeViewModel,
             modifier = modifier,
             horizontalArrangement = Arrangement.Start,
+            lockscreenContent = lockscreenContent,
         ) {
             Text(
                 text = "Notifications list",
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt
index 636c6c3..04f76f5 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt
@@ -26,13 +26,16 @@
 import com.android.compose.animation.scene.UserAction
 import com.android.compose.animation.scene.UserActionResult
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.ui.composable.LockscreenContent
 import com.android.systemui.qs.ui.viewmodel.QuickSettingsShadeSceneViewModel
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.scene.ui.composable.ComposableScene
 import com.android.systemui.shade.ui.composable.OverlayShade
 import com.android.systemui.shade.ui.viewmodel.OverlayShadeViewModel
+import dagger.Lazy
 import javax.inject.Inject
 import kotlinx.coroutines.flow.StateFlow
+import java.util.Optional
 
 @SysUISingleton
 class QuickSettingsShadeScene
@@ -40,6 +43,7 @@
 constructor(
     viewModel: QuickSettingsShadeSceneViewModel,
     private val overlayShadeViewModel: OverlayShadeViewModel,
+    private val lockscreenContent: Lazy<Optional<LockscreenContent>>,
 ) : ComposableScene {
 
     override val key = Scenes.QuickSettingsShade
@@ -55,6 +59,7 @@
             viewModel = overlayShadeViewModel,
             modifier = modifier,
             horizontalArrangement = Arrangement.End,
+            lockscreenContent = lockscreenContent,
         ) {
             Text(
                 text = "Quick settings grid",
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
index 00ef11d..736d805 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/OverlayShade.kt
@@ -27,11 +27,9 @@
 import androidx.compose.foundation.layout.width
 import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.ReadOnlyComposable
 import androidx.compose.runtime.getValue
-import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.clip
 import androidx.compose.ui.graphics.Color
@@ -40,14 +38,19 @@
 import com.android.compose.animation.scene.ElementKey
 import com.android.compose.animation.scene.LowestZIndexScenePicker
 import com.android.compose.animation.scene.SceneScope
+import com.android.systemui.keyguard.ui.composable.LockscreenContent
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.shade.ui.viewmodel.OverlayShadeViewModel
+import com.android.systemui.util.kotlin.getOrNull
+import dagger.Lazy
+import java.util.Optional
 
 /** The overlay shade renders a lightweight shade UI container on top of a background scene. */
 @Composable
 fun SceneScope.OverlayShade(
     viewModel: OverlayShadeViewModel,
     horizontalArrangement: Arrangement.Horizontal,
+    lockscreenContent: Lazy<Optional<LockscreenContent>>,
     modifier: Modifier = Modifier,
     content: @Composable () -> Unit,
 ) {
@@ -55,7 +58,10 @@
 
     Box(modifier) {
         if (backgroundScene == Scenes.Lockscreen) {
-            Lockscreen()
+            // Lockscreen content is optionally injected, because variants of System UI without a
+            // lockscreen cannot provide it.
+            val lockscreenContentOrNull = lockscreenContent.get().getOrNull()
+            lockscreenContentOrNull?.apply { Content(Modifier.fillMaxSize()) }
         }
 
         Scrim(onClicked = viewModel::onScrimClicked)
@@ -70,16 +76,6 @@
 }
 
 @Composable
-private fun Lockscreen(
-    modifier: Modifier = Modifier,
-) {
-    // TODO(b/338025605): This is a placeholder, replace with the actual lockscreen.
-    Box(modifier = modifier.fillMaxSize().background(Color.LightGray)) {
-        Text(text = "Lockscreen", modifier = Modifier.align(Alignment.Center))
-    }
-}
-
-@Composable
 private fun SceneScope.Scrim(
     onClicked: () -> Unit,
     modifier: Modifier = Modifier,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
index 18baee9..ad3d4ad8 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
@@ -342,10 +342,8 @@
 
     if (transition != previousTransition && transition != null && previousTransition != null) {
         // The previous transition was interrupted by another transition.
-        prepareInterruption(element)
-    }
-
-    if (transition == null && previousTransition != null) {
+        prepareInterruption(element, transition, previousTransition)
+    } else if (transition == null && previousTransition != null) {
         // The transition was just finished.
         element.sceneStates.values.forEach {
             it.clearValuesBeforeInterruption()
@@ -356,46 +354,103 @@
     return transition
 }
 
-private fun prepareInterruption(element: Element) {
-    // We look for the last unique state of this element so that we animate the delta with its
-    // future state.
-    val sceneStates = element.sceneStates.values
-    var lastUniqueState: Element.SceneState? = null
-    for (sceneState in sceneStates) {
-        val offset = sceneState.lastOffset
+private fun prepareInterruption(
+    element: Element,
+    transition: TransitionState.Transition,
+    previousTransition: TransitionState.Transition,
+) {
+    val previousUniqueState = reconcileStates(element, previousTransition)
+    if (previousUniqueState == null) {
+        reconcileStates(element, transition)
+        return
+    }
 
-        // If the element was placed in this scene...
-        if (offset != Offset.Unspecified) {
-            // ... and it is the first (and potentially the only) scene where the element was
-            // placed, save the state for later.
-            if (lastUniqueState == null) {
-                lastUniqueState = sceneState
-            } else {
-                // The element was placed in multiple scenes: we abort the interruption for this
-                // element.
-                // TODO(b/290930950): Better support cases where a shared element animation is
-                // disabled and the same element is drawn/placed in multiple scenes at the same
-                // time.
-                lastUniqueState = null
-                break
+    val fromSceneState = element.sceneStates[transition.fromScene]
+    val toSceneState = element.sceneStates[transition.toScene]
+
+    if (
+        fromSceneState == null ||
+            toSceneState == null ||
+            sharedElementTransformation(element.key, transition)?.enabled != false
+    ) {
+        // If there is only one copy of the element or if the element is shared, animate deltas in
+        // both scenes.
+        fromSceneState?.updateValuesBeforeInterruption(previousUniqueState)
+        toSceneState?.updateValuesBeforeInterruption(previousUniqueState)
+    }
+}
+
+/**
+ * Reconcile the state of [element] in the fromScene and toScene of [transition] so that the values
+ * before interruption have their expected values, taking shared transitions into account.
+ *
+ * If the element had a unique state, i.e. it is shared in [transition] or it is only present in one
+ * of the scenes, return it.
+ */
+private fun reconcileStates(
+    element: Element,
+    transition: TransitionState.Transition,
+): Element.SceneState? {
+    val fromSceneState = element.sceneStates[transition.fromScene]
+    val toSceneState = element.sceneStates[transition.toScene]
+    when {
+        // Element is in both scenes.
+        fromSceneState != null && toSceneState != null -> {
+            val isSharedTransformationDisabled =
+                sharedElementTransformation(element.key, transition)?.enabled == false
+            when {
+                // Element shared transition is disabled so the element is placed in both scenes.
+                isSharedTransformationDisabled -> {
+                    fromSceneState.updateValuesBeforeInterruption(fromSceneState)
+                    toSceneState.updateValuesBeforeInterruption(toSceneState)
+                    return null
+                }
+
+                // Element is shared and placed in fromScene only.
+                fromSceneState.lastOffset != Offset.Unspecified -> {
+                    fromSceneState.updateValuesBeforeInterruption(fromSceneState)
+                    toSceneState.updateValuesBeforeInterruption(fromSceneState)
+                    return fromSceneState
+                }
+
+                // Element is shared and placed in toScene only.
+                toSceneState.lastOffset != Offset.Unspecified -> {
+                    fromSceneState.updateValuesBeforeInterruption(toSceneState)
+                    toSceneState.updateValuesBeforeInterruption(toSceneState)
+                    return toSceneState
+                }
+
+                // Element is in none of the scenes.
+                else -> {
+                    fromSceneState.updateValuesBeforeInterruption(null)
+                    toSceneState.updateValuesBeforeInterruption(null)
+                    return null
+                }
             }
         }
+
+        // Element is only in fromScene.
+        fromSceneState != null -> {
+            fromSceneState.updateValuesBeforeInterruption(fromSceneState)
+            return fromSceneState
+        }
+
+        // Element is only in toScene.
+        toSceneState != null -> {
+            toSceneState.updateValuesBeforeInterruption(toSceneState)
+            return toSceneState
+        }
+        else -> return null
     }
+}
 
-    val lastOffset = lastUniqueState?.lastOffset ?: Offset.Unspecified
-    val lastSize = lastUniqueState?.lastSize ?: Element.SizeUnspecified
-    val lastScale = lastUniqueState?.lastScale ?: Scale.Unspecified
-    val lastAlpha = lastUniqueState?.lastAlpha ?: Element.AlphaUnspecified
+private fun Element.SceneState.updateValuesBeforeInterruption(lastState: Element.SceneState?) {
+    offsetBeforeInterruption = lastState?.lastOffset ?: Offset.Unspecified
+    sizeBeforeInterruption = lastState?.lastSize ?: Element.SizeUnspecified
+    scaleBeforeInterruption = lastState?.lastScale ?: Scale.Unspecified
+    alphaBeforeInterruption = lastState?.lastAlpha ?: Element.AlphaUnspecified
 
-    // Store the state of the element before the interruption and reset the deltas.
-    sceneStates.forEach { sceneState ->
-        sceneState.offsetBeforeInterruption = lastOffset
-        sceneState.sizeBeforeInterruption = lastSize
-        sceneState.scaleBeforeInterruption = lastScale
-        sceneState.alphaBeforeInterruption = lastAlpha
-
-        sceneState.clearInterruptionDeltas()
-    }
+    clearInterruptionDeltas()
 }
 
 private fun Element.SceneState.clearInterruptionDeltas() {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt
index 92d5c26..f1b2249 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt
@@ -73,7 +73,16 @@
          * the transition completes/settles.
          */
         val isUserInputOngoing: Flow<Boolean>,
-    ) : ObservableTransitionState
+    ) : ObservableTransitionState {
+        override fun toString(): String =
+            """Transition
+                |(from=$fromScene,
+                | to=$toScene,
+                | isInitiatedByUserInput=$isInitiatedByUserInput,
+                | isUserInputOngoing=$isUserInputOngoing
+                |)"""
+                .trimMargin()
+    }
 
     fun isIdle(scene: SceneKey?): Boolean {
         return this is Idle && (scene == null || this.currentScene == scene)
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
index 6e114e3..3eef1f0 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
@@ -1225,4 +1225,110 @@
         assertThat(stateInC.scaleInterruptionDelta).isEqualTo(Scale.Zero)
         assertThat(stateInC.alphaInterruptionDelta).isEqualTo(0f)
     }
+
+    @Test
+    fun interruption_sharedTransitionDisabled() = runTest {
+        // 4 frames of animation.
+        val duration = 4 * 16
+        val layoutSize = DpSize(200.dp, 100.dp)
+        val fooSize = 100.dp
+        val state =
+            rule.runOnUiThread {
+                MutableSceneTransitionLayoutStateImpl(
+                    SceneA,
+                    transitions {
+                        from(SceneA, to = SceneB) { spec = tween(duration, easing = LinearEasing) }
+
+                        // Disable the shared transition during B => C.
+                        from(SceneB, to = SceneC) {
+                            spec = tween(duration, easing = LinearEasing)
+                            sharedElement(TestElements.Foo, enabled = false)
+                        }
+                    },
+                )
+            }
+
+        @Composable
+        fun SceneScope.Foo(modifier: Modifier = Modifier) {
+            Box(modifier.element(TestElements.Foo).size(fooSize))
+        }
+
+        rule.setContent {
+            SceneTransitionLayout(state, Modifier.size(layoutSize)) {
+                scene(SceneA) {
+                    Box(Modifier.fillMaxSize()) { Foo(Modifier.align(Alignment.TopStart)) }
+                }
+
+                scene(SceneB) {
+                    Box(Modifier.fillMaxSize()) { Foo(Modifier.align(Alignment.TopEnd)) }
+                }
+
+                scene(SceneC) {
+                    Box(Modifier.fillMaxSize()) { Foo(Modifier.align(Alignment.BottomEnd)) }
+                }
+            }
+        }
+
+        // The offset of Foo when idle in A, B or C.
+        val offsetInA = DpOffset.Zero
+        val offsetInB = DpOffset(layoutSize.width - fooSize, 0.dp)
+        val offsetInC = DpOffset(layoutSize.width - fooSize, layoutSize.height - fooSize)
+
+        // State is a transition A => B at 50% interrupted by B => C at 30%.
+        val aToB =
+            transition(from = SceneA, to = SceneB, progress = { 0.5f }, onFinish = neverFinish())
+        var bToCInterruptionProgress by mutableStateOf(1f)
+        val bToC =
+            transition(
+                from = SceneB,
+                to = SceneC,
+                progress = { 0.3f },
+                interruptionProgress = { bToCInterruptionProgress },
+                onFinish = neverFinish(),
+            )
+        rule.runOnUiThread { state.startTransition(aToB, transitionKey = null) }
+        rule.waitForIdle()
+        rule.runOnUiThread { state.startTransition(bToC, transitionKey = null) }
+
+        // Foo is placed in both B and C given that the shared transition is disabled. In B, its
+        // offset is impacted by the interruption but in C it is not.
+        val offsetInAToB = lerp(offsetInA, offsetInB, 0.5f)
+        val interruptionDelta = offsetInAToB - offsetInB
+        assertThat(interruptionDelta).isNotEqualTo(Offset.Zero)
+        rule
+            .onNode(isElement(TestElements.Foo, SceneB))
+            .assertPositionInRootIsEqualTo(
+                offsetInB.x + interruptionDelta.x,
+                offsetInB.y + interruptionDelta.y,
+            )
+
+        rule
+            .onNode(isElement(TestElements.Foo, SceneC))
+            .assertPositionInRootIsEqualTo(offsetInC.x, offsetInC.y)
+
+        // Manually finish A => B so only B => C is remaining.
+        bToCInterruptionProgress = 0f
+        rule.runOnUiThread { state.finishTransition(aToB, SceneB) }
+        rule
+            .onNode(isElement(TestElements.Foo, SceneB))
+            .assertPositionInRootIsEqualTo(offsetInB.x, offsetInB.y)
+        rule
+            .onNode(isElement(TestElements.Foo, SceneC))
+            .assertPositionInRootIsEqualTo(offsetInC.x, offsetInC.y)
+
+        // Interrupt B => C by B => A, starting directly at 70%
+        val bToA =
+            transition(
+                from = SceneB,
+                to = SceneA,
+                progress = { 0.7f },
+                interruptionProgress = { 1f },
+            )
+        rule.runOnUiThread { state.startTransition(bToA, transitionKey = null) }
+
+        // Foo should have the position it had in B right before the interruption.
+        rule
+            .onNode(isElement(TestElements.Foo, SceneB))
+            .assertPositionInRootIsEqualTo(offsetInB.x, offsetInB.y)
+    }
 }
diff --git a/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestTransition.kt b/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestTransition.kt
index 4225291..6724851 100644
--- a/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestTransition.kt
+++ b/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestTransition.kt
@@ -138,10 +138,13 @@
     toScene: SceneKey = TestScenes.SceneB,
 ): RecordedMotion {
     val state =
-        MutableSceneTransitionLayoutState(
-            fromScene,
-            transitions { from(fromScene, to = toScene, builder = transition) }
-        )
+        toolkit.composeContentTestRule.runOnUiThread {
+            MutableSceneTransitionLayoutState(
+                fromScene,
+                transitions { from(fromScene, to = toScene, builder = transition) }
+            )
+        }
+
     return recordMotion(
         content = { play ->
             LaunchedEffect(play) {
diff --git a/packages/SystemUI/monet/Android.bp b/packages/SystemUI/monet/Android.bp
deleted file mode 100644
index c54fdab..0000000
--- a/packages/SystemUI/monet/Android.bp
+++ /dev/null
@@ -1,33 +0,0 @@
-//
-// Copyright (C) 2021 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 {
-    default_team: "trendy_team_system_ui_please_use_a_more_specific_subteam_if_possible_",
-    default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-java_library {
-    name: "monet",
-    platform_apis: true,
-    static_libs: [
-        "androidx.annotation_annotation",
-        "androidx.core_core",
-        "libmonet",
-    ],
-    srcs: [
-        "src/**/*.java",
-        "src/**/*.kt",
-    ],
-}
diff --git a/packages/SystemUI/monet/AndroidManifest.xml b/packages/SystemUI/monet/AndroidManifest.xml
deleted file mode 100644
index 1fab528..0000000
--- a/packages/SystemUI/monet/AndroidManifest.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2021 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.systemui.monet">
-</manifest>
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
deleted file mode 100644
index 624f18d..0000000
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
+++ /dev/null
@@ -1,372 +0,0 @@
-/*
- * Copyright (C) 2021 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.monet
-
-import android.annotation.ColorInt
-import android.app.WallpaperColors
-import android.graphics.Color
-import com.android.internal.graphics.ColorUtils
-import com.google.ux.material.libmonet.hct.Hct
-import com.google.ux.material.libmonet.scheme.DynamicScheme
-import com.google.ux.material.libmonet.scheme.SchemeContent
-import com.google.ux.material.libmonet.scheme.SchemeExpressive
-import com.google.ux.material.libmonet.scheme.SchemeFruitSalad
-import com.google.ux.material.libmonet.scheme.SchemeMonochrome
-import com.google.ux.material.libmonet.scheme.SchemeNeutral
-import com.google.ux.material.libmonet.scheme.SchemeRainbow
-import com.google.ux.material.libmonet.scheme.SchemeTonalSpot
-import com.google.ux.material.libmonet.scheme.SchemeVibrant
-import kotlin.math.absoluteValue
-import kotlin.math.roundToInt
-
-const val TAG = "ColorScheme"
-
-const val ACCENT1_CHROMA = 48.0f
-const val GOOGLE_BLUE = 0xFF1b6ef3.toInt()
-const val MIN_CHROMA = 5
-
-enum class Style{
-    SPRITZ,
-    TONAL_SPOT,
-    VIBRANT,
-    EXPRESSIVE,
-    RAINBOW,
-    FRUIT_SALAD,
-    CONTENT,
-    MONOCHROMATIC,
-    CLOCK,
-    CLOCK_VIBRANT
-}
-
-class TonalPalette
-internal constructor(
-    private val materialTonalPalette: com.google.ux.material.libmonet.palettes.TonalPalette
-) {
-    @Deprecated("Do not use. For color system only")
-    val allShades: List<Int>
-    val allShadesMapped: Map<Int, Int>
-
-    init{
-        allShades = SHADE_KEYS.map {key -> getAtTone(key.toFloat()) }
-        allShadesMapped = SHADE_KEYS.zip(allShades).toMap()
-    }
-
-    // Dynamically computed tones across the full range from 0 to 1000
-    fun getAtTone(shade: Float): Int = materialTonalPalette.tone(((1000.0f - shade) / 10f).toInt())
-
-    // Predefined & precomputed tones
-    val s0: Int
-        get() = this.allShades[0]
-    val s10: Int
-        get() = this.allShades[1]
-    val s50: Int
-        get() = this.allShades[2]
-    val s100: Int
-        get() = this.allShades[3]
-    val s200: Int
-        get() = this.allShades[4]
-    val s300: Int
-        get() = this.allShades[5]
-    val s400: Int
-        get() = this.allShades[6]
-    val s500: Int
-        get() = this.allShades[7]
-    val s600: Int
-        get() = this.allShades[8]
-    val s700: Int
-        get() = this.allShades[9]
-    val s800: Int
-        get() = this.allShades[10]
-    val s900: Int
-        get() = this.allShades[11]
-    val s1000: Int
-        get() = this.allShades[12]
-
-    companion object {
-        val SHADE_KEYS = listOf(0, 10, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000)
-    }
-}
-
-@Deprecated("Please use com.google.ux.material.libmonet.dynamiccolor.MaterialDynamicColors " +
-        "instead")
-class ColorScheme(
-    @ColorInt val seed: Int,
-    val isDark: Boolean,
-    val style: Style,
-    val contrastLevel: Double
-) {
-    var materialScheme: DynamicScheme
-
-    private val proposedSeedHct: Hct = Hct.fromInt(seed)
-    private val seedHct: Hct = Hct.fromInt(if (seed == Color.TRANSPARENT) {
-        GOOGLE_BLUE
-    } else if (style != Style.CONTENT && proposedSeedHct.chroma < 5) {
-        GOOGLE_BLUE
-    } else {
-        seed
-    })
-
-    val accent1: TonalPalette
-    val accent2: TonalPalette
-    val accent3: TonalPalette
-    val neutral1: TonalPalette
-    val neutral2: TonalPalette
-
-    constructor(@ColorInt seed: Int, darkTheme: Boolean) : this(seed, darkTheme, Style.TONAL_SPOT)
-
-    @JvmOverloads
-    constructor(
-        @ColorInt seed: Int,
-        darkTheme: Boolean,
-        style: Style
-    ) : this(seed, darkTheme, style, 0.0)
-
-    @JvmOverloads
-    constructor(
-        wallpaperColors: WallpaperColors,
-        darkTheme: Boolean,
-        style: Style = Style.TONAL_SPOT
-    ) : this(getSeedColor(wallpaperColors, style != Style.CONTENT), darkTheme, style)
-
-    val backgroundColor
-        get() = ColorUtils.setAlphaComponent(if (isDark) neutral1.s700 else neutral1.s10, 0xFF)
-
-    val accentColor
-        get() = ColorUtils.setAlphaComponent(if (isDark) accent1.s100 else accent1.s500, 0xFF)
-
-    init {
-        materialScheme = when (style) {
-            Style.SPRITZ -> SchemeNeutral(seedHct, isDark, contrastLevel)
-            Style.TONAL_SPOT -> SchemeTonalSpot(seedHct, isDark, contrastLevel)
-            Style.VIBRANT -> SchemeVibrant(seedHct, isDark, contrastLevel)
-            Style.EXPRESSIVE -> SchemeExpressive(seedHct, isDark, contrastLevel)
-            Style.RAINBOW -> SchemeRainbow(seedHct, isDark, contrastLevel)
-            Style.FRUIT_SALAD -> SchemeFruitSalad(seedHct, isDark, contrastLevel)
-            Style.CONTENT -> SchemeContent(seedHct, isDark, contrastLevel)
-            Style.MONOCHROMATIC -> SchemeMonochrome(seedHct, isDark, contrastLevel)
-
-            // SystemUI Schemes
-            Style.CLOCK -> SchemeClock(seedHct, isDark, contrastLevel)
-            Style.CLOCK_VIBRANT -> SchemeClockVibrant(seedHct, isDark, contrastLevel)
-        }
-
-        accent1 = TonalPalette(materialScheme.primaryPalette)
-        accent2 = TonalPalette(materialScheme.secondaryPalette)
-        accent3 = TonalPalette(materialScheme.tertiaryPalette)
-        neutral1 = TonalPalette(materialScheme.neutralPalette)
-        neutral2 = TonalPalette(materialScheme.neutralVariantPalette)
-    }
-
-    val seedTone: Float
-        get() = 1000f - proposedSeedHct.tone.toFloat() * 10f
-
-    override fun toString(): String {
-        return "ColorScheme {\n" +
-            "  seed color: ${stringForColor(seed)}\n" +
-            "  style: $style\n" +
-            "  palettes: \n" +
-            "  ${humanReadable("PRIMARY", accent1.allShades)}\n" +
-            "  ${humanReadable("SECONDARY", accent2.allShades)}\n" +
-            "  ${humanReadable("TERTIARY", accent3.allShades)}\n" +
-            "  ${humanReadable("NEUTRAL", neutral1.allShades)}\n" +
-            "  ${humanReadable("NEUTRAL VARIANT", neutral2.allShades)}\n" +
-            "}"
-    }
-
-    companion object {
-        /**
-         * Identifies a color to create a color scheme from.
-         *
-         * @param wallpaperColors Colors extracted from an image via quantization.
-         * @param filter If false, allow colors that have low chroma, creating grayscale themes.
-         * @return ARGB int representing the color
-         */
-        @JvmStatic
-        @JvmOverloads
-        @ColorInt
-        fun getSeedColor(wallpaperColors: WallpaperColors, filter: Boolean = true): Int {
-            return getSeedColors(wallpaperColors, filter).first()
-        }
-
-        /**
-         * Filters and ranks colors from WallpaperColors.
-         *
-         * @param wallpaperColors Colors extracted from an image via quantization.
-         * @param filter If false, allow colors that have low chroma, creating grayscale themes.
-         * @return List of ARGB ints, ordered from highest scoring to lowest.
-         */
-        @JvmStatic
-        @JvmOverloads
-        fun getSeedColors(wallpaperColors: WallpaperColors, filter: Boolean = true): List<Int> {
-            val totalPopulation =
-                wallpaperColors.allColors.values.reduce { a, b -> a + b }.toDouble()
-            val totalPopulationMeaningless = (totalPopulation == 0.0)
-            if (totalPopulationMeaningless) {
-                // WallpaperColors with a population of 0 indicate the colors didn't come from
-                // quantization. Instead of scoring, trust the ordering of the provided primary
-                // secondary/tertiary colors.
-                //
-                // In this case, the colors are usually from a Live Wallpaper.
-                val distinctColors =
-                    wallpaperColors.mainColors
-                        .map { it.toArgb() }
-                        .distinct()
-                        .filter {
-                            if (!filter) {
-                                true
-                            } else {
-                                Hct.fromInt(it).chroma >= MIN_CHROMA
-                            }
-                        }
-                        .toList()
-                if (distinctColors.isEmpty()) {
-                    return listOf(GOOGLE_BLUE)
-                }
-                return distinctColors
-            }
-
-            val intToProportion =
-                wallpaperColors.allColors.mapValues { it.value.toDouble() / totalPopulation }
-            val intToHct = wallpaperColors.allColors.mapValues { Hct.fromInt(it.key) }
-
-            // Get an array with 360 slots. A slot contains the percentage of colors with that hue.
-            val hueProportions = huePopulations(intToHct, intToProportion, filter)
-            // Map each color to the percentage of the image with its hue.
-            val intToHueProportion =
-                wallpaperColors.allColors.mapValues {
-                    val hct = intToHct[it.key]!!
-                    val hue = hct.hue.roundToInt()
-                    var proportion = 0.0
-                    for (i in hue - 15..hue + 15) {
-                        proportion += hueProportions[wrapDegrees(i)]
-                    }
-                    proportion
-                }
-            // Remove any inappropriate seed colors. For example, low chroma colors look grayscale
-            // raising their chroma will turn them to a much louder color that may not have been
-            // in the image.
-            val filteredIntToHct =
-                if (!filter) intToHct
-                else
-                    (intToHct.filter {
-                        val hct = it.value
-                        val proportion = intToHueProportion[it.key]!!
-                        hct.chroma >= MIN_CHROMA &&
-                            (totalPopulationMeaningless || proportion > 0.01)
-                    })
-            // Sort the colors by score, from high to low.
-            val intToScoreIntermediate =
-                filteredIntToHct.mapValues { score(it.value, intToHueProportion[it.key]!!) }
-            val intToScore = intToScoreIntermediate.entries.toMutableList()
-            intToScore.sortByDescending { it.value }
-
-            // Go through the colors, from high score to low score.
-            // If the color is distinct in hue from colors picked so far, pick the color.
-            // Iteratively decrease the amount of hue distinctness required, thus ensuring we
-            // maximize difference between colors.
-            val minimumHueDistance = 15
-            val seeds = mutableListOf<Int>()
-            maximizeHueDistance@ for (i in 90 downTo minimumHueDistance step 1) {
-                seeds.clear()
-                for (entry in intToScore) {
-                    val int = entry.key
-                    val existingSeedNearby =
-                        seeds.find {
-                            val hueA = intToHct[int]!!.hue
-                            val hueB = intToHct[it]!!.hue
-                            hueDiff(hueA, hueB) < i
-                        } != null
-                    if (existingSeedNearby) {
-                        continue
-                    }
-                    seeds.add(int)
-                    if (seeds.size >= 4) {
-                        break@maximizeHueDistance
-                    }
-                }
-            }
-
-            if (seeds.isEmpty()) {
-                // Use gBlue 500 if there are 0 colors
-                seeds.add(GOOGLE_BLUE)
-            }
-
-            return seeds
-        }
-
-        private fun wrapDegrees(degrees: Int): Int {
-            return when {
-                degrees < 0 -> {
-                    (degrees % 360) + 360
-                }
-                degrees >= 360 -> {
-                    degrees % 360
-                }
-                else -> {
-                    degrees
-                }
-            }
-        }
-
-        private fun hueDiff(a: Double, b: Double): Double {
-            return 180f - ((a - b).absoluteValue - 180f).absoluteValue
-        }
-
-        private fun stringForColor(color: Int): String {
-            val width = 4
-            val hct = Hct.fromInt(color)
-            val h = "H${hct.hue.roundToInt().toString().padEnd(width)}"
-            val c = "C${hct.chroma.roundToInt().toString().padEnd(width)}"
-            val t = "T${hct.tone.roundToInt().toString().padEnd(width)}"
-            val hex = Integer.toHexString(color and 0xffffff).padStart(6, '0').uppercase()
-            return "$h$c$t = #$hex"
-        }
-
-        private fun humanReadable(paletteName: String, colors: List<Int>): String {
-            return "$paletteName\n" +
-                colors.map { stringForColor(it) }.joinToString(separator = "\n") { it }
-        }
-
-        private fun score(hct: Hct, proportion: Double): Double {
-            val proportionScore = 0.7 * 100.0 * proportion
-            val chromaScore =
-                if (hct.chroma < ACCENT1_CHROMA) 0.1 * (hct.chroma - ACCENT1_CHROMA)
-                else 0.3 * (hct.chroma - ACCENT1_CHROMA)
-            return chromaScore + proportionScore
-        }
-
-        private fun huePopulations(
-            hctByColor: Map<Int, Hct>,
-            populationByColor: Map<Int, Double>,
-            filter: Boolean = true
-        ): List<Double> {
-            val huePopulation = List(size = 360, init = { 0.0 }).toMutableList()
-
-            for (entry in populationByColor.entries) {
-                val population = populationByColor[entry.key]!!
-                val hct = hctByColor[entry.key]!!
-                val hue = hct.hue.roundToInt() % 360
-                if (filter && hct.chroma <= MIN_CHROMA) {
-                    continue
-                }
-                huePopulation[hue] = huePopulation[hue] + population
-            }
-
-            return huePopulation
-        }
-    }
-}
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/SchemeClock.java b/packages/SystemUI/monet/src/com/android/systemui/monet/SchemeClock.java
deleted file mode 100644
index 4747cc5..0000000
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/SchemeClock.java
+++ /dev/null
@@ -1,55 +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.monet;
-
-import static com.google.ux.material.libmonet.utils.MathUtils.clampDouble;
-
-import static java.lang.Double.max;
-
-import com.google.ux.material.libmonet.hct.Hct;
-import com.google.ux.material.libmonet.palettes.TonalPalette;
-import com.google.ux.material.libmonet.scheme.DynamicScheme;
-import com.google.ux.material.libmonet.scheme.Variant;
-
-public class SchemeClock extends DynamicScheme {
-    public SchemeClock(Hct sourceColorHct, boolean isDark, double contrastLevel) {
-        super(
-                sourceColorHct,
-                Variant.MONOCHROME,
-                isDark,
-                contrastLevel,
-                /*primary*/
-                TonalPalette.fromHueAndChroma(
-                        /*hue*/ sourceColorHct.getHue(),
-                        /*chroma*/ max(sourceColorHct.getChroma(), 20)
-                ),
-                /*secondary*/
-                TonalPalette.fromHueAndChroma(
-                        /*hue*/ sourceColorHct.getHue() + 10.0,
-                        /*chroma*/ clampDouble(17, 40, sourceColorHct.getChroma() * 0.85)
-                ),
-                /*tertiary*/
-                TonalPalette.fromHueAndChroma(
-                        /*hue*/ sourceColorHct.getHue() + 20.0,
-                        /*chroma*/ max(sourceColorHct.getChroma() + 20, 50)
-                ),
-
-                //not used
-                TonalPalette.fromHueAndChroma(sourceColorHct.getHue(), 0.0),
-                TonalPalette.fromHueAndChroma(sourceColorHct.getHue(), 0.0));
-    }
-}
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/SchemeClockVibrant.java b/packages/SystemUI/monet/src/com/android/systemui/monet/SchemeClockVibrant.java
deleted file mode 100644
index fb5e972..0000000
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/SchemeClockVibrant.java
+++ /dev/null
@@ -1,53 +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.monet;
-
-import static java.lang.Double.max;
-
-import com.google.ux.material.libmonet.hct.Hct;
-import com.google.ux.material.libmonet.palettes.TonalPalette;
-import com.google.ux.material.libmonet.scheme.DynamicScheme;
-import com.google.ux.material.libmonet.scheme.Variant;
-
-public class SchemeClockVibrant extends DynamicScheme {
-    public SchemeClockVibrant(Hct sourceColorHct, boolean isDark, double contrastLevel) {
-        super(
-                sourceColorHct,
-                Variant.MONOCHROME,
-                isDark,
-                contrastLevel,
-                /*primary*/
-                TonalPalette.fromHueAndChroma(
-                        /*hue*/ sourceColorHct.getHue(),
-                        /*chroma*/ max(sourceColorHct.getChroma(), 70)
-                ),
-                /*secondary*/
-                TonalPalette.fromHueAndChroma(
-                        /*hue*/ sourceColorHct.getHue() + 20.0,
-                        /*chroma*/ max(sourceColorHct.getChroma(), 70)
-                ),
-                /*tertiary*/
-                TonalPalette.fromHueAndChroma(
-                        /*hue*/ sourceColorHct.getHue() + 60.0,
-                        /*chroma*/ max(sourceColorHct.getChroma(), 70)
-                ),
-
-                //not used
-                TonalPalette.fromHueAndChroma(sourceColorHct.getHue(), 0.0),
-                TonalPalette.fromHueAndChroma(sourceColorHct.getHue(), 0.0));
-    }
-}
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/Shades.java b/packages/SystemUI/monet/src/com/android/systemui/monet/Shades.java
deleted file mode 100644
index c8b9fe0..0000000
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/Shades.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2021 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.monet;
-
-
-import androidx.annotation.ColorInt;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.graphics.ColorUtils;
-
-/**
- * Generate sets of colors that are shades of the same color
- */
-@VisibleForTesting
-public class Shades {
-    /**
-     *  Combining the ability to convert between relative luminance and perceptual luminance with
-     *  contrast leads to a design system that can be based on a linear value to determine contrast,
-     *  rather than a ratio.
-     *
-     *  This codebase implements a design system that has that property, and as a result, we can
-     *  guarantee that any shades 5 steps from each other have a contrast ratio of at least 4.5.
-     *  4.5 is the requirement for smaller text contrast in WCAG 2.1 and earlier.
-     *
-     *  However, lstar 50 does _not_ have a contrast ratio >= 4.5 with lstar 100.
-     *  lstar 49.6 is the smallest lstar that will lead to a contrast ratio >= 4.5 with lstar 100,
-     *  and it also contrasts >= 4.5 with lstar 100.
-     */
-    public static final float MIDDLE_LSTAR = 49.6f;
-
-    /**
-     * Generate shades of a color. Ordered in lightness _descending_.
-     * <p>
-     * The first shade will be at 95% lightness, the next at 90, 80, etc. through 0.
-     *
-     * @param hue    hue in CAM16 color space
-     * @param chroma chroma in CAM16 color space
-     * @return shades of a color, as argb integers. Ordered by lightness descending.
-     */
-    public static @ColorInt int[] of(float hue, float chroma) {
-        int[] shades = new int[12];
-        // At tone 90 and above, blue and yellow hues can reach a much higher chroma.
-        // To preserve a consistent appearance across all hues, use a maximum chroma of 40.
-        shades[0] = ColorUtils.CAMToColor(hue, Math.min(40f, chroma), 99);
-        shades[1] = ColorUtils.CAMToColor(hue, Math.min(40f, chroma), 95);
-        for (int i = 2; i < 12; i++) {
-            float lStar = (i == 6) ? MIDDLE_LSTAR : 100 - 10 * (i - 1);
-            shades[i] = ColorUtils.CAMToColor(hue, chroma, lStar);
-        }
-        return shades;
-    }
-}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt
index 325a324..89c5495 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt
@@ -195,6 +195,7 @@
         }
 
     @EnableFlags(FLAG_COMMUNAL_HUB)
+    @DisableFlags(FLAG_ALLOW_ALL_WIDGETS_ON_LOCKSCREEN_BY_DEFAULT)
     @Test
     fun hubShowsKeyguardWidgetsByDefault() =
         testScope.runTest {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
index 2fa94ef..229a711 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
@@ -126,6 +126,31 @@
         }
 
     @Test
+    fun changeScene_toGoneWhenTransitionToLockedFromGone() =
+        testScope.runTest {
+            underTest = kosmos.sceneInteractor
+            val currentScene by collectLastValue(underTest.currentScene)
+            val transitionTo by collectLastValue(underTest.transitioningTo)
+            kosmos.sceneContainerRepository.setTransitionState(
+                flowOf(
+                    ObservableTransitionState.Transition(
+                        fromScene = Scenes.Gone,
+                        toScene = Scenes.Lockscreen,
+                        currentScene = flowOf(Scenes.Lockscreen),
+                        progress = flowOf(.5f),
+                        isInitiatedByUserInput = true,
+                        isUserInputOngoing = flowOf(false),
+                    )
+                )
+            )
+            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
+            assertThat(transitionTo).isEqualTo(Scenes.Lockscreen)
+
+            underTest.changeScene(Scenes.Gone, "simulate double tap power")
+            assertThat(currentScene).isEqualTo(Scenes.Gone)
+        }
+
+    @Test
     fun snapToScene_toUnknownScene_doesNothing() =
         testScope.runTest {
             val sceneKeys =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
index 677477d..ac66e66 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
@@ -49,6 +49,7 @@
 import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest
 import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
 import com.android.systemui.power.domain.interactor.powerInteractor
+import com.android.systemui.power.shared.model.WakeSleepReason
 import com.android.systemui.power.shared.model.WakefulnessState
 import com.android.systemui.scene.domain.interactor.sceneContainerStartable
 import com.android.systemui.scene.domain.interactor.sceneInteractor
@@ -383,6 +384,43 @@
         }
 
     @Test
+    fun switchToGoneWhenDoubleTapPowerGestureIsTriggeredFromGone() =
+        testScope.runTest {
+            val currentSceneKey by collectLastValue(sceneInteractor.currentScene)
+            val transitionStateFlow =
+                prepareState(
+                    authenticationMethod = AuthenticationMethodModel.Pin,
+                    isDeviceUnlocked = true,
+                    initialSceneKey = Scenes.Gone,
+                )
+            assertThat(currentSceneKey).isEqualTo(Scenes.Gone)
+            underTest.start()
+
+            kosmos.fakePowerRepository.updateWakefulness(
+                rawState = WakefulnessState.STARTING_TO_SLEEP,
+                lastSleepReason = WakeSleepReason.POWER_BUTTON,
+                powerButtonLaunchGestureTriggered = false,
+            )
+            transitionStateFlow.value =
+                ObservableTransitionState.Transition(
+                    fromScene = Scenes.Gone,
+                    toScene = Scenes.Lockscreen,
+                    currentScene = flowOf(Scenes.Lockscreen),
+                    progress = flowOf(0.5f),
+                    isInitiatedByUserInput = true,
+                    isUserInputOngoing = flowOf(false),
+                )
+            assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen)
+
+            kosmos.fakePowerRepository.updateWakefulness(
+                rawState = WakefulnessState.STARTING_TO_WAKE,
+                lastSleepReason = WakeSleepReason.POWER_BUTTON,
+                powerButtonLaunchGestureTriggered = true,
+            )
+            assertThat(currentSceneKey).isEqualTo(Scenes.Gone)
+        }
+
+    @Test
     fun hydrateSystemUiState() =
         testScope.runTest {
             val transitionStateFlow = prepareState()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioVolumeInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioVolumeInteractorTest.kt
index a163ca0..d620639 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioVolumeInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/domain/interactor/AudioVolumeInteractorTest.kt
@@ -192,10 +192,12 @@
     fun streamNotAffectedByMute_isNotMutable() {
         with(kosmos) {
             testScope.runTest {
-                audioRepository.setIsAffectedByMute(audioStream, false)
-                val isMutable = underTest.isAffectedByMute(audioStream)
+                val audioStreamModel by collectLastValue(underTest.getAudioStream(audioStream))
+                audioRepository.setAudioStreamModel(
+                    audioStreamModel!!.copy(isAffectedByMute = false)
+                )
 
-                assertThat(isMutable).isFalse()
+                assertThat(audioStreamModel!!.isAffectedByMute).isFalse()
             }
         }
     }
@@ -230,6 +232,7 @@
             testScope.runTest {
                 val audioStreamModel by
                     collectLastValue(audioRepository.getAudioStream(audioStream))
+                underTest.setVolume(audioStream, audioStreamModel!!.maxVolume)
                 runCurrent()
 
                 underTest.setVolume(audioStream, audioStreamModel!!.minVolume)
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 8813588..b8f71c1 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -1261,6 +1261,7 @@
         <item name="android:lineHeight">32sp</item>
         <item name="android:gravity">center</item>
         <item name="android:textAlignment">center</item>
+        <item name="android:hyphenationFrequency">full</item>
     </style>
 
     <style name="TextAppearance.Dialog.Body" parent="@android:style/TextAppearance.DeviceDefault.Medium">
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 3462164..93f3793 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -69,6 +69,7 @@
 import com.android.systemui.inputmethod.InputMethodModule;
 import com.android.systemui.keyboard.KeyboardModule;
 import com.android.systemui.keyevent.data.repository.KeyEventRepositoryModule;
+import com.android.systemui.keyguard.ui.composable.LockscreenContent;
 import com.android.systemui.keyguard.ui.view.layout.blueprints.KeyguardBlueprintModule;
 import com.android.systemui.keyguard.ui.view.layout.sections.KeyguardSectionsModule;
 import com.android.systemui.log.dagger.LogModule;
@@ -364,6 +365,9 @@
     @BindsOptionalOf
     abstract FingerprintReEnrollNotification optionalFingerprintReEnrollNotification();
 
+    @BindsOptionalOf
+    abstract LockscreenContent optionalLockscreenContent();
+
     @SysUISingleton
     @Binds
     abstract SystemClock bindSystemClock(SystemClockImpl systemClock);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index f9adc47..9cdba58 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -68,6 +68,7 @@
 import android.window.TransitionInfo;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.foldables.FoldGracePeriodProvider;
 import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IKeyguardDrawnCallback;
 import com.android.internal.policy.IKeyguardExitCallback;
@@ -308,6 +309,13 @@
 
     private final WindowManagerOcclusionManager mWmOcclusionManager;
 
+    private final Lazy<FoldGracePeriodProvider> mFoldGracePeriodProvider = new Lazy<>() {
+        @Override
+        public FoldGracePeriodProvider get() {
+            return new FoldGracePeriodProvider();
+        }
+    };
+
     @Inject
     public KeyguardService(
             KeyguardViewMediator keyguardViewMediator,
@@ -609,7 +617,8 @@
             trace("showDismissibleKeyguard");
             checkPermission();
             mKeyguardViewMediator.showDismissibleKeyguard();
-            if (SceneContainerFlag.isEnabled()) {
+
+            if (SceneContainerFlag.isEnabled() && mFoldGracePeriodProvider.get().isEnabled()) {
                 mSceneInteractorLazy.get().changeScene(
                         Scenes.Lockscreen, "KeyguardService.showDismissibleKeyguard");
             }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
index bda5be4..fb1853f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
@@ -631,7 +631,7 @@
             // color will need to use wallpaper's extracted color and consider if the
             // wallpaper's color is dark or light.
             val style = themeStyle ?: fetchThemeStyleFromSetting().also { themeStyle = it }
-            val wallpaperColorScheme = ColorScheme(colors, darkTheme = false, style)
+            val wallpaperColorScheme = ColorScheme(colors, false, style)
             val lightClockColor = wallpaperColorScheme.accent1.s100
             val darkClockColor = wallpaperColorScheme.accent2.s600
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt
index c98f3b0..b33eaa2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModel.kt
@@ -18,7 +18,6 @@
 
 import android.content.res.Resources
 import com.android.internal.annotations.VisibleForTesting
-import com.android.keyguard.KeyguardClockSwitch.SMALL
 import com.android.systemui.biometrics.AuthController
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
@@ -48,7 +47,7 @@
     val longPress: KeyguardLongPressViewModel,
     val shadeInteractor: ShadeInteractor,
     @Application private val applicationScope: CoroutineScope,
-    private val unfoldTransitionInteractor: UnfoldTransitionInteractor,
+    unfoldTransitionInteractor: UnfoldTransitionInteractor,
 ) {
     @VisibleForTesting val clockSize = clockInteractor.clockSize
 
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaArtworkHelper.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaArtworkHelper.kt
index 3b09f41..c97221e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaArtworkHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaArtworkHelper.kt
@@ -107,7 +107,7 @@
         return try {
             // Set up media source app's logo.
             val icon = applicationContext.packageManager.getApplicationIcon(packageName)
-            ColorScheme(WallpaperColors.fromDrawable(icon), darkTheme = true, style)
+            ColorScheme(WallpaperColors.fromDrawable(icon), true, style)
         } catch (e: PackageManager.NameNotFoundException) {
             Log.w(tag, "Fail to get media app info", e)
             null
diff --git a/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt b/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt
index a144dc2..c8e896d 100644
--- a/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt
+++ b/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt
@@ -84,7 +84,9 @@
                 SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE to { it.scene != Scenes.Gone },
                 SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED to
                     {
-                        it.scene == Scenes.NotificationsShade || it.scene == Scenes.Shade
+                        it.scene == Scenes.Lockscreen ||
+                            it.scene == Scenes.NotificationsShade ||
+                            it.scene == Scenes.Shade
                     },
                 SYSUI_STATE_QUICK_SETTINGS_EXPANDED to
                     {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt
index 2cc3985..d161c6b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt
@@ -29,14 +29,17 @@
 import com.android.systemui.qs.panels.shared.model.GridConsistencyLog
 import com.android.systemui.qs.panels.shared.model.GridLayoutType
 import com.android.systemui.qs.panels.shared.model.InfiniteGridLayoutType
+import com.android.systemui.qs.panels.shared.model.PartitionedGridLayoutType
 import com.android.systemui.qs.panels.shared.model.StretchedGridLayoutType
 import com.android.systemui.qs.panels.ui.compose.GridLayout
 import com.android.systemui.qs.panels.ui.compose.InfiniteGridLayout
+import com.android.systemui.qs.panels.ui.compose.PartitionedGridLayout
 import com.android.systemui.qs.panels.ui.compose.StretchedGridLayout
 import dagger.Binds
 import dagger.Module
 import dagger.Provides
 import dagger.multibindings.IntoSet
+import javax.inject.Named
 
 @Module
 interface PanelsModule {
@@ -50,6 +53,8 @@
         impl: NoopGridConsistencyInteractor
     ): GridTypeConsistencyInteractor
 
+    @Binds @Named("Default") fun bindDefaultGridLayout(impl: PartitionedGridLayout): GridLayout
+
     companion object {
         @Provides
         @SysUISingleton
@@ -73,6 +78,14 @@
         }
 
         @Provides
+        @IntoSet
+        fun providePartitionedGridLayout(
+            gridLayout: PartitionedGridLayout
+        ): Pair<GridLayoutType, GridLayout> {
+            return Pair(PartitionedGridLayoutType, gridLayout)
+        }
+
+        @Provides
         fun provideGridLayoutMap(
             entries: Set<@JvmSuppressWildcards Pair<GridLayoutType, GridLayout>>
         ): Map<GridLayoutType, GridLayout> {
@@ -103,6 +116,14 @@
         }
 
         @Provides
+        @IntoSet
+        fun providePartitionedGridConsistencyInteractor(
+            consistencyInteractor: NoopGridConsistencyInteractor
+        ): Pair<GridLayoutType, GridTypeConsistencyInteractor> {
+            return Pair(PartitionedGridLayoutType, consistencyInteractor)
+        }
+
+        @Provides
         fun provideGridConsistencyInteractorMap(
             entries: Set<@JvmSuppressWildcards Pair<GridLayoutType, GridTypeConsistencyInteractor>>
         ): Map<GridLayoutType, GridTypeConsistencyInteractor> {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/GridLayoutTypeRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/GridLayoutTypeRepository.kt
index 31795d5..44d8688 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/GridLayoutTypeRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/GridLayoutTypeRepository.kt
@@ -18,7 +18,7 @@
 
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.qs.panels.shared.model.GridLayoutType
-import com.android.systemui.qs.panels.shared.model.InfiniteGridLayoutType
+import com.android.systemui.qs.panels.shared.model.PartitionedGridLayoutType
 import javax.inject.Inject
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
@@ -31,7 +31,8 @@
 
 @SysUISingleton
 class GridLayoutTypeRepositoryImpl @Inject constructor() : GridLayoutTypeRepository {
-    private val _layout: MutableStateFlow<GridLayoutType> = MutableStateFlow(InfiniteGridLayoutType)
+    private val _layout: MutableStateFlow<GridLayoutType> =
+        MutableStateFlow(PartitionedGridLayoutType)
     override val layout = _layout.asStateFlow()
 
     override fun setLayout(type: GridLayoutType) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/shared/model/GridLayoutType.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/shared/model/GridLayoutType.kt
index 501730a..9550ddb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/shared/model/GridLayoutType.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/shared/model/GridLayoutType.kt
@@ -31,3 +31,6 @@
  * spaces.
  */
 data object StretchedGridLayoutType : GridLayoutType
+
+/** Grid type grouping large tiles on top and icon tiles at the bottom. */
+data object PartitionedGridLayoutType : GridLayoutType
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PartitionedGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PartitionedGridLayout.kt
new file mode 100644
index 0000000..8d0b386
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PartitionedGridLayout.kt
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.panels.ui.compose
+
+import androidx.compose.foundation.border
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+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.rememberScrollState
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.DisposableEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberUpdatedState
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.dimensionResource
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.android.compose.modifiers.background
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.qs.panels.domain.interactor.IconTilesInteractor
+import com.android.systemui.qs.panels.domain.interactor.InfiniteGridSizeInteractor
+import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel
+import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel
+import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.res.R
+import javax.inject.Inject
+
+@SysUISingleton
+class PartitionedGridLayout
+@Inject
+constructor(
+    private val iconTilesInteractor: IconTilesInteractor,
+    private val gridSizeInteractor: InfiniteGridSizeInteractor,
+) : GridLayout {
+    @Composable
+    override fun TileGrid(tiles: List<TileViewModel>, modifier: Modifier) {
+        DisposableEffect(tiles) {
+            val token = Any()
+            tiles.forEach { it.startListening(token) }
+            onDispose { tiles.forEach { it.stopListening(token) } }
+        }
+        val iconTilesSpecs by iconTilesInteractor.iconTilesSpecs.collectAsStateWithLifecycle()
+        val columns by gridSizeInteractor.columns.collectAsStateWithLifecycle()
+        val tileHeight = dimensionResource(id = R.dimen.qs_tile_height)
+        val (smallTiles, largeTiles) = tiles.partition { iconTilesSpecs.contains(it.spec) }
+
+        TileLazyGrid(modifier = modifier, columns = GridCells.Fixed(columns)) {
+            // Large tiles
+            items(largeTiles.size, span = { GridItemSpan(2) }) { index ->
+                Tile(
+                    tile = largeTiles[index],
+                    iconOnly = false,
+                    modifier = Modifier.height(tileHeight)
+                )
+            }
+            fillUpRow(nTiles = largeTiles.size, columns = columns / 2)
+
+            // Small tiles
+            items(smallTiles.size) { index ->
+                Tile(
+                    tile = smallTiles[index],
+                    iconOnly = true,
+                    modifier = Modifier.height(tileHeight)
+                )
+            }
+        }
+    }
+
+    @Composable
+    override fun EditTileGrid(
+        tiles: List<EditTileViewModel>,
+        modifier: Modifier,
+        onAddTile: (TileSpec, Int) -> Unit,
+        onRemoveTile: (TileSpec) -> Unit
+    ) {
+        val iconOnlySpecs by iconTilesInteractor.iconTilesSpecs.collectAsStateWithLifecycle()
+        val columns by gridSizeInteractor.columns.collectAsStateWithLifecycle()
+
+        val (currentTiles, otherTiles) = tiles.partition { it.isCurrent }
+        val addTileToEnd: (TileSpec) -> Unit by rememberUpdatedState {
+            onAddTile(it, CurrentTilesInteractor.POSITION_AT_END)
+        }
+        val isIconOnly: (TileSpec) -> Boolean =
+            remember(iconOnlySpecs) { { tileSpec: TileSpec -> tileSpec in iconOnlySpecs } }
+        val tileHeight = dimensionResource(id = R.dimen.qs_tile_height)
+        val tilePadding = dimensionResource(R.dimen.qs_tile_margin_vertical)
+
+        Column(
+            verticalArrangement = Arrangement.spacedBy(tilePadding),
+            modifier = modifier.fillMaxSize().verticalScroll(rememberScrollState())
+        ) {
+            CurrentTiles(
+                tiles = currentTiles,
+                tileHeight = tileHeight,
+                tilePadding = tilePadding,
+                onRemoveTile = onRemoveTile,
+                isIconOnly = isIconOnly,
+                columns = columns,
+            )
+            AvailableTiles(
+                tiles = otherTiles,
+                tileHeight = tileHeight,
+                tilePadding = tilePadding,
+                addTileToEnd = addTileToEnd,
+                isIconOnly = isIconOnly,
+                columns = columns,
+            )
+        }
+    }
+
+    @Composable
+    private fun CurrentTiles(
+        tiles: List<EditTileViewModel>,
+        tileHeight: Dp,
+        tilePadding: Dp,
+        onRemoveTile: (TileSpec) -> Unit,
+        isIconOnly: (TileSpec) -> Boolean,
+        columns: Int,
+    ) {
+        val (smallTiles, largeTiles) = tiles.partition { isIconOnly(it.tileSpec) }
+
+        val largeGridHeight = gridHeight(largeTiles.size, tileHeight, columns / 2, tilePadding)
+        val smallGridHeight = gridHeight(smallTiles.size, tileHeight, columns, tilePadding)
+
+        CurrentTilesContainer {
+            TileLazyGrid(
+                columns = GridCells.Fixed(columns),
+                modifier = Modifier.height(largeGridHeight),
+            ) {
+                editTiles(largeTiles, ClickAction.REMOVE, onRemoveTile, { false }, true)
+            }
+        }
+        CurrentTilesContainer {
+            TileLazyGrid(
+                columns = GridCells.Fixed(columns),
+                modifier = Modifier.height(smallGridHeight),
+            ) {
+                editTiles(smallTiles, ClickAction.REMOVE, onRemoveTile, { true }, true)
+            }
+        }
+    }
+
+    @Composable
+    private fun AvailableTiles(
+        tiles: List<EditTileViewModel>,
+        tileHeight: Dp,
+        tilePadding: Dp,
+        addTileToEnd: (TileSpec) -> Unit,
+        isIconOnly: (TileSpec) -> Boolean,
+        columns: Int,
+    ) {
+        val (tilesStock, tilesCustom) = tiles.partition { it.appName == null }
+        val (smallTiles, largeTiles) = tilesStock.partition { isIconOnly(it.tileSpec) }
+
+        val largeGridHeight = gridHeight(largeTiles.size, tileHeight, columns / 2, tilePadding)
+        val smallGridHeight = gridHeight(smallTiles.size, tileHeight, columns, tilePadding)
+        val largeGridHeightCustom =
+            gridHeight(tilesCustom.size, tileHeight, columns / 2, tilePadding)
+
+        // Add up the height of all three grids and add padding in between
+        val gridHeight =
+            largeGridHeight + smallGridHeight + largeGridHeightCustom + (tilePadding * 2)
+
+        AvailableTilesContainer {
+            TileLazyGrid(
+                columns = GridCells.Fixed(columns),
+                modifier = Modifier.height(gridHeight),
+            ) {
+                // Large tiles
+                editTiles(largeTiles, ClickAction.ADD, addTileToEnd, isIconOnly)
+                fillUpRow(nTiles = largeTiles.size, columns = columns / 2)
+
+                // Small tiles
+                editTiles(smallTiles, ClickAction.ADD, addTileToEnd, isIconOnly)
+                fillUpRow(nTiles = smallTiles.size, columns = columns)
+
+                // Custom tiles, all large
+                editTiles(tilesCustom, ClickAction.ADD, addTileToEnd, isIconOnly)
+            }
+        }
+    }
+
+    @Composable
+    private fun CurrentTilesContainer(content: @Composable () -> Unit) {
+        Box(
+            Modifier.fillMaxWidth()
+                .border(
+                    width = 1.dp,
+                    color = MaterialTheme.colorScheme.onBackground,
+                    shape = RoundedCornerShape(dimensionResource(R.dimen.qs_corner_radius))
+                )
+                .padding(dimensionResource(R.dimen.qs_tile_margin_vertical))
+        ) {
+            content()
+        }
+    }
+
+    @Composable
+    private fun AvailableTilesContainer(content: @Composable () -> Unit) {
+        Box(
+            Modifier.fillMaxWidth()
+                .background(
+                    color = MaterialTheme.colorScheme.surfaceVariant,
+                    alpha = { 1f },
+                    shape = RoundedCornerShape(dimensionResource(R.dimen.qs_corner_radius))
+                )
+                .padding(dimensionResource(R.dimen.qs_tile_margin_vertical))
+        ) {
+            content()
+        }
+    }
+
+    private fun gridHeight(nTiles: Int, tileHeight: Dp, columns: Int, padding: Dp): Dp {
+        val rows = (nTiles + columns - 1) / columns
+        return ((tileHeight + padding) * rows) - padding
+    }
+
+    /** Fill up the rest of the row if it's not complete. */
+    private fun LazyGridScope.fillUpRow(nTiles: Int, columns: Int) {
+        if (nTiles % columns != 0) {
+            item(span = { GridItemSpan(maxCurrentLineSpan) }) { Spacer(Modifier) }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt
index eb45110..e8c65a5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/Tile.kt
@@ -208,7 +208,7 @@
     }
 }
 
-private fun LazyGridScope.editTiles(
+fun LazyGridScope.editTiles(
     tiles: List<EditTileViewModel>,
     clickAction: ClickAction,
     onClick: (TileSpec) -> Unit,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModel.kt
index 69f50a7..5b4186c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModel.kt
@@ -22,12 +22,12 @@
 import com.android.systemui.qs.panels.domain.interactor.GridLayoutTypeInteractor
 import com.android.systemui.qs.panels.shared.model.GridLayoutType
 import com.android.systemui.qs.panels.ui.compose.GridLayout
-import com.android.systemui.qs.panels.ui.compose.InfiniteGridLayout
 import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor
 import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor.Companion.POSITION_AT_END
 import com.android.systemui.qs.pipeline.domain.interactor.MinimumTilesInteractor
 import com.android.systemui.qs.pipeline.shared.TileSpec
 import javax.inject.Inject
+import javax.inject.Named
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.MutableStateFlow
@@ -47,7 +47,7 @@
     private val editTilesListInteractor: EditTilesListInteractor,
     private val currentTilesInteractor: CurrentTilesInteractor,
     private val minTilesInteractor: MinimumTilesInteractor,
-    private val defaultGridLayout: InfiniteGridLayout,
+    @Named("Default") private val defaultGridLayout: GridLayout,
     @Application private val applicationScope: CoroutineScope,
     gridLayoutTypeInteractor: GridLayoutTypeInteractor,
     gridLayoutMap: Map<GridLayoutType, @JvmSuppressWildcards GridLayout>,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileGridViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileGridViewModel.kt
index 5eee691..127ecb2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileGridViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/TileGridViewModel.kt
@@ -21,9 +21,9 @@
 import com.android.systemui.qs.panels.domain.interactor.GridLayoutTypeInteractor
 import com.android.systemui.qs.panels.shared.model.GridLayoutType
 import com.android.systemui.qs.panels.ui.compose.GridLayout
-import com.android.systemui.qs.panels.ui.compose.InfiniteGridLayout
 import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor
 import javax.inject.Inject
+import javax.inject.Named
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
@@ -41,7 +41,7 @@
     gridLayoutTypeInteractor: GridLayoutTypeInteractor,
     gridLayoutMap: Map<GridLayoutType, @JvmSuppressWildcards GridLayout>,
     tilesInteractor: CurrentTilesInteractor,
-    defaultGridLayout: InfiniteGridLayout,
+    @Named("Default") defaultGridLayout: GridLayout,
     @Application private val applicationScope: CoroutineScope
 ) {
     val gridLayout: StateFlow<GridLayout> =
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
index 0d0f6e0..b1700e3 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
@@ -315,9 +315,17 @@
             return false
         }
 
-        check(to != Scenes.Gone || deviceUnlockedInteractor.deviceUnlockStatus.value.isUnlocked) {
-            "Cannot change to the Gone scene while the device is locked. Logging reason for scene" +
-                " change was: $loggingReason"
+        val inMidTransitionFromGone =
+            (transitionState.value as? ObservableTransitionState.Transition)?.fromScene ==
+                Scenes.Gone
+        val isChangeAllowed =
+            to != Scenes.Gone ||
+                inMidTransitionFromGone ||
+                deviceUnlockedInteractor.deviceUnlockStatus.value.isUnlocked
+        check(isChangeAllowed) {
+            "Cannot change to the Gone scene while the device is locked and not currently" +
+                " transitioning from Gone. Current transition state is ${transitionState.value}." +
+                " Logging reason for scene change was: $loggingReason"
         }
 
         return from != to
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
index 3ce12dd..0304e73 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
@@ -45,6 +45,7 @@
 import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.plugins.FalsingManager.FalsingBeliefListener
 import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.power.shared.model.WakeSleepReason
 import com.android.systemui.scene.data.model.asIterable
 import com.android.systemui.scene.domain.interactor.SceneBackInteractor
 import com.android.systemui.scene.domain.interactor.SceneContainerOcclusionInteractor
@@ -365,6 +366,29 @@
 
     private fun handlePowerState() {
         applicationScope.launch {
+            powerInteractor.detailedWakefulness.collect { wakefulness ->
+                // Detect a double-tap-power-button gesture that was started while the device was
+                // still awake.
+                if (wakefulness.isAsleep()) return@collect
+                if (!wakefulness.powerButtonLaunchGestureTriggered) return@collect
+                if (wakefulness.lastSleepReason != WakeSleepReason.POWER_BUTTON) return@collect
+
+                // If we're mid-transition from Gone to Lockscreen due to the first power button
+                // press, then return to Gone.
+                val transition: ObservableTransitionState.Transition =
+                    sceneInteractor.transitionState.value as? ObservableTransitionState.Transition
+                        ?: return@collect
+                if (
+                    transition.fromScene == Scenes.Gone && transition.toScene == Scenes.Lockscreen
+                ) {
+                    switchToScene(
+                        targetSceneKey = Scenes.Gone,
+                        loggingReason = "double-tap power gesture",
+                    )
+                }
+            }
+        }
+        applicationScope.launch {
             powerInteractor.isAsleep.collect { isAsleep ->
                 if (isAsleep) {
                     switchToScene(
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
new file mode 100644
index 0000000..e85df0e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/domain/interactor/CallChipInteractor.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.chips.call.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.chips.domain.interactor.OngoingActivityChipInteractor
+import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
+import javax.inject.Inject
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+
+/** Interactor for the ongoing phone call chip shown in the status bar. */
+@SysUISingleton
+open class CallChipInteractor @Inject constructor() : OngoingActivityChipInteractor {
+    // TODO(b/332662551): Implement this flow.
+    override val chip: StateFlow<OngoingActivityChipModel> =
+        MutableStateFlow(OngoingActivityChipModel.Hidden)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/domain/interactor/OngoingActivityChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/domain/interactor/OngoingActivityChipInteractor.kt
new file mode 100644
index 0000000..70362c8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/domain/interactor/OngoingActivityChipInteractor.kt
@@ -0,0 +1,26 @@
+/*
+ * 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.chips.domain.interactor
+
+import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
+import kotlinx.coroutines.flow.StateFlow
+
+/** Interface for an interactor that knows the state of a single type of ongoing activity chip. */
+interface OngoingActivityChipInteractor {
+    /** A flow modeling the chip that should be shown. */
+    val chip: StateFlow<OngoingActivityChipModel>
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt
new file mode 100644
index 0000000..6f16969
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.chips.screenrecord.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
+import com.android.systemui.statusbar.chips.domain.interactor.OngoingActivityChipInteractor
+import javax.inject.Inject
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+
+/** Interactor for the screen recording chip shown in the status bar. */
+@SysUISingleton
+open class ScreenRecordChipInteractor @Inject constructor() : OngoingActivityChipInteractor {
+    // TODO(b/332662551): Implement this flow.
+    override val chip: StateFlow<OngoingActivityChipModel> =
+        MutableStateFlow(OngoingActivityChipModel.Hidden)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt
new file mode 100644
index 0000000..e63713b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt
@@ -0,0 +1,44 @@
+/*
+ * 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.chips.ui.model
+
+import android.view.View
+import com.android.systemui.common.shared.model.Icon
+
+/** Model representing the display of an ongoing activity as a chip in the status bar. */
+sealed class OngoingActivityChipModel {
+    /** This chip shouldn't be shown. */
+    data object Hidden : OngoingActivityChipModel()
+
+    /** This chip should be shown with the given information. */
+    data class Shown(
+        /** The icon to show on the chip. */
+        val icon: Icon,
+        /**
+         * The time this event started, used to show the timer.
+         *
+         * This time should be relative to
+         * [com.android.systemui.util.time.SystemClock.elapsedRealtime], *not*
+         * [com.android.systemui.util.time.SystemClock.currentTimeMillis] because the
+         * [ChipChronometer] is based off of elapsed realtime. See
+         * [android.widget.Chronometer.setBase].
+         */
+        val startTimeMs: Long,
+        /** Listener method to invoke when this chip is clicked. */
+        val onClickListener: View.OnClickListener,
+    ) : OngoingActivityChipModel()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
new file mode 100644
index 0000000..47b2b03
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
@@ -0,0 +1,62 @@
+/*
+ * 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.chips.ui.viewmodel
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.statusbar.chips.call.domain.interactor.CallChipInteractor
+import com.android.systemui.statusbar.chips.screenrecord.domain.interactor.ScreenRecordChipInteractor
+import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.stateIn
+
+/**
+ * View model deciding which ongoing activity chip to show in the status bar.
+ *
+ * There may be multiple ongoing activities at the same time, but we can only ever show one chip at
+ * any one time (for now). This class decides which ongoing activity to show if there are multiple.
+ */
+@SysUISingleton
+class OngoingActivityChipsViewModel
+@Inject
+constructor(
+    @Application scope: CoroutineScope,
+    screenRecordChipInteractor: ScreenRecordChipInteractor,
+    callChipInteractor: CallChipInteractor,
+) {
+
+    /**
+     * A flow modeling the chip that should be shown in the status bar after accounting for possibly
+     * multiple ongoing activities.
+     *
+     * [com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment] is responsible for
+     * actually displaying the chip.
+     */
+    val chip: StateFlow<OngoingActivityChipModel> =
+        combine(screenRecordChipInteractor.chip, callChipInteractor.chip) { screenRecord, call ->
+                // This `when` statement shows the priority order of the chips
+                when {
+                    screenRecord is OngoingActivityChipModel.Shown -> screenRecord
+                    else -> call
+                }
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), OngoingActivityChipModel.Hidden)
+}
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 e5c86c8..97f9e06 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
@@ -51,6 +51,7 @@
 import com.android.systemui.statusbar.OperatorNameView;
 import com.android.systemui.statusbar.OperatorNameViewController;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModel;
 import com.android.systemui.statusbar.disableflags.DisableFlagsLogger.DisableState;
 import com.android.systemui.statusbar.events.SystemStatusAnimationCallback;
 import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
@@ -134,6 +135,8 @@
     private final CollapsedStatusBarFragmentLogger mCollapsedStatusBarFragmentLogger;
     private final OperatorNameViewController.Factory mOperatorNameViewControllerFactory;
     private final OngoingCallController mOngoingCallController;
+    // TODO(b/332662551): Use this view model to show the ongoing activity chips.
+    private final OngoingActivityChipsViewModel mOngoingActivityChipsViewModel;
     private final SystemStatusAnimationScheduler mAnimationScheduler;
     private final StatusBarLocationPublisher mLocationPublisher;
     private final NotificationIconAreaController mNotificationIconAreaController;
@@ -217,6 +220,7 @@
     public CollapsedStatusBarFragment(
             StatusBarFragmentComponent.Factory statusBarFragmentComponentFactory,
             OngoingCallController ongoingCallController,
+            OngoingActivityChipsViewModel ongoingActivityChipsViewModel,
             SystemStatusAnimationScheduler animationScheduler,
             StatusBarLocationPublisher locationPublisher,
             NotificationIconAreaController notificationIconAreaController,
@@ -242,6 +246,7 @@
             DemoModeController demoModeController) {
         mStatusBarFragmentComponentFactory = statusBarFragmentComponentFactory;
         mOngoingCallController = ongoingCallController;
+        mOngoingActivityChipsViewModel = ongoingActivityChipsViewModel;
         mAnimationScheduler = animationScheduler;
         mLocationPublisher = locationPublisher;
         mNotificationIconAreaController = notificationIconAreaController;
diff --git a/packages/SystemUI/src/com/android/systemui/theme/CustomDynamicColors.java b/packages/SystemUI/src/com/android/systemui/theme/CustomDynamicColors.java
deleted file mode 100644
index efeb2f9..0000000
--- a/packages/SystemUI/src/com/android/systemui/theme/CustomDynamicColors.java
+++ /dev/null
@@ -1,322 +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.theme;
-
-import com.google.ux.material.libmonet.dynamiccolor.ContrastCurve;
-import com.google.ux.material.libmonet.dynamiccolor.DynamicColor;
-import com.google.ux.material.libmonet.dynamiccolor.MaterialDynamicColors;
-import com.google.ux.material.libmonet.dynamiccolor.ToneDeltaPair;
-import com.google.ux.material.libmonet.dynamiccolor.TonePolarity;
-
-class CustomDynamicColors {
-    private final MaterialDynamicColors mMdc;
-
-    CustomDynamicColors(boolean isExtendedFidelity) {
-        this.mMdc = new MaterialDynamicColors(isExtendedFidelity);
-    }
-
-    // CLOCK COLORS
-
-    public DynamicColor widgetBackground() {
-        return new DynamicColor(
-                /* name= */ "widget_background",
-                /* palette= */ (s) -> s.primaryPalette,
-                /* tone= */ (s) -> s.isDark ? 20.0 : 95.0,
-                /* isBackground= */ true,
-                /* background= */ null,
-                /* secondBackground= */ null,
-                /* contrastCurve= */ null,
-                /* toneDeltaPair= */ null);
-    }
-
-    public DynamicColor clockHour() {
-        return new DynamicColor(
-                /* name= */ "clock_hour",
-                /* palette= */ (s) -> s.secondaryPalette,
-                /* tone= */ (s) -> s.isDark ? 30.0 : 60.0,
-                /* isBackground= */ false,
-                /* background= */ (s) -> widgetBackground(),
-                /* secondBackground= */ null,
-                /* contrastCurve= */ new ContrastCurve(1.0, 4.0, 5.0, 15.0),
-                /* toneDeltaPair= */
-                (s) -> new ToneDeltaPair(clockHour(), clockMinute(), 10.0, TonePolarity.DARKER,
-                        false));
-    }
-
-    public DynamicColor clockMinute() {
-        return new DynamicColor(
-                /* name= */ "clock_minute",
-                /* palette= */ (s) -> s.primaryPalette,
-                /* tone= */ (s) -> s.isDark ? 40.0 : 90.0,
-                /* isBackground= */ false,
-                /* background= */ (s) -> widgetBackground(),
-                /* secondBackground= */ null,
-                /* contrastCurve= */ new ContrastCurve(1.0, 6.5, 10.0, 15.0),
-                /* toneDeltaPair= */ null);
-    }
-
-    public DynamicColor clockSecond() {
-        return new DynamicColor(
-                /* name= */ "clock_second",
-                /* palette= */ (s) -> s.tertiaryPalette,
-                /* tone= */ (s) -> s.isDark ? 40.0 : 90.0,
-                /* isBackground= */ false,
-                /* background= */ (s) -> widgetBackground(),
-                /* secondBackground= */ null,
-                /* contrastCurve= */ new ContrastCurve(1.0, 5.0, 70.0, 11.0),
-                /* toneDeltaPair= */ null);
-    }
-
-    public DynamicColor weatherTemp() {
-        return new DynamicColor(
-                /* name= */ "clock_second",
-                /* palette= */ (s) -> s.primaryPalette,
-                /* tone= */ (s) -> s.isDark ? 55.0 : 80.0,
-                /* isBackground= */ false,
-                /* background= */ (s) -> widgetBackground(),
-                /* secondBackground= */ null,
-                /* contrastCurve= */ new ContrastCurve(1.0, 5.0, 70.0, 11.0),
-                /* toneDeltaPair= */ null);
-    }
-
-    // THEME APP ICONS
-
-    public DynamicColor themeApp() {
-        return new DynamicColor(
-                /* name= */ "theme_app",
-                /* palette= */ (s) -> s.primaryPalette,
-                /* tone= */ (s) -> s.isDark ? 90.0 : 30.0, // Adjusted values
-                /* isBackground= */ true,
-                /* background= */ null,
-                /* secondBackground= */ null,
-                /* contrastCurve= */ null,
-                /* toneDeltaPair= */ null);
-    }
-
-    public DynamicColor onThemeApp() {
-        return new DynamicColor(
-                /* name= */ "on_theme_app",
-                /* palette= */ (s) -> s.primaryPalette,
-                /* tone= */ (s) -> s.isDark ? 40.0 : 80.0, // Adjusted values
-                /* isBackground= */ false,
-                /* background= */ (s) -> themeApp(),
-                /* secondBackground= */ null,
-                /* contrastCurve= */ new ContrastCurve(1.0, 3.0, 7.0, 10.0),
-                /* toneDeltaPair= */ null);
-    }
-
-    public DynamicColor themeAppRing() {
-        return new DynamicColor(
-                /* name= */ "theme_app_ring",
-                /* palette= */ (s) -> s.primaryPalette,
-                /* tone= */ (s) -> 70.0,
-                /* isBackground= */ true,
-                /* background= */ null,
-                /* secondBackground= */ null,
-                /* contrastCurve= */ new ContrastCurve(1.0, 1.0, 1.0, 1.0),
-                /* toneDeltaPair= */ null);
-    }
-
-    public DynamicColor themeNotif() {
-        return new DynamicColor(
-                /* name= */ "theme_notif",
-                /* palette= */ (s) -> s.tertiaryPalette,
-                /* tone= */ (s) -> s.isDark ? 80.0 : 90.0,
-                /* isBackground= */ false,
-                /* background= */ (s) -> themeAppRing(),
-                /* secondBackground= */ null,
-                /* contrastCurve= */ new ContrastCurve(1.0, 1.0, 1.0, 1.0),
-                /* toneDeltaPair= */
-                (s) -> new ToneDeltaPair(themeNotif(), themeAppRing(), 10.0, TonePolarity.NEARER,
-                        false));
-    }
-
-    // SUPER G COLORS
-
-    public DynamicColor brandA() {
-        return new DynamicColor(
-                /* name= */ "brand_a",
-                /* palette= */ (s) -> s.primaryPalette,
-                /* tone= */ (s) -> s.isDark ? 40.0 : 80.0,
-                /* isBackground= */ true,
-                /* background= */ (s) -> mMdc.surfaceContainerLow(),
-                /* secondBackground= */ null,
-                /* contrastCurve= */ new ContrastCurve(1.0, 3.0, 7.0, 17.0),
-                /* toneDeltaPair= */
-                (s) -> new ToneDeltaPair(brandA(), brandB(), 10.0, TonePolarity.NEARER, false));
-    }
-
-    public DynamicColor brandB() {
-        return new DynamicColor(
-                /* name= */ "brand_b",
-                /* palette= */ (s) -> s.secondaryPalette,
-                /* tone= */ (s) -> s.isDark ? 70.0 : 98.0,
-                /* isBackground= */ true,
-                /* background= */ (s) -> mMdc.surfaceContainerLow(),
-                /* secondBackground= */ null,
-                /* contrastCurve= */ new ContrastCurve(1.0, 3.0, 3.0, 6.0),
-                /* toneDeltaPair= */
-                (s) -> new ToneDeltaPair(brandB(), brandC(), 10.0, TonePolarity.NEARER, false));
-    }
-
-    public DynamicColor brandC() {
-        return new DynamicColor(
-                /* name= */ "brand_c",
-                /* palette= */ (s) -> s.primaryPalette,
-                /* tone= */ (s) -> s.isDark ? 50.0 : 60.0,
-                /* isBackground= */ false,
-                /* background= */ (s) -> mMdc.surfaceContainerLow(),
-                /* secondBackground= */ null,
-                /* contrastCurve= */ new ContrastCurve(1.0, 3.0, 4.0, 9.0),
-                /* toneDeltaPair= */
-                (s) -> new ToneDeltaPair(brandC(), brandD(), 10.0, TonePolarity.NEARER, false));
-    }
-
-    public DynamicColor brandD() {
-        return new DynamicColor(
-                /* name= */ "brand_d",
-                /* palette= */ (s) -> s.tertiaryPalette,
-                /* tone= */ (s) -> s.isDark ? 59.0 : 90.0,
-                /* isBackground= */ false,
-                /* background= */ (s) -> mMdc.surfaceContainerLow(),
-                /* secondBackground= */ null,
-                /* contrastCurve= */ new ContrastCurve(1.0, 3.0, 4.0, 13.0),
-                /* toneDeltaPair= */
-                (s) -> new ToneDeltaPair(brandD(), brandA(), 10.0, TonePolarity.NEARER, false));
-    }
-
-    // QUICK SETTING TIILES
-
-    public DynamicColor underSurface() {
-        return new DynamicColor(
-                /* name= */ "under_surface",
-                /* palette= */ (s) -> s.primaryPalette,
-                /* tone= */ (s) -> 0.0,
-                /* isBackground= */ true,
-                /* background= */ null,
-                /* secondBackground= */ null,
-                /* contrastCurve= */ null,
-                /* toneDeltaPair= */ null);
-    }
-
-    public DynamicColor shadeActive() {
-        return new DynamicColor(
-                /* name= */ "shade_active",
-                /* palette= */ (s) -> s.primaryPalette,
-                /* tone= */ (s) -> 90.0,
-                /* isBackground= */ false,
-                /* background= */ (s) -> underSurface(),
-                /* secondBackground= */ null,
-                /* contrastCurve= */ new ContrastCurve(1.0, 3.0, 4.5, 7.0),
-                /* toneDeltaPair= */
-                (s) -> new ToneDeltaPair(shadeActive(), shadeInactive(), 30.0, TonePolarity.LIGHTER,
-                        false));
-    }
-
-    public DynamicColor onShadeActive() {
-        return new DynamicColor(
-                /* name= */ "on_shade_active",
-                /* palette= */ (s) -> s.primaryPalette,
-                /* tone= */ (s) -> 10.0,
-                /* isBackground= */ false,
-                /* background= */ (s) -> shadeActive(),
-                /* secondBackground= */ null,
-                /* contrastCurve= */ new ContrastCurve(1.0, 4.5, 7.0, 11.0),
-                /* toneDeltaPair= */
-                (s) -> new ToneDeltaPair(onShadeActive(), onShadeActiveVariant(), 20.0,
-                        TonePolarity.NEARER, false));
-    }
-
-    public DynamicColor onShadeActiveVariant() {
-        return new DynamicColor(
-                /* name= */ "on_shade_active_variant",
-                /* palette= */ (s) -> s.primaryPalette,
-                /* tone= */ (s) -> 30.0,
-                /* isBackground= */ false,
-                /* background= */ (s) -> shadeActive(),
-                /* secondBackground= */ null,
-                /* contrastCurve= */ new ContrastCurve(1.0, 4.5, 7.0, 11.0),
-                /* toneDeltaPair= */
-                (s) -> new ToneDeltaPair(onShadeActiveVariant(), onShadeActive(), 20.0,
-                        TonePolarity.NEARER, false));
-    }
-
-    public DynamicColor shadeInactive() {
-        return new DynamicColor(
-                /* name= */ "shade_inactive",
-                /* palette= */ (s) -> s.neutralPalette,
-                /* tone= */ (s) -> 20.0,
-                /* isBackground= */ true,
-                /* background= */ (s) -> underSurface(),
-                /* secondBackground= */ null,
-                /* contrastCurve= */ new ContrastCurve(1.0, 1.0, 1.0, 1.0),
-                /* toneDeltaPair= */(s) -> new ToneDeltaPair(shadeInactive(), shadeDisabled(), 15.0,
-                TonePolarity.LIGHTER, false));
-    }
-
-    public DynamicColor onShadeInactive() {
-        return new DynamicColor(
-                /* name= */ "on_shade_inactive",
-                /* palette= */ (s) -> s.neutralVariantPalette,
-                /* tone= */ (s) -> 90.0,
-                /* isBackground= */ true,
-                /* background= */ (s) -> shadeInactive(),
-                /* secondBackground= */ null,
-                /* contrastCurve= */ new ContrastCurve(1.0, 4.5, 7.0, 11.0),
-                /* toneDeltaPair= */
-                (s) -> new ToneDeltaPair(onShadeInactive(), onShadeInactiveVariant(), 10.0,
-                        TonePolarity.NEARER, false));
-    }
-
-    public DynamicColor onShadeInactiveVariant() {
-        return new DynamicColor(
-                /* name= */ "on_shade_inactive_variant",
-                /* palette= */ (s) -> s.neutralVariantPalette,
-                /* tone= */ (s) -> 80.0,
-                /* isBackground= */ false,
-                /* background= */ (s) -> shadeInactive(),
-                /* secondBackground= */ null,
-                /* contrastCurve= */ new ContrastCurve(1.0, 4.5, 7.0, 11.0),
-                /* toneDeltaPair= */
-                (s) -> new ToneDeltaPair(onShadeInactiveVariant(), onShadeInactive(), 10.0,
-                        TonePolarity.NEARER, false));
-    }
-
-    public DynamicColor shadeDisabled() {
-        return new DynamicColor(
-                /* name= */ "shade_disabled",
-                /* palette= */ (s) -> s.neutralPalette,
-                /* tone= */ (s) -> 4.0,
-                /* isBackground= */ false,
-                /* background= */ (s) -> underSurface(),
-                /* secondBackground= */ null,
-                /* contrastCurve= */ new ContrastCurve(1.0, 1.0, 1.0, 1.0),
-                /* toneDeltaPair= */ null);
-    }
-
-    public DynamicColor overviewBackground() {
-        return new DynamicColor(
-                /* name= */ "overview_background",
-                /* palette= */ (s) -> s.neutralVariantPalette,
-                /* tone= */ (s) -> s.isDark ? 80.0 : 35.0,
-                /* isBackground= */ true,
-                /* background= */ null,
-                /* secondBackground= */ null,
-                /* contrastCurve= */null,
-                /* toneDeltaPair= */ null);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt b/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt
deleted file mode 100644
index 3518759..0000000
--- a/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.theme
-
-import android.util.Pair
-import com.google.ux.material.libmonet.dynamiccolor.DynamicColor
-import com.google.ux.material.libmonet.dynamiccolor.MaterialDynamicColors
-
-class DynamicColors {
-    companion object {
-        @JvmStatic
-        fun allDynamicColorsMapped(isExtendedFidelity: Boolean): List<Pair<String, DynamicColor>> {
-            val mdc = MaterialDynamicColors(isExtendedFidelity)
-            return arrayListOf(
-                Pair.create("primary_container", mdc.primaryContainer()),
-                Pair.create("on_primary_container", mdc.onPrimaryContainer()),
-                Pair.create("primary", mdc.primary()),
-                Pair.create("on_primary", mdc.onPrimary()),
-                Pair.create("secondary_container", mdc.secondaryContainer()),
-                Pair.create("on_secondary_container", mdc.onSecondaryContainer()),
-                Pair.create("secondary", mdc.secondary()),
-                Pair.create("on_secondary", mdc.onSecondary()),
-                Pair.create("tertiary_container", mdc.tertiaryContainer()),
-                Pair.create("on_tertiary_container", mdc.onTertiaryContainer()),
-                Pair.create("tertiary", mdc.tertiary()),
-                Pair.create("on_tertiary", mdc.onTertiary()),
-                Pair.create("background", mdc.background()),
-                Pair.create("on_background", mdc.onBackground()),
-                Pair.create("surface", mdc.surface()),
-                Pair.create("on_surface", mdc.onSurface()),
-                Pair.create("surface_container_low", mdc.surfaceContainerLow()),
-                Pair.create("surface_container_lowest", mdc.surfaceContainerLowest()),
-                Pair.create("surface_container", mdc.surfaceContainer()),
-                Pair.create("surface_container_high", mdc.surfaceContainerHigh()),
-                Pair.create("surface_container_highest", mdc.surfaceContainerHighest()),
-                Pair.create("surface_bright", mdc.surfaceBright()),
-                Pair.create("surface_dim", mdc.surfaceDim()),
-                Pair.create("surface_variant", mdc.surfaceVariant()),
-                Pair.create("on_surface_variant", mdc.onSurfaceVariant()),
-                Pair.create("outline", mdc.outline()),
-                Pair.create("outline_variant", mdc.outlineVariant()),
-                Pair.create("error", mdc.error()),
-                Pair.create("on_error", mdc.onError()),
-                Pair.create("error_container", mdc.errorContainer()),
-                Pair.create("on_error_container", mdc.onErrorContainer()),
-                Pair.create("control_activated", mdc.controlActivated()),
-                Pair.create("control_normal", mdc.controlNormal()),
-                Pair.create("control_highlight", mdc.controlHighlight()),
-                Pair.create("text_primary_inverse", mdc.textPrimaryInverse()),
-                Pair.create(
-                    "text_secondary_and_tertiary_inverse",
-                    mdc.textSecondaryAndTertiaryInverse()
-                ),
-                Pair.create(
-                    "text_primary_inverse_disable_only",
-                    mdc.textPrimaryInverseDisableOnly()
-                ),
-                Pair.create(
-                    "text_secondary_and_tertiary_inverse_disabled",
-                    mdc.textSecondaryAndTertiaryInverseDisabled()
-                ),
-                Pair.create("text_hint_inverse", mdc.textHintInverse()),
-                Pair.create("palette_key_color_primary", mdc.primaryPaletteKeyColor()),
-                Pair.create("palette_key_color_secondary", mdc.secondaryPaletteKeyColor()),
-                Pair.create("palette_key_color_tertiary", mdc.tertiaryPaletteKeyColor()),
-                Pair.create("palette_key_color_neutral", mdc.neutralPaletteKeyColor()),
-                Pair.create(
-                    "palette_key_color_neutral_variant",
-                    mdc.neutralVariantPaletteKeyColor()
-                ),
-            )
-        }
-
-        @JvmStatic
-        fun getFixedColorsMapped(isExtendedFidelity: Boolean): List<Pair<String, DynamicColor>> {
-            val mdc = MaterialDynamicColors(isExtendedFidelity)
-            return arrayListOf(
-                Pair.create("primary_fixed", mdc.primaryFixed()),
-                Pair.create("primary_fixed_dim", mdc.primaryFixedDim()),
-                Pair.create("on_primary_fixed", mdc.onPrimaryFixed()),
-                Pair.create("on_primary_fixed_variant", mdc.onPrimaryFixedVariant()),
-                Pair.create("secondary_fixed", mdc.secondaryFixed()),
-                Pair.create("secondary_fixed_dim", mdc.secondaryFixedDim()),
-                Pair.create("on_secondary_fixed", mdc.onSecondaryFixed()),
-                Pair.create("on_secondary_fixed_variant", mdc.onSecondaryFixedVariant()),
-                Pair.create("tertiary_fixed", mdc.tertiaryFixed()),
-                Pair.create("tertiary_fixed_dim", mdc.tertiaryFixedDim()),
-                Pair.create("on_tertiary_fixed", mdc.onTertiaryFixed()),
-                Pair.create("on_tertiary_fixed_variant", mdc.onTertiaryFixedVariant()),
-            )
-        }
-
-        @JvmStatic
-        fun getCustomColorsMapped(isExtendedFidelity: Boolean): List<Pair<String, DynamicColor>> {
-            val customMdc = CustomDynamicColors(isExtendedFidelity)
-            return arrayListOf(
-                Pair.create("widget_background", customMdc.widgetBackground()),
-                Pair.create("clock_hour", customMdc.clockHour()),
-                Pair.create("clock_minute", customMdc.clockMinute()),
-                Pair.create("clock_second", customMdc.weatherTemp()),
-                Pair.create("theme_app", customMdc.themeApp()),
-                Pair.create("on_theme_app", customMdc.onThemeApp()),
-                Pair.create("theme_app_ring", customMdc.themeAppRing()),
-                Pair.create("on_theme_app_ring", customMdc.themeNotif()),
-                Pair.create("brand_a", customMdc.brandA()),
-                Pair.create("brand_b", customMdc.brandB()),
-                Pair.create("brand_c", customMdc.brandC()),
-                Pair.create("brand_d", customMdc.brandD()),
-                Pair.create("under_surface", customMdc.underSurface()),
-                Pair.create("shade_active", customMdc.shadeActive()),
-                Pair.create("on_shade_active", customMdc.onShadeActive()),
-                Pair.create("on_shade_active_variant", customMdc.onShadeActiveVariant()),
-                Pair.create("shade_inactive", customMdc.shadeInactive()),
-                Pair.create("on_shade_inactive", customMdc.onShadeInactive()),
-                Pair.create("on_shade_inactive_variant", customMdc.onShadeInactiveVariant()),
-                Pair.create("shade_disabled", customMdc.shadeDisabled()),
-                Pair.create("overview_background", customMdc.overviewBackground())
-            )
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index d256c4a..7494649 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -77,6 +77,7 @@
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
 import com.android.systemui.keyguard.shared.model.KeyguardState;
 import com.android.systemui.monet.ColorScheme;
+import com.android.systemui.monet.DynamicColors;
 import com.android.systemui.monet.Style;
 import com.android.systemui.monet.TonalPalette;
 import com.android.systemui.settings.UserTracker;
@@ -623,7 +624,7 @@
             TonalPalette tonalPalette) {
         String resourcePrefix = "android:color/system_" + name;
 
-        tonalPalette.getAllShadesMapped().forEach((key, value) -> {
+        tonalPalette.allShadesMapped.forEach((key, value) -> {
             String resourceName = resourcePrefix + "_" + key;
             int colorValue = ColorUtils.setAlphaComponent(value, 0xFF);
             overlay.setResourceValue(resourceName, TYPE_INT_COLOR_ARGB8, colorValue,
@@ -634,7 +635,7 @@
     protected FabricatedOverlay createDynamicOverlay() {
         FabricatedOverlay overlay = newFabricatedOverlay("dynamic");
         //Themed Colors
-        assignColorsToOverlay(overlay, DynamicColors.allDynamicColorsMapped(mIsFidelityEnabled),
+        assignColorsToOverlay(overlay, DynamicColors.getAllDynamicColorsMapped(mIsFidelityEnabled),
                 false);
         // Fixed Colors
         assignColorsToOverlay(overlay, DynamicColors.getFixedColorsMapped(mIsFidelityEnabled),
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt
index c08cd64..fd01b48 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt
@@ -77,8 +77,6 @@
         mapOf(
             AudioStream(AudioManager.STREAM_NOTIFICATION) to
                 R.string.stream_notification_unavailable,
-            AudioStream(AudioManager.STREAM_ALARM) to R.string.stream_alarm_unavailable,
-            AudioStream(AudioManager.STREAM_MUSIC) to R.string.stream_media_unavailable,
         )
     private val uiEventByStream =
         mapOf(
@@ -126,7 +124,7 @@
         }
     }
 
-    private suspend fun AudioStreamModel.toState(
+    private fun AudioStreamModel.toState(
         isEnabled: Boolean,
         ringerMode: RingerMode,
     ): State {
@@ -138,7 +136,13 @@
             valueRange = volumeRange.first.toFloat()..volumeRange.last.toFloat(),
             icon = getIcon(ringerMode),
             label = label,
-            disabledMessage = disabledTextByStream[audioStream]?.let(context::getString),
+            disabledMessage =
+                context.getString(
+                    disabledTextByStream.getOrDefault(
+                        audioStream,
+                        R.string.stream_alarm_unavailable,
+                    )
+                ),
             isEnabled = isEnabled,
             a11yStep = volumeRange.step,
             a11yClickDescription =
@@ -167,14 +171,13 @@
                     null
                 },
             audioStreamModel = this,
-            isMutable = audioVolumeInteractor.isAffectedByMute(audioStream),
+            isMutable = isAffectedByMute,
         )
     }
 
     private fun AudioStreamModel.getIcon(ringerMode: RingerMode): Icon {
-        val isMutedOrNoVolume = isMuted || volume == minVolume
         val iconRes =
-            if (isMutedOrNoVolume) {
+            if (isAffectedByMute && isMuted) {
                 if (audioStream.value in streamsAffectedByRing) {
                     if (ringerMode.value == AudioManager.RINGER_MODE_VIBRATE) {
                         R.drawable.ic_volume_ringer_vibrate
diff --git a/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.kt b/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.kt
deleted file mode 100644
index 85cc88d..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.kt
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * Copyright (C) 2021 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.monet
-
-import android.testing.AndroidTestingRunner
-import android.util.Log
-import android.util.Pair
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.theme.DynamicColors
-import com.google.ux.material.libmonet.dynamiccolor.DynamicColor
-import com.google.ux.material.libmonet.hct.Hct
-import com.google.ux.material.libmonet.scheme.SchemeTonalSpot
-import java.io.File
-import java.io.FileWriter
-import java.io.StringWriter
-import javax.xml.parsers.DocumentBuilderFactory
-import javax.xml.transform.OutputKeys
-import javax.xml.transform.TransformerException
-import javax.xml.transform.TransformerFactory
-import javax.xml.transform.dom.DOMSource
-import javax.xml.transform.stream.StreamResult
-import kotlin.math.abs
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.w3c.dom.Document
-import org.w3c.dom.Element
-import org.w3c.dom.Node
-
-private const val fileHeader =
-    """
-  ~ Copyright (C) 2022 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-"""
-
-private fun testName(name: String): String {
-    return "Auto generated by: atest ColorSchemeTest#$name"
-}
-
-private const val commentRoles =
-    "Colors used in Android system, from design system. These " +
-        "values can be overlaid at runtime by OverlayManager RROs."
-
-private const val commentOverlay = "This value can be overlaid at runtime by OverlayManager RROs."
-
-private fun commentWhite(paletteName: String): String {
-    return "Lightest shade of the $paletteName color used by the system. White. $commentOverlay"
-}
-
-private fun commentBlack(paletteName: String): String {
-    return "Darkest shade of the $paletteName color used by the system. Black. $commentOverlay"
-}
-
-private fun commentShade(paletteName: String, tone: Int): String {
-    return "Shade of the $paletteName system color at $tone% perceptual luminance (L* in L*a*b* " +
-        "color space). $commentOverlay"
-}
-
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-class ColorSchemeTest : SysuiTestCase() {
-    private val defaultContrast = 0.0
-    private val defaultIsDark = false
-    private val defaultIsFidelity = false
-
-    @Test
-    fun generateThemeStyles() {
-        val document = buildDoc<Any>()
-
-        val themes = document.createElement("themes")
-        document.appendWithBreak(themes)
-
-        var hue = 0.0
-        while (hue < 360) {
-            val sourceColor = Hct.from(hue, 50.0, 50.0)
-            val sourceColorHex = sourceColor.toInt().toRGBHex()
-
-            val theme = document.createElement("theme")
-            theme.setAttribute("color", sourceColorHex)
-            themes.appendChild(theme)
-
-            for (styleValue in Style.entries) {
-                if (
-                    styleValue == Style.CLOCK ||
-                        styleValue == Style.CLOCK_VIBRANT ||
-                        styleValue == Style.CONTENT
-                ) {
-                    continue
-                }
-
-                val style = document.createElement(styleValue.name.lowercase())
-                val colorScheme = ColorScheme(sourceColor.toInt(), defaultIsDark, styleValue)
-
-                style.appendChild(
-                    document.createTextNode(
-                        listOf(
-                                colorScheme.accent1,
-                                colorScheme.accent2,
-                                colorScheme.accent3,
-                                colorScheme.neutral1,
-                                colorScheme.neutral2
-                            )
-                            .flatMap { a -> listOf(*a.allShades.toTypedArray()) }
-                            .joinToString(",", transform = Int::toRGBHex)
-                    )
-                )
-                theme.appendChild(style)
-            }
-
-            hue += 60
-        }
-
-        saveFile(document, "current_themes.xml")
-    }
-
-    @Test
-    fun generateDefaultValues() {
-        val document = buildDoc<Any>()
-
-        val resources = document.createElement("resources")
-        document.appendWithBreak(resources)
-
-        // shade colors
-        val colorScheme = ColorScheme(GOOGLE_BLUE, defaultIsDark)
-        arrayOf(
-                Triple("accent1", "Primary", colorScheme.accent1),
-                Triple("accent2", "Secondary", colorScheme.accent2),
-                Triple("accent3", "Tertiary", colorScheme.accent3),
-                Triple("neutral1", "Neutral", colorScheme.neutral1),
-                Triple("neutral2", "Secondary Neutral", colorScheme.neutral2)
-            )
-            .forEach {
-                val (paletteName, readable, palette) = it
-                palette.allShadesMapped.entries.forEachIndexed { index, (shade, colorValue) ->
-                    val comment =
-                        when (index) {
-                            0 -> commentWhite(readable)
-                            palette.allShadesMapped.entries.size - 1 -> commentBlack(readable)
-                            else -> commentShade(readable, abs(shade / 10 - 100))
-                        }
-                    resources.createColorEntry("system_${paletteName}_$shade", colorValue, comment)
-                }
-            }
-
-        resources.appendWithBreak(document.createComment(commentRoles), 2)
-
-        fun generateDynamic(pairs: List<Pair<String, DynamicColor>>) {
-            arrayOf(false, true).forEach { isDark ->
-                val suffix = if (isDark) "_dark" else "_light"
-                val dynamicScheme =
-                    SchemeTonalSpot(Hct.fromInt(GOOGLE_BLUE), isDark, defaultContrast)
-                pairs.forEach {
-                    resources.createColorEntry(
-                        "system_${it.first}$suffix",
-                        it.second.getArgb(dynamicScheme)
-                    )
-                }
-            }
-        }
-
-        // dynamic colors
-        generateDynamic(DynamicColors.allDynamicColorsMapped(defaultIsFidelity))
-
-        // fixed colors
-        val dynamicScheme =
-            SchemeTonalSpot(Hct.fromInt(GOOGLE_BLUE), defaultIsDark, defaultContrast)
-        DynamicColors.getFixedColorsMapped(defaultIsFidelity).forEach {
-            resources.createColorEntry("system_${it.first}", it.second.getArgb(dynamicScheme))
-        }
-
-        resources.appendWithBreak(document.createComment(commentRoles), 2)
-
-        // custom colors
-        generateDynamic(DynamicColors.getCustomColorsMapped(defaultIsFidelity))
-
-        saveFile(document, "role_values.xml")
-    }
-
-    // Helper Functions
-
-    private inline fun <reified T> buildDoc(): Document {
-        val functionName = T::class.simpleName + ""
-        val factory = DocumentBuilderFactory.newInstance()
-        val builder = factory.newDocumentBuilder()
-        val document = builder.newDocument()
-
-        document.appendWithBreak(document.createComment(fileHeader))
-        document.appendWithBreak(document.createComment(testName(functionName)))
-
-        return document
-    }
-
-    private fun documentToString(document: Document): String {
-        try {
-            val transformerFactory = TransformerFactory.newInstance()
-            val transformer = transformerFactory.newTransformer()
-            transformer.setOutputProperty(OutputKeys.MEDIA_TYPE, "application/xml")
-            transformer.setOutputProperty(OutputKeys.METHOD, "xml")
-            transformer.setOutputProperty(OutputKeys.INDENT, "yes")
-            transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4")
-
-            val stringWriter = StringWriter()
-            transformer.transform(DOMSource(document), StreamResult(stringWriter))
-            return stringWriter.toString()
-        } catch (e: TransformerException) {
-            throw RuntimeException("Error transforming XML", e)
-        }
-    }
-
-    private fun saveFile(document: Document, fileName: String) {
-        val outPath = context.filesDir.path + "/" + fileName
-        Log.d("ColorSchemeXml", "Artifact $fileName created")
-        val writer = FileWriter(File(outPath))
-        writer.write(documentToString(document))
-        writer.close()
-    }
-}
-
-private fun Element.createColorEntry(name: String, value: Int, comment: String? = null) {
-    val doc = this.ownerDocument
-
-    if (comment != null) {
-        this.appendChild(doc.createComment(comment))
-    }
-
-    val color = doc.createElement("color")
-    this.appendChild(color)
-
-    color.setAttribute("name", name)
-    color.appendChild(doc.createTextNode("#" + value.toRGBHex()))
-}
-
-private fun Node.appendWithBreak(child: Node, lineBreaks: Int = 1): Node {
-    val doc = if (this is Document) this else this.ownerDocument
-    val node = doc.createTextNode("\n".repeat(lineBreaks))
-    this.appendChild(node)
-    return this.appendChild(child)
-}
-
-private fun Int.toRGBHex(): String {
-    return "%06X".format(0xFFFFFF and this)
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractorTest.kt
index d15cfbf..2da4b72 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractorTest.kt
@@ -23,8 +23,8 @@
 import com.android.systemui.qs.panels.data.repository.IconTilesRepository
 import com.android.systemui.qs.panels.data.repository.gridLayoutTypeRepository
 import com.android.systemui.qs.panels.data.repository.iconTilesRepository
-import com.android.systemui.qs.panels.shared.model.GridLayoutType
 import com.android.systemui.qs.panels.shared.model.InfiniteGridLayoutType
+import com.android.systemui.qs.panels.shared.model.PartitionedGridLayoutType
 import com.android.systemui.qs.pipeline.data.repository.tileSpecRepository
 import com.android.systemui.qs.pipeline.domain.interactor.currentTilesInteractor
 import com.android.systemui.qs.pipeline.shared.TileSpec
@@ -45,8 +45,6 @@
 @RunWith(AndroidTestingRunner::class)
 class GridConsistencyInteractorTest : SysuiTestCase() {
 
-    data object TestGridLayoutType : GridLayoutType
-
     private val iconOnlyTiles =
         MutableStateFlow(
             setOf(
@@ -65,17 +63,13 @@
                     override val iconTilesSpecs: StateFlow<Set<TileSpec>>
                         get() = iconOnlyTiles.asStateFlow()
                 }
-            gridConsistencyInteractorsMap =
-                mapOf(
-                    Pair(InfiniteGridLayoutType, infiniteGridConsistencyInteractor),
-                    Pair(TestGridLayoutType, noopGridConsistencyInteractor)
-                )
         }
 
     private val underTest = with(kosmos) { gridConsistencyInteractor }
 
     @Before
     fun setUp() {
+        // Mostly testing InfiniteGridConsistencyInteractor because it reorders tiles
         with(kosmos) { gridLayoutTypeRepository.setLayout(InfiniteGridLayoutType) }
         underTest.start()
     }
@@ -86,7 +80,7 @@
         with(kosmos) {
             testScope.runTest {
                 // Using the no-op grid consistency interactor
-                gridLayoutTypeRepository.setLayout(TestGridLayoutType)
+                gridLayoutTypeRepository.setLayout(PartitionedGridLayoutType)
 
                 // Setting an invalid layout with holes
                 // [ Large A ] [ sa ]
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
new file mode 100644
index 0000000..fa2b343
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
@@ -0,0 +1,160 @@
+/*
+ * 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.chips.ui.viewmodel
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.ContentDescription
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+
+@SmallTest
+class OngoingActivityChipsViewModelTest : SysuiTestCase() {
+
+    private val kosmos = Kosmos()
+    private val underTest = kosmos.ongoingActivityChipsViewModel
+
+    @Test
+    fun chip_allHidden_hidden() =
+        kosmos.testScope.runTest {
+            kosmos.screenRecordChipInteractor.chip.value = OngoingActivityChipModel.Hidden
+            kosmos.callChipInteractor.chip.value = OngoingActivityChipModel.Hidden
+
+            val latest by collectLastValue(underTest.chip)
+
+            assertThat(latest).isEqualTo(OngoingActivityChipModel.Hidden)
+        }
+
+    @Test
+    fun chip_screenRecordShow_restHidden_screenRecordShown() =
+        kosmos.testScope.runTest {
+            val screenRecordChip =
+                OngoingActivityChipModel.Shown(
+                    Icon.Resource(R.drawable.ic_cake, ContentDescription.Loaded("icon")),
+                    startTimeMs = 500L,
+                ) {}
+            kosmos.screenRecordChipInteractor.chip.value = screenRecordChip
+            kosmos.callChipInteractor.chip.value = OngoingActivityChipModel.Hidden
+
+            val latest by collectLastValue(underTest.chip)
+
+            assertThat(latest).isEqualTo(screenRecordChip)
+        }
+
+    @Test
+    fun chip_screenRecordShowAndCallShow_screenRecordShown() =
+        kosmos.testScope.runTest {
+            val screenRecordChip =
+                OngoingActivityChipModel.Shown(
+                    Icon.Resource(R.drawable.ic_cake, ContentDescription.Loaded("icon")),
+                    startTimeMs = 500L,
+                ) {}
+            kosmos.screenRecordChipInteractor.chip.value = screenRecordChip
+
+            val callChip =
+                OngoingActivityChipModel.Shown(
+                    Icon.Resource(R.drawable.ic_call, ContentDescription.Loaded("icon")),
+                    startTimeMs = 600L,
+                ) {}
+            kosmos.callChipInteractor.chip.value = callChip
+
+            val latest by collectLastValue(underTest.chip)
+
+            assertThat(latest).isEqualTo(screenRecordChip)
+        }
+
+    @Test
+    fun chip_screenRecordHideAndCallShown_callShown() =
+        kosmos.testScope.runTest {
+            kosmos.screenRecordChipInteractor.chip.value = OngoingActivityChipModel.Hidden
+
+            val callChip =
+                OngoingActivityChipModel.Shown(
+                    Icon.Resource(R.drawable.ic_call, ContentDescription.Loaded("icon")),
+                    startTimeMs = 600L,
+                ) {}
+            kosmos.callChipInteractor.chip.value = callChip
+
+            val latest by collectLastValue(underTest.chip)
+
+            assertThat(latest).isEqualTo(callChip)
+        }
+
+    @Test
+    fun chip_higherPriorityChipAdded_lowerPriorityChipReplaced() =
+        kosmos.testScope.runTest {
+            // Start with just the lower priority call chip
+            val callChip =
+                OngoingActivityChipModel.Shown(
+                    Icon.Resource(R.drawable.ic_call, ContentDescription.Loaded("icon")),
+                    startTimeMs = 600L,
+                ) {}
+            kosmos.callChipInteractor.chip.value = callChip
+            kosmos.screenRecordChipInteractor.chip.value = OngoingActivityChipModel.Hidden
+
+            val latest by collectLastValue(underTest.chip)
+
+            assertThat(latest).isEqualTo(callChip)
+
+            // WHEN the higher priority screen record chip is added
+            val screenRecordChip =
+                OngoingActivityChipModel.Shown(
+                    Icon.Resource(R.drawable.ic_cake, ContentDescription.Loaded("icon")),
+                    startTimeMs = 500L,
+                ) {}
+            kosmos.screenRecordChipInteractor.chip.value = screenRecordChip
+
+            // THEN the higher priority screen record chip is used
+            assertThat(latest).isEqualTo(screenRecordChip)
+        }
+
+    @Test
+    fun chip_highestPriorityChipRemoved_showsNextPriorityChip() =
+        kosmos.testScope.runTest {
+            // Start with both the higher priority screen record chip and lower priority call chip
+            val screenRecordChip =
+                OngoingActivityChipModel.Shown(
+                    Icon.Resource(R.drawable.ic_cake, ContentDescription.Loaded("icon")),
+                    startTimeMs = 500L,
+                ) {}
+            kosmos.screenRecordChipInteractor.chip.value = screenRecordChip
+
+            val callChip =
+                OngoingActivityChipModel.Shown(
+                    Icon.Resource(R.drawable.ic_call, ContentDescription.Loaded("icon")),
+                    startTimeMs = 600L,
+                ) {}
+            kosmos.callChipInteractor.chip.value = callChip
+
+            val latest by collectLastValue(underTest.chip)
+
+            assertThat(latest).isEqualTo(screenRecordChip)
+
+            // WHEN the higher priority screen record is removed
+            kosmos.screenRecordChipInteractor.chip.value = OngoingActivityChipModel.Hidden
+
+            // THEN the lower priority call is used
+            assertThat(latest).isEqualTo(callChip)
+        }
+}
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 fdf77ae..ff182ad 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
@@ -46,6 +46,7 @@
 import com.android.systemui.animation.AnimatorTestRule;
 import com.android.systemui.demomode.DemoModeController;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.kosmos.KosmosJavaAdapter;
 import com.android.systemui.log.LogBuffer;
 import com.android.systemui.log.LogcatEchoTracker;
 import com.android.systemui.plugins.DarkIconDispatcher;
@@ -55,6 +56,7 @@
 import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.OperatorNameViewController;
+import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModel;
 import com.android.systemui.statusbar.disableflags.DisableFlagsLogger;
 import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
 import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerStatusBarViewBinder;
@@ -90,10 +92,11 @@
 @RunWithLooper(setAsMainLooper = true)
 @SmallTest
 public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
-
+    private final KosmosJavaAdapter mKosmos = new KosmosJavaAdapter();
     private NotificationIconAreaController mMockNotificationAreaController;
     private ShadeExpansionStateManager mShadeExpansionStateManager;
     private OngoingCallController mOngoingCallController;
+    private OngoingActivityChipsViewModel mOngoingActivityChipsViewModel;
     private SystemStatusAnimationScheduler mAnimationScheduler;
     private StatusBarLocationPublisher mLocationPublisher;
     // Set in instantiate()
@@ -667,6 +670,7 @@
         MockitoAnnotations.initMocks(this);
         setUpDaggerComponent();
         mOngoingCallController = mock(OngoingCallController.class);
+        mOngoingActivityChipsViewModel = mKosmos.getOngoingActivityChipsViewModel();
         mAnimationScheduler = mock(SystemStatusAnimationScheduler.class);
         mLocationPublisher = mock(StatusBarLocationPublisher.class);
         mStatusBarIconController = mock(StatusBarIconController.class);
@@ -687,6 +691,7 @@
         return new CollapsedStatusBarFragment(
                 mStatusBarFragmentComponentFactory,
                 mOngoingCallController,
+                mOngoingActivityChipsViewModel,
                 mAnimationScheduler,
                 mLocationPublisher,
                 mMockNotificationAreaController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index a5e7a67..5ad88ad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -64,6 +64,7 @@
 import com.android.systemui.flags.Flags;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
+import com.android.systemui.monet.DynamicColors;
 import com.android.systemui.monet.Style;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -997,7 +998,7 @@
         // All fixed colors were added once
         // All custom dynamic tokens added twice
         verify(dynamic, times(
-                DynamicColors.allDynamicColorsMapped(false).size() * 2
+                DynamicColors.getAllDynamicColorsMapped(false).size() * 2
                         + DynamicColors.getFixedColorsMapped(false).size()
                         + DynamicColors.getCustomColorsMapped(false).size() * 2)
         ).setResourceValue(any(String.class), eq(TYPE_INT_COLOR_ARGB8), anyInt(), eq(null));
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysUITestModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/SysUITestModule.kt
index 42b6e18..020f7fa 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysUITestModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysUITestModule.kt
@@ -66,6 +66,7 @@
             FaceWakeUpTriggersConfigModule::class,
         ]
 )
+@Deprecated("Use Kosmos instead. See com.android.systemui.kosmos.Kosmos.")
 interface SysUITestModule {
 
     @Binds fun bindTestableContext(sysuiTestableContext: SysuiTestableContext): TestableContext
@@ -127,6 +128,7 @@
     }
 }
 
+@Deprecated("Use Kosmos instead. See com.android.systemui.kosmos.Kosmos.")
 interface SysUITestComponent<out T> {
     val testScope: TestScope
     val underTest: T
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
index 0e95320..f2f4332 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
@@ -55,6 +55,7 @@
 import com.android.systemui.shade.data.repository.shadeRepository
 import com.android.systemui.shade.domain.interactor.shadeInteractor
 import com.android.systemui.shade.shadeController
+import com.android.systemui.statusbar.chips.ui.viewmodel.ongoingActivityChipsViewModel
 import com.android.systemui.statusbar.notification.stack.domain.interactor.headsUpNotificationInteractor
 import com.android.systemui.statusbar.notification.stack.domain.interactor.sharedNotificationContainerInteractor
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.fakeMobileConnectionsRepository
@@ -63,11 +64,18 @@
 import com.android.systemui.util.time.systemClock
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 
-/** Helper for using [Kosmos] from Java. */
+/**
+ * Helper for using [Kosmos] from Java.
+ *
+ * If your test class extends [SysuiTestCase], you may use the secondary constructor so that
+ * [Kosmos.applicationContext] and [Kosmos.testCase] are automatically set.
+ */
 @Deprecated("Please convert your test to Kotlin and use [Kosmos] directly.")
-class KosmosJavaAdapter(
-    testCase: SysuiTestCase,
-) {
+class KosmosJavaAdapter() {
+    constructor(testCase: SysuiTestCase) : this() {
+        kosmos.applicationContext = testCase.context
+        kosmos.testCase = testCase
+    }
 
     private val kosmos = Kosmos()
 
@@ -119,8 +127,5 @@
     val shadeRepository by lazy { kosmos.shadeRepository }
     val shadeInteractor by lazy { kosmos.shadeInteractor }
 
-    init {
-        kosmos.applicationContext = testCase.context
-        kosmos.testCase = testCase
-    }
+    val ongoingActivityChipsViewModel by lazy { kosmos.ongoingActivityChipsViewModel }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractorKosmos.kt
index 34e99d3..5568c6c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractorKosmos.kt
@@ -20,13 +20,24 @@
 import com.android.systemui.qs.panels.data.repository.gridLayoutTypeRepository
 import com.android.systemui.qs.panels.shared.model.GridLayoutType
 import com.android.systemui.qs.panels.shared.model.InfiniteGridLayoutType
+import com.android.systemui.qs.panels.shared.model.PartitionedGridLayoutType
 import com.android.systemui.qs.panels.ui.compose.GridLayout
 
 val Kosmos.gridLayoutTypeInteractor by
     Kosmos.Fixture { GridLayoutTypeInteractor(gridLayoutTypeRepository) }
 
 val Kosmos.gridLayoutMap: Map<GridLayoutType, GridLayout> by
-    Kosmos.Fixture { mapOf(Pair(InfiniteGridLayoutType, infiniteGridLayout)) }
+    Kosmos.Fixture {
+        mapOf(
+            Pair(PartitionedGridLayoutType, partitionedGridLayout),
+            Pair(InfiniteGridLayoutType, infiniteGridLayout)
+        )
+    }
 
 var Kosmos.gridConsistencyInteractorsMap: Map<GridLayoutType, GridTypeConsistencyInteractor> by
-    Kosmos.Fixture { mapOf(Pair(InfiniteGridLayoutType, infiniteGridConsistencyInteractor)) }
+    Kosmos.Fixture {
+        mapOf(
+            Pair(PartitionedGridLayoutType, noopGridConsistencyInteractor),
+            Pair(InfiniteGridLayoutType, infiniteGridConsistencyInteractor)
+        )
+    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/PartitionedGridLayoutKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/PartitionedGridLayoutKosmos.kt
new file mode 100644
index 0000000..4febfe91
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/PartitionedGridLayoutKosmos.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.panels.domain.interactor
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.qs.panels.ui.compose.PartitionedGridLayout
+
+val Kosmos.partitionedGridLayout by
+    Kosmos.Fixture { PartitionedGridLayout(iconTilesInteractor, infiniteGridSizeInteractor) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/TileGridViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/TileGridViewModelKosmos.kt
index 9481fca..6625bb5 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/TileGridViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/TileGridViewModelKosmos.kt
@@ -20,7 +20,7 @@
 import com.android.systemui.kosmos.applicationCoroutineScope
 import com.android.systemui.qs.panels.domain.interactor.gridLayoutMap
 import com.android.systemui.qs.panels.domain.interactor.gridLayoutTypeInteractor
-import com.android.systemui.qs.panels.domain.interactor.infiniteGridLayout
+import com.android.systemui.qs.panels.domain.interactor.partitionedGridLayout
 import com.android.systemui.qs.pipeline.domain.interactor.currentTilesInteractor
 
 val Kosmos.tileGridViewModel by
@@ -29,7 +29,7 @@
             gridLayoutTypeInteractor,
             gridLayoutMap,
             currentTilesInteractor,
-            infiniteGridLayout,
+            partitionedGridLayout,
             applicationCoroutineScope,
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/FakeOngoingActivityChipInteractor.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/FakeOngoingActivityChipInteractor.kt
new file mode 100644
index 0000000..cd08274
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/FakeOngoingActivityChipInteractor.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.chips.ui.viewmodel
+
+import com.android.systemui.statusbar.chips.call.domain.interactor.CallChipInteractor
+import com.android.systemui.statusbar.chips.screenrecord.domain.interactor.ScreenRecordChipInteractor
+import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
+import kotlinx.coroutines.flow.MutableStateFlow
+
+class FakeScreenRecordChipInteractor : ScreenRecordChipInteractor() {
+    override val chip: MutableStateFlow<OngoingActivityChipModel> =
+        MutableStateFlow(OngoingActivityChipModel.Hidden)
+}
+
+class FakeCallChipInteractor : CallChipInteractor() {
+    override val chip: MutableStateFlow<OngoingActivityChipModel> =
+        MutableStateFlow(OngoingActivityChipModel.Hidden)
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt
new file mode 100644
index 0000000..ffbaa7f
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelKosmos.kt
@@ -0,0 +1,34 @@
+/*
+ * 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.chips.ui.viewmodel
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+
+val Kosmos.screenRecordChipInteractor: FakeScreenRecordChipInteractor by
+    Kosmos.Fixture { FakeScreenRecordChipInteractor() }
+
+val Kosmos.callChipInteractor: FakeCallChipInteractor by Kosmos.Fixture { FakeCallChipInteractor() }
+
+val Kosmos.ongoingActivityChipsViewModel: OngoingActivityChipsViewModel by
+    Kosmos.Fixture {
+        OngoingActivityChipsViewModel(
+            testScope.backgroundScope,
+            screenRecordChipInteractor = screenRecordChipInteractor,
+            callChipInteractor = callChipInteractor,
+        )
+    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioRepository.kt
index 6b27079..21d59f0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/data/repository/FakeAudioRepository.kt
@@ -43,8 +43,6 @@
     private val models: MutableMap<AudioStream, MutableStateFlow<AudioStreamModel>> = mutableMapOf()
     private val lastAudibleVolumes: MutableMap<AudioStream, Int> = mutableMapOf()
 
-    private var isAffectedByMute: MutableMap<AudioStream, Boolean> = mutableMapOf()
-
     private fun getAudioStreamModelState(
         audioStream: AudioStream
     ): MutableStateFlow<AudioStreamModel> =
@@ -55,6 +53,7 @@
                     volume = 0,
                     minVolume = 0,
                     maxVolume = 10,
+                    isAffectedByMute = false,
                     isAffectedByRingerMode = false,
                     isMuted = false,
                 )
@@ -104,11 +103,4 @@
     override suspend fun setRingerMode(audioStream: AudioStream, mode: RingerMode) {
         mutableRingerMode.value = mode
     }
-
-    override suspend fun isAffectedByMute(audioStream: AudioStream): Boolean =
-        isAffectedByMute[audioStream] ?: true
-
-    fun setIsAffectedByMute(audioStream: AudioStream, isAffected: Boolean) {
-        isAffectedByMute[audioStream] = isAffected
-    }
 }
diff --git a/ravenwood/OWNERS b/ravenwood/OWNERS
index 41fd68e..a90328c 100644
--- a/ravenwood/OWNERS
+++ b/ravenwood/OWNERS
@@ -2,4 +2,6 @@
 
 jsharkey@google.com
 omakoto@google.com
-jaggies@google.com
+
+per-file ravenwood-annotation-allowed-classes.txt = dplotnikov@google.com
+per-file texts/ravenwood-annotation-allowed-classes.txt = dplotnikov@google.com
diff --git a/ravenwood/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/RavenwoodRuleTest.java b/ravenwood/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/RavenwoodRuleTest.java
index 3edca7e..01e90d8 100644
--- a/ravenwood/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/RavenwoodRuleTest.java
+++ b/ravenwood/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/RavenwoodRuleTest.java
@@ -18,6 +18,7 @@
 import android.platform.test.annotations.DisabledOnNonRavenwood;
 import android.platform.test.annotations.DisabledOnRavenwood;
 import android.platform.test.ravenwood.RavenwoodRule;
+import android.util.Log;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 
@@ -43,5 +44,13 @@
         Assert.assertTrue(RavenwoodRule.isOnRavenwood());
     }
 
+    @Test
+    public void testDumpSystemProperties() {
+        Log.w("XXX", "System properties");
+        for (var sp : System.getProperties().entrySet()) {
+            Log.w("XXX", "" + sp.getKey() + "=" + sp.getValue());
+        }
+    }
+
     // TODO: Add more tests
 }
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
index 56a3c64..5506a46 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
@@ -100,10 +100,11 @@
 
         android.os.Process.init$ravenwood(rule.mUid, rule.mPid);
         android.os.Binder.init$ravenwood();
-        android.os.SystemProperties.init$ravenwood(
-                rule.mSystemProperties.getValues(),
-                rule.mSystemProperties.getKeyReadablePredicate(),
-                rule.mSystemProperties.getKeyWritablePredicate());
+//        android.os.SystemProperties.init$ravenwood(
+//                rule.mSystemProperties.getValues(),
+//                rule.mSystemProperties.getKeyReadablePredicate(),
+//                rule.mSystemProperties.getKeyWritablePredicate());
+        setSystemProperties(rule.mSystemProperties);
 
         ServiceManager.init$ravenwood();
         LocalServices.removeAllServicesForTest();
@@ -157,7 +158,7 @@
         LocalServices.removeAllServicesForTest();
         ServiceManager.reset$ravenwood();
 
-        android.os.SystemProperties.reset$ravenwood();
+        setSystemProperties(RavenwoodSystemProperties.DEFAULT_VALUES);
         android.os.Binder.reset$ravenwood();
         android.os.Process.reset$ravenwood();
 
@@ -291,4 +292,16 @@
             collectMethods(clazz.getSuperclass(), result);
         }
     }
+
+    /**
+     * Set the current configuration to the actual SystemProperties.
+     */
+    public static void setSystemProperties(RavenwoodSystemProperties ravenwoodSystemProperties) {
+        var clone = new RavenwoodSystemProperties(ravenwoodSystemProperties, true);
+
+        android.os.SystemProperties.init$ravenwood(
+                clone.getValues(),
+                clone.getKeyReadablePredicate(),
+                clone.getKeyWritablePredicate());
+    }
 }
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java
index 85ad4e4..c3786ee 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java
@@ -22,7 +22,9 @@
 import java.util.Set;
 import java.util.function.Predicate;
 
-class RavenwoodSystemProperties {
+public class RavenwoodSystemProperties {
+    private volatile boolean mIsImmutable;
+
     private final Map<String, String> mValues = new HashMap<>();
 
     /** Set of additional keys that should be considered readable */
@@ -101,15 +103,23 @@
         setValue("ro.debuggable", "1");
     }
 
-    Map<String, String> getValues() {
+    /** Copy constructor */
+    public RavenwoodSystemProperties(RavenwoodSystemProperties source, boolean immutable) {
+        this.mKeyReadable.addAll(source.mKeyReadable);
+        this.mKeyWritable.addAll(source.mKeyWritable);
+        this.mValues.putAll(source.mValues);
+        this.mIsImmutable = immutable;
+    }
+
+    public Map<String, String> getValues() {
         return new HashMap<>(mValues);
     }
 
-    Predicate<String> getKeyReadablePredicate() {
+    public Predicate<String> getKeyReadablePredicate() {
         return mKeyReadablePredicate;
     }
 
-    Predicate<String> getKeyWritablePredicate() {
+    public Predicate<String> getKeyWritablePredicate() {
         return mKeyWritablePredicate;
     }
 
@@ -123,12 +133,20 @@
             "vendor_dlkm",
     };
 
+    private void ensureNotImmutable() {
+        if (mIsImmutable) {
+            throw new RuntimeException("Unable to update immutable instance");
+        }
+    }
+
     /**
      * Set the given property for all possible partitions where it could be defined. For
      * example, the value of {@code ro.build.type} is typically also mirrored under
      * {@code ro.system.build.type}, etc.
      */
     private void setValueForPartitions(String key, String value) {
+        ensureNotImmutable();
+
         setValue("ro." + key, value);
         for (String partition : PARTITIONS) {
             setValue("ro." + partition + "." + key, value);
@@ -136,6 +154,8 @@
     }
 
     public void setValue(String key, Object value) {
+        ensureNotImmutable();
+
         final String valueString = (value == null) ? null : String.valueOf(value);
         if ((valueString == null) || valueString.isEmpty()) {
             mValues.remove(key);
@@ -145,16 +165,19 @@
     }
 
     public void setAccessNone(String key) {
+        ensureNotImmutable();
         mKeyReadable.remove(key);
         mKeyWritable.remove(key);
     }
 
     public void setAccessReadOnly(String key) {
+        ensureNotImmutable();
         mKeyReadable.add(key);
         mKeyWritable.remove(key);
     }
 
     public void setAccessReadWrite(String key) {
+        ensureNotImmutable();
         mKeyReadable.add(key);
         mKeyWritable.add(key);
     }
@@ -172,4 +195,11 @@
             return key;
         }
     }
-}
+
+    /**
+     * Return an immutable, default instance.
+     */
+    // Create a default instance, and make an immutable copy of it.
+    public static final RavenwoodSystemProperties DEFAULT_VALUES =
+            new RavenwoodSystemProperties(new RavenwoodSystemProperties(), true);
+}
\ No newline at end of file
diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/RavenwoodEnvironment_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/RavenwoodEnvironment_host.java
new file mode 100644
index 0000000..68bf922
--- /dev/null
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/RavenwoodEnvironment_host.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.platform.test.ravenwood.nativesubstitution;
+
+import android.platform.test.ravenwood.RavenwoodSystemProperties;
+import android.util.Log;
+
+import com.android.internal.ravenwood.RavenwoodEnvironment;
+
+public class RavenwoodEnvironment_host {
+    private static final String TAG = RavenwoodEnvironment.TAG;
+
+    private static final Object sInitializeLock = new Object();
+
+    // @GuardedBy("sInitializeLock")
+    private static boolean sInitialized;
+
+    private RavenwoodEnvironment_host() {
+    }
+
+    /**
+     * Called from {@link RavenwoodEnvironment#ensureRavenwoodInitialized()}.
+     */
+    public static void ensureRavenwoodInitializedInternal() {
+        synchronized (sInitializeLock) {
+            if (sInitialized) {
+                return;
+            }
+            Log.w(TAG, "Initializing Ravenwood environment");
+
+            // Set the default values.
+            var sysProps = RavenwoodSystemProperties.DEFAULT_VALUES;
+
+            // We have a method that does it in RavenwoodRuleImpl, but we can't use that class
+            // here, So just inline it.
+            SystemProperties_host.initializeIfNeeded(
+                    sysProps.getValues(),
+                    sysProps.getKeyReadablePredicate(),
+                    sysProps.getKeyWritablePredicate());
+
+            sInitialized = true;
+        }
+    }
+}
diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/SystemProperties_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/SystemProperties_host.java
index eba6c8b..e7479d3 100644
--- a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/SystemProperties_host.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/SystemProperties_host.java
@@ -47,6 +47,21 @@
     @GuardedBy("sLock")
     private static SparseArray<String> sKeyHandles = new SparseArray<>();
 
+    /**
+     * Basically the same as {@link #native_init$ravenwood}, but it'll only run if no values are
+     * set yet.
+     */
+    public static void initializeIfNeeded(Map<String, String> values,
+            Predicate<String> keyReadablePredicate, Predicate<String> keyWritablePredicate) {
+        synchronized (sLock) {
+            if (sValues != null) {
+                return; // Already initialized.
+            }
+            native_init$ravenwood(values, keyReadablePredicate, keyWritablePredicate,
+                    () -> {});
+        }
+    }
+
     public static void native_init$ravenwood(Map<String, String> values,
             Predicate<String> keyReadablePredicate, Predicate<String> keyWritablePredicate,
             Runnable changeCallback) {
diff --git a/services/autofill/bugfixes.aconfig b/services/autofill/bugfixes.aconfig
index 0c3d40d..ba84485 100644
--- a/services/autofill/bugfixes.aconfig
+++ b/services/autofill/bugfixes.aconfig
@@ -23,13 +23,6 @@
 }
 
 flag {
-  name: "ignore_view_state_reset_to_empty"
-  namespace: "autofill"
-  description: "Mitigation for view state reset to empty causing no save dialog to show issue"
-  bug: "297976948"
-}
-
-flag {
   name: "include_invisible_view_group_in_assist_structure"
   namespace: "autofill"
   description: "Mitigation for autofill providers miscalculating view visibility"
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index f8c4116..07daecd 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -1249,46 +1249,21 @@
             return AUDIO_DEVICE_CATEGORY_UNKNOWN;
         }
         String deviceCategory = new String(deviceType);
-
-        if (com.android.bluetooth.flags.Flags.supportMetadataDeviceTypesApis()) {
-            switch (deviceCategory) {
-                case DEVICE_TYPE_HEARING_AID:
-                    return AUDIO_DEVICE_CATEGORY_HEARING_AID;
-                case DEVICE_TYPE_CARKIT:
-                    return AUDIO_DEVICE_CATEGORY_CARKIT;
-                case DEVICE_TYPE_HEADSET:
-                case DEVICE_TYPE_UNTETHERED_HEADSET:
-                    return AUDIO_DEVICE_CATEGORY_HEADPHONES;
-                case DEVICE_TYPE_SPEAKER:
-                    return AUDIO_DEVICE_CATEGORY_SPEAKER;
-                case DEVICE_TYPE_WATCH:
-                    return AUDIO_DEVICE_CATEGORY_WATCH;
-                case DEVICE_TYPE_DEFAULT:
-                    // fall through
-                default:
-                    break;
-            }
-        } else {
-            // Duplicate switch for now to cover the cases when the flag is not rolled out
-            // This will cover the cases in which clients could write directly to these
-            // metadata keys
-            switch (deviceCategory) {
-                case "HearingAid":
-                    return AUDIO_DEVICE_CATEGORY_HEARING_AID;
-                case "Carkit":
-                    return AUDIO_DEVICE_CATEGORY_CARKIT;
-                case "Headset":
-                case DEVICE_TYPE_UNTETHERED_HEADSET:
-                    return AUDIO_DEVICE_CATEGORY_HEADPHONES;
-                case "Speaker":
-                    return AUDIO_DEVICE_CATEGORY_SPEAKER;
-                case "Watch":
-                    return AUDIO_DEVICE_CATEGORY_WATCH;
-                case "Default":
-                    // fall through
-                default:
-                    break;
-            }
+        switch (deviceCategory) {
+            case DEVICE_TYPE_HEARING_AID:
+                return AUDIO_DEVICE_CATEGORY_HEARING_AID;
+            case DEVICE_TYPE_CARKIT:
+                return AUDIO_DEVICE_CATEGORY_CARKIT;
+            case DEVICE_TYPE_HEADSET:
+            case DEVICE_TYPE_UNTETHERED_HEADSET:
+                return AUDIO_DEVICE_CATEGORY_HEADPHONES;
+            case DEVICE_TYPE_SPEAKER:
+                return AUDIO_DEVICE_CATEGORY_SPEAKER;
+            case DEVICE_TYPE_WATCH:
+                return AUDIO_DEVICE_CATEGORY_WATCH;
+            case DEVICE_TYPE_DEFAULT:
+            default:
+                // fall through
         }
 
         BluetoothClass deviceClass = device.getBluetoothClass();
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index b589f49..2fce295 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -1446,6 +1446,7 @@
         if (Flags.modesApi()) {
             azr = new AutomaticZenRule.Builder(rule.name, rule.conditionId)
                     .setManualInvocationAllowed(rule.allowManualInvocation)
+                    .setPackage(rule.pkg)
                     .setCreationTime(rule.creationTime)
                     .setIconResId(drawableResNameToResId(rule.pkg, rule.iconResName))
                     .setType(rule.type)
@@ -1464,8 +1465,8 @@
                     rule.conditionId, rule.zenPolicy,
                     NotificationManager.zenModeToInterruptionFilter(rule.zenMode),
                     rule.enabled, rule.creationTime);
+            azr.setPackageName(rule.pkg);
         }
-        azr.setPackageName(rule.pkg);
         return azr;
     }
 
diff --git a/services/core/java/com/android/server/wm/AsyncRotationController.java b/services/core/java/com/android/server/wm/AsyncRotationController.java
index 24d4be8..a9450c4 100644
--- a/services/core/java/com/android/server/wm/AsyncRotationController.java
+++ b/services/core/java/com/android/server/wm/AsyncRotationController.java
@@ -290,7 +290,7 @@
         }
         // The insets position may be frozen by shouldFreezeInsetsPosition(), so refresh the
         // position to the latest state when it is ready to show in new rotation.
-        if (mTransitionOp == OP_APP_SWITCH) {
+        if (isSeamlessTransition()) {
             for (int i = windowToken.getChildCount() - 1; i >= 0; i--) {
                 final WindowState w = windowToken.getChildAt(i);
                 final InsetsSourceProvider insetsProvider = w.getControllableInsetProvider();
@@ -506,11 +506,16 @@
     boolean shouldFreezeInsetsPosition(WindowState w) {
         // Non-change transition (OP_APP_SWITCH) and METHOD_BLAST don't use screenshot so the
         // insets should keep original position before the start transaction is applied.
-        return mTransitionOp != OP_LEGACY && (mTransitionOp == OP_APP_SWITCH
+        return mTransitionOp != OP_LEGACY && (isSeamlessTransition()
                 || TransitionController.SYNC_METHOD == BLASTSyncEngine.METHOD_BLAST)
                 && !mIsStartTransactionCommitted && canBeAsync(w.mToken) && isTargetToken(w.mToken);
     }
 
+    /** Returns true if there won't be a screen rotation animation (screenshot-based). */
+    private boolean isSeamlessTransition() {
+        return mTransitionOp == OP_APP_SWITCH || mTransitionOp == OP_CHANGE_MAY_SEAMLESS;
+    }
+
     /**
      * Returns the transaction which will be applied after the window redraws in new rotation.
      * This is used to update the position of insets animation leash synchronously.
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index f7910b0..bf8bf34 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -714,9 +714,6 @@
 
         if (!state.hasRealCaller()) {
             if (resultForCaller.allows()) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(TAG, "Background activity start allowed. " + state);
-                }
                 return allowBasedOnCaller(state);
             }
             return abortLaunch(state);
@@ -742,15 +739,9 @@
 
         // Handle cases with explicit opt-in
         if (resultForCaller.allows() && state.callerExplicitOptInOrAutoOptIn()) {
-            if (DEBUG_ACTIVITY_STARTS) {
-                Slog.d(TAG, "Activity start explicitly allowed by caller. " + state);
-            }
             return allowBasedOnCaller(state);
         }
         if (resultForRealCaller.allows() && state.realCallerExplicitOptInOrAutoOptIn()) {
-            if (DEBUG_ACTIVITY_STARTS) {
-                Slog.d(TAG, "Activity start explicitly allowed by real caller. " + state);
-            }
             return allowBasedOnRealCaller(state);
         }
         // Handle PendingIntent cases with default behavior next
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e49cb38..e2b0932 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -5707,7 +5707,9 @@
                 // VR virtual display will be used to run and render 2D app within a VR experience.
                 && mDisplayId != mWmService.mVr2dDisplayId
                 // Do not show system decorations on untrusted virtual display.
-                && isTrusted();
+                && isTrusted()
+                // No system decoration on rear display.
+                && (mDisplay.getFlags() & Display.FLAG_REAR) == 0;
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 72ae64c..e3827aa 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -239,8 +239,8 @@
                         dragSurface = mSurfaceControl;
                     }
                 }
-                DragEvent event = DragEvent.obtain(DragEvent.ACTION_DRAG_ENDED,
-                        x, y, mThumbOffsetX, mThumbOffsetY, null, null, null, dragSurface, null,
+                DragEvent event = DragEvent.obtain(DragEvent.ACTION_DRAG_ENDED, x, y,
+                        mThumbOffsetX, mThumbOffsetY, mFlags, null, null, null, dragSurface, null,
                         mDragResult);
                 try {
                     if (DEBUG_DRAG) Slog.d(TAG_WM, "Sending DRAG_ENDED to " + ws);
@@ -298,7 +298,7 @@
      * as a part of the dispatched event.
      */
     private DragEvent createDropEvent(float x, float y, @Nullable WindowState touchedWin,
-            boolean includeDragSurface) {
+            boolean includePrivateInfo) {
         if (touchedWin != null) {
             final int targetUserId = UserHandle.getUserId(touchedWin.getOwningUid());
             final DragAndDropPermissionsHandler dragAndDropPermissions;
@@ -319,11 +319,16 @@
                     mData.fixUris(mSourceUserId);
                 }
             }
+            final boolean targetInterceptsGlobalDrag = targetInterceptsGlobalDrag(touchedWin);
             return obtainDragEvent(DragEvent.ACTION_DROP, x, y, mData,
-                    targetInterceptsGlobalDrag(touchedWin), dragAndDropPermissions);
+                    /* includeDragSurface= */ targetInterceptsGlobalDrag,
+                    /* includeDragFlags= */ targetInterceptsGlobalDrag,
+                    dragAndDropPermissions);
         } else {
             return obtainDragEvent(DragEvent.ACTION_DROP, x, y, mData,
-                    includeDragSurface /* includeDragSurface */, null /* dragAndDropPermissions */);
+                    /* includeDragSurface= */ includePrivateInfo,
+                    /* includeDragFlags= */ includePrivateInfo,
+                    null /* dragAndDropPermissions */);
         }
     }
 
@@ -525,7 +530,7 @@
             ClipData data = interceptsGlobalDrag ? mData.copyForTransferWithActivityInfo() : null;
             DragEvent event = obtainDragEvent(DragEvent.ACTION_DRAG_STARTED,
                     newWin.translateToWindowX(touchX), newWin.translateToWindowY(touchY),
-                    data, false /* includeDragSurface */,
+                    data, false /* includeDragSurface */, true /* includeDragFlags */,
                     null /* dragAndDropPermission */);
             try {
                 newWin.mClient.dispatchDragEvent(event);
@@ -696,8 +701,10 @@
     }
 
     private DragEvent obtainDragEvent(int action, float x, float y, ClipData data,
-            boolean includeDragSurface, IDragAndDropPermissions dragAndDropPermissions) {
+            boolean includeDragSurface, boolean includeDragFlags,
+            IDragAndDropPermissions dragAndDropPermissions) {
         return DragEvent.obtain(action, x, y, mThumbOffsetX, mThumbOffsetY,
+                includeDragFlags ? mFlags : 0,
                 null  /* localState */, mDataDescription, data,
                 includeDragSurface ? mSurfaceControl : null,
                 dragAndDropPermissions, false /* result */);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 8fb83fa..90c287c 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -224,6 +224,7 @@
 import android.view.InputChannel;
 import android.view.InputWindowHandle;
 import android.view.InsetsSource;
+import android.view.InsetsSourceControl;
 import android.view.InsetsState;
 import android.view.Surface;
 import android.view.Surface.Rotation;
@@ -432,6 +433,10 @@
     /** @see #isLastConfigReportedToClient() */
     private boolean mLastConfigReportedToClient;
 
+    // TODO(b/339380439): Ensure to use the same object for IWindowSession#relayout
+    private final InsetsSourceControl.Array mLastReportedActiveControls =
+            new InsetsSourceControl.Array();
+
     private final Configuration mTempConfiguration = new Configuration();
 
     /**
@@ -3813,9 +3818,9 @@
         }
         final InsetsStateController stateController =
                 getDisplayContent().getInsetsStateController();
+        mLastReportedActiveControls.set(stateController.getControlsForDispatch(this));
         try {
-            mClient.insetsControlChanged(getCompatInsetsState(),
-                    stateController.getControlsForDispatch(this));
+            mClient.insetsControlChanged(getCompatInsetsState(), mLastReportedActiveControls);
         } catch (RemoteException e) {
             Slog.w(TAG, "Failed to deliver inset control state change to w=" + this, e);
         }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/NonRequiredPackageDeleteObserver.java b/services/devicepolicy/java/com/android/server/devicepolicy/NonRequiredPackageDeleteObserver.java
index 0e448cd..a1bf040 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/NonRequiredPackageDeleteObserver.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/NonRequiredPackageDeleteObserver.java
@@ -25,7 +25,6 @@
 
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * Awaits the deletion of all the non-required apps.
@@ -33,38 +32,38 @@
 final class NonRequiredPackageDeleteObserver extends IPackageDeleteObserver.Stub {
     private static final int PACKAGE_DELETE_TIMEOUT_SEC = 30;
 
-    private final AtomicInteger mPackageCount = new AtomicInteger(/* initialValue= */ 0);
     private final CountDownLatch mLatch;
-    private boolean mSuccess;
+    private boolean mFailed = false;
 
     NonRequiredPackageDeleteObserver(int packageCount) {
         this.mLatch = new CountDownLatch(packageCount);
-        this.mPackageCount.set(packageCount);
     }
 
     @Override
     public void packageDeleted(String packageName, int returnCode) {
         if (returnCode != PackageManager.DELETE_SUCCEEDED) {
             Slog.e(LOG_TAG, "Failed to delete package: " + packageName);
-            mLatch.notifyAll();
-            return;
-        }
-        int currentPackageCount = mPackageCount.decrementAndGet();
-        if (currentPackageCount == 0) {
-            mSuccess = true;
-            Slog.i(LOG_TAG, "All non-required system apps with launcher icon, "
-                    + "and all disallowed apps have been uninstalled.");
+            mFailed = true;
         }
         mLatch.countDown();
     }
 
     public boolean awaitPackagesDeletion() {
         try {
-            mLatch.await(PACKAGE_DELETE_TIMEOUT_SEC, TimeUnit.SECONDS);
+            if (mLatch.await(PACKAGE_DELETE_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+                if (!mFailed) {
+                    Slog.i(LOG_TAG, "All non-required system apps with launcher icon, "
+                            + "and all disallowed apps have been uninstalled.");
+                }
+                return !mFailed;
+            } else {
+                Slog.i(LOG_TAG, "Waiting time elapsed before all package deletion finished");
+                return false;
+            }
         } catch (InterruptedException e) {
             Log.w(LOG_TAG, "Interrupted while waiting for package deletion", e);
             Thread.currentThread().interrupt();
+            return false;
         }
-        return mSuccess;
     }
 }
diff --git a/services/tests/PackageManagerServiceTests/server/Android.bp b/services/tests/PackageManagerServiceTests/server/Android.bp
index a738acb..ea7bb8b 100644
--- a/services/tests/PackageManagerServiceTests/server/Android.bp
+++ b/services/tests/PackageManagerServiceTests/server/Android.bp
@@ -105,7 +105,6 @@
         ":PackageParserTestApp5",
         ":PackageParserTestApp6",
         ":PackageParserTestApp7",
-        ":PackageParserTestApp8",
     ],
     resource_zips: [":PackageManagerServiceServerTests_apks_as_resources"],
 
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
index 5da202f..a0e0e1e 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
@@ -101,7 +101,6 @@
 import com.android.internal.pm.pkg.component.ParsedUsesPermission;
 import com.android.internal.pm.pkg.component.ParsedUsesPermissionImpl;
 import com.android.internal.pm.pkg.parsing.ParsingPackage;
-import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
 import com.android.internal.util.ArrayUtils;
 import com.android.server.pm.parsing.PackageCacher;
 import com.android.server.pm.parsing.PackageInfoUtils;
@@ -127,7 +126,6 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
@@ -156,7 +154,6 @@
     private static final String TEST_APP5_APK = "PackageParserTestApp5.apk";
     private static final String TEST_APP6_APK = "PackageParserTestApp6.apk";
     private static final String TEST_APP7_APK = "PackageParserTestApp7.apk";
-    private static final String TEST_APP8_APK = "PackageParserTestApp8.apk";
     private static final String PACKAGE_NAME = "com.android.servicestests.apps.packageparserapp";
 
     @Before
@@ -817,39 +814,6 @@
         }
     }
 
-    @Test
-    @RequiresFlagsEnabled(android.content.res.Flags.FLAG_MANIFEST_FLAGGING)
-    public void testParseWithFeatureFlagAttributes() throws Exception {
-        final File testFile = extractFile(TEST_APP8_APK);
-        try (PackageParser2 parser = new TestPackageParser2()) {
-            Map<String, Boolean> flagValues = new HashMap<>();
-            flagValues.put("my.flag1", true);
-            flagValues.put("my.flag2", false);
-            flagValues.put("my.flag3", false);
-            flagValues.put("my.flag4", true);
-            ParsingPackageUtils.getAconfigFlags().addFlagValuesForTesting(flagValues);
-
-            // The manifest has:
-            //    <permission android:name="PERM1" android:featureFlag="my.flag1 " />
-            //    <permission android:name="PERM2" android:featureFlag=" !my.flag2" />
-            //    <permission android:name="PERM3" android:featureFlag="my.flag3" />
-            //    <permission android:name="PERM4" android:featureFlag="!my.flag4" />
-            //    <permission android:name="PERM5" android:featureFlag="unknown.flag" />
-            // Therefore with the above flag values, only PERM1 and PERM2 should be present.
-
-            final ParsedPackage pkg = parser.parsePackage(testFile, 0, false);
-            List<String> permissionNames =
-                    pkg.getPermissions().stream().map(ParsedComponent::getName).toList();
-            assertThat(permissionNames).contains(PACKAGE_NAME + ".PERM1");
-            assertThat(permissionNames).contains(PACKAGE_NAME + ".PERM2");
-            assertThat(permissionNames).doesNotContain(PACKAGE_NAME + ".PERM3");
-            assertThat(permissionNames).doesNotContain(PACKAGE_NAME + ".PERM4");
-            assertThat(permissionNames).doesNotContain(PACKAGE_NAME + ".PERM5");
-        } finally {
-            testFile.delete();
-        }
-    }
-
     /**
      * A subclass of package parser that adds a "cache_" prefix to the package name for the cached
      * results. This is used by tests to tell if a ParsedPackage is generated from the cache or not.
diff --git a/services/tests/servicestests/test-apps/PackageParserApp/Android.bp b/services/tests/servicestests/test-apps/PackageParserApp/Android.bp
index 3def48a..131b380 100644
--- a/services/tests/servicestests/test-apps/PackageParserApp/Android.bp
+++ b/services/tests/servicestests/test-apps/PackageParserApp/Android.bp
@@ -116,20 +116,3 @@
     resource_dirs: ["res"],
     manifest: "AndroidManifestApp7.xml",
 }
-
-android_test_helper_app {
-    name: "PackageParserTestApp8",
-    sdk_version: "current",
-    srcs: ["**/*.java"],
-    dex_preopt: {
-        enabled: false,
-    },
-    optimize: {
-        enabled: false,
-    },
-    resource_dirs: ["res"],
-    aaptflags: [
-        "--feature-flags my.flag1,my.flag2,my.flag3,my.flag4,unknown.flag",
-    ],
-    manifest: "AndroidManifestApp8.xml",
-}
diff --git a/services/tests/servicestests/test-apps/PackageParserApp/AndroidManifestApp8.xml b/services/tests/servicestests/test-apps/PackageParserApp/AndroidManifestApp8.xml
deleted file mode 100644
index d489c1b..0000000
--- a/services/tests/servicestests/test-apps/PackageParserApp/AndroidManifestApp8.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2020 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.servicestests.apps.packageparserapp" >
-
-    <application>
-        <activity android:name=".TestActivity"
-                  android:exported="true" />
-    </application>
-
-    <permission android:name="PERM1" android:featureFlag="my.flag1 " />
-    <permission android:name="PERM2" android:featureFlag=" !my.flag2" />
-    <permission android:name="PERM3" android:featureFlag="my.flag3" />
-    <permission android:name="PERM4" android:featureFlag="!my.flag4" />
-    <permission android:name="PERM5" android:featureFlag="unknown.flag" />
-</manifest>
\ No newline at end of file
diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index a0461a6..7faf2aa 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -324,6 +324,44 @@
                 });
     }
 
+    @Test
+    public void testPrivateInterceptGlobalDragDropGetsDragFlags() {
+        mWindow.mAttrs.privateFlags |= PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP;
+        mWindow.setViewVisibility(View.GONE);
+
+        // Necessary for now since DragState.sendDragStartedLocked() will recycle drag events
+        // immediately after dispatching, which is a problem when using mockito arguments captor
+        // because it returns and modifies the same drag event
+        TestIWindow iwindow = (TestIWindow) mWindow.mClient;
+        final ArrayList<DragEvent> dragEvents = new ArrayList<>();
+        iwindow.setDragEventJournal(dragEvents);
+
+        startDrag(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG,
+                ClipData.newPlainText("label", "text"), () -> {
+                    // Verify the start-drag event has the drag flags
+                    final DragEvent dragEvent = dragEvents.get(0);
+                    assertTrue(dragEvent.getAction() == ACTION_DRAG_STARTED);
+                    assertTrue(dragEvent.getDragFlags() ==
+                            (View.DRAG_FLAG_GLOBAL
+                                    | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG));
+
+                    try {
+                        mTarget.mDeferDragStateClosed = true;
+                        mTarget.reportDropWindow(mWindow.mInputChannelToken, 0, 0);
+                        // // Verify the drop event does not have the drag flags
+                        mTarget.handleMotionEvent(false, 0, 0);
+                        final DragEvent dropEvent = dragEvents.get(dragEvents.size() - 1);
+                        assertTrue(dropEvent.getDragFlags() ==
+                                (View.DRAG_FLAG_GLOBAL
+                                        | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG));
+
+                        mTarget.reportDropResult(iwindow, true);
+                    } finally {
+                        mTarget.mDeferDragStateClosed = false;
+                    }
+                });
+    }
+
     private DragEvent last(ArrayList<DragEvent> list) {
         return list.get(list.size() - 1);
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
index 4fc222b..788b624 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
@@ -53,7 +53,7 @@
 
     @Override
     public void insetsControlChanged(InsetsState insetsState,
-            InsetsSourceControl[] activeControls) {
+            InsetsSourceControl.Array activeControls) {
     }
 
     @Override
diff --git a/tools/hoststubgen/OWNERS b/tools/hoststubgen/OWNERS
index a8c5321..3d8888d 100644
--- a/tools/hoststubgen/OWNERS
+++ b/tools/hoststubgen/OWNERS
@@ -1,3 +1 @@
-omakoto@google.com
-jsharkey@google.com
-jaggies@google.com
+file:platform/frameworks/base:/ravenwood/OWNERS