Merge "Fix keyguard on secondary displays" into main
diff --git a/nfc/api/current.txt b/nfc/api/current.txt
index f111327..e244520 100644
--- a/nfc/api/current.txt
+++ b/nfc/api/current.txt
@@ -228,20 +228,10 @@
     method public final android.os.IBinder onBind(android.content.Intent);
     method public abstract void onDeactivated(int);
     method public abstract byte[] processCommandApdu(byte[], android.os.Bundle);
-    method @FlaggedApi("android.nfc.nfc_read_polling_loop") public void processPollingFrames(@NonNull java.util.List<android.os.Bundle>);
+    method @FlaggedApi("android.nfc.nfc_read_polling_loop") public void processPollingFrames(@NonNull java.util.List<android.nfc.cardemulation.PollingFrame>);
     method public final void sendResponseApdu(byte[]);
     field public static final int DEACTIVATION_DESELECTED = 1; // 0x1
     field public static final int DEACTIVATION_LINK_LOSS = 0; // 0x0
-    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final String KEY_POLLING_LOOP_DATA = "android.nfc.cardemulation.DATA";
-    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final String KEY_POLLING_LOOP_GAIN = "android.nfc.cardemulation.GAIN";
-    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final String KEY_POLLING_LOOP_TIMESTAMP = "android.nfc.cardemulation.TIMESTAMP";
-    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final String KEY_POLLING_LOOP_TYPE = "android.nfc.cardemulation.TYPE";
-    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_A = 65; // 0x0041 'A'
-    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_B = 66; // 0x0042 'B'
-    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_F = 70; // 0x0046 'F'
-    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_OFF = 88; // 0x0058 'X'
-    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_ON = 79; // 0x004f 'O'
-    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_UNKNOWN = 85; // 0x0055 'U'
     field public static final String SERVICE_INTERFACE = "android.nfc.cardemulation.action.HOST_APDU_SERVICE";
     field public static final String SERVICE_META_DATA = "android.nfc.cardemulation.host_apdu_service";
   }
@@ -274,6 +264,23 @@
     field public static final String SERVICE_META_DATA = "android.nfc.cardemulation.off_host_apdu_service";
   }
 
+  @FlaggedApi("android.nfc.nfc_read_polling_loop") public final class PollingFrame implements android.os.Parcelable {
+    ctor public PollingFrame(int, @Nullable byte[], int, int);
+    method public int describeContents();
+    method @NonNull public byte[] getData();
+    method public int getGain();
+    method public int getTimestamp();
+    method public int getType();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.nfc.cardemulation.PollingFrame> CREATOR;
+    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final int POLLING_LOOP_TYPE_A = 65; // 0x41
+    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final int POLLING_LOOP_TYPE_B = 66; // 0x42
+    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final int POLLING_LOOP_TYPE_F = 70; // 0x46
+    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final int POLLING_LOOP_TYPE_OFF = 88; // 0x58
+    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final int POLLING_LOOP_TYPE_ON = 79; // 0x4f
+    field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final int POLLING_LOOP_TYPE_UNKNOWN = 85; // 0x55
+  }
+
 }
 
 package android.nfc.tech {
diff --git a/nfc/java/android/nfc/NfcAdapter.java b/nfc/java/android/nfc/NfcAdapter.java
index c5b7582..e5752d1 100644
--- a/nfc/java/android/nfc/NfcAdapter.java
+++ b/nfc/java/android/nfc/NfcAdapter.java
@@ -38,6 +38,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.net.Uri;
+import android.nfc.cardemulation.PollingFrame;
 import android.nfc.tech.MifareClassic;
 import android.nfc.tech.Ndef;
 import android.nfc.tech.NfcA;
@@ -2799,7 +2800,8 @@
      */
     @TestApi
     @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
-    public void notifyPollingLoop(@NonNull Bundle frame) {
+    public void notifyPollingLoop(@NonNull PollingFrame pollingFrame) {
+        Bundle frame = pollingFrame.toBundle();
         try {
             if (sService == null) {
                 attemptDeadServiceRecovery(null);
diff --git a/nfc/java/android/nfc/cardemulation/HostApduService.java b/nfc/java/android/nfc/cardemulation/HostApduService.java
index 363788e..61037a2 100644
--- a/nfc/java/android/nfc/cardemulation/HostApduService.java
+++ b/nfc/java/android/nfc/cardemulation/HostApduService.java
@@ -244,85 +244,6 @@
     public static final String KEY_DATA = "data";
 
     /**
-     * KEY_POLLING_LOOP_TYPE is the Bundle key for the type of
-     * polling loop frame in the Bundle passed to {@link #processPollingFrames(List)}
-     */
-    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
-    public static final String KEY_POLLING_LOOP_TYPE = "android.nfc.cardemulation.TYPE";
-
-    /**
-     * POLLING_LOOP_TYPE_A is the value associated with the key
-     * POLLING_LOOP_TYPE  in the Bundle passed to {@link #processPollingFrames(List)}
-     * when the polling loop is for NFC-A.
-     */
-    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
-    public static final char POLLING_LOOP_TYPE_A = 'A';
-
-    /**
-     * POLLING_LOOP_TYPE_B is the value associated with the key
-     * POLLING_LOOP_TYPE  in the Bundle passed to {@link #processPollingFrames(List)}
-     * when the polling loop is for NFC-B.
-     */
-    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
-    public static final char POLLING_LOOP_TYPE_B = 'B';
-
-    /**
-     * POLLING_LOOP_TYPE_F is the value associated with the key
-     * POLLING_LOOP_TYPE  in the Bundle passed to {@link #processPollingFrames(List)}
-     * when the polling loop is for NFC-F.
-     */
-    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
-    public static final char POLLING_LOOP_TYPE_F = 'F';
-
-    /**
-     * POLLING_LOOP_TYPE_ON is the value associated with the key
-     * POLLING_LOOP_TYPE  in the Bundle passed to {@link #processPollingFrames(List)}
-     * when the polling loop turns on.
-     */
-    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
-    public static final char POLLING_LOOP_TYPE_ON = 'O';
-
-    /**
-     * POLLING_LOOP_TYPE_OFF is the value associated with the key
-     * POLLING_LOOP_TYPE  in the Bundle passed to {@link #processPollingFrames(List)}
-     * when the polling loop turns off.
-     */
-    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
-    public static final char POLLING_LOOP_TYPE_OFF = 'X';
-
-    /**
-     * POLLING_LOOP_TYPE_UNKNOWN is the value associated with the key
-     * POLLING_LOOP_TYPE  in the Bundle passed to {@link #processPollingFrames(List)}
-     * when the polling loop frame isn't recognized.
-     */
-    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
-    public static final char POLLING_LOOP_TYPE_UNKNOWN = 'U';
-
-    /**
-     * KEY_POLLING_LOOP_DATA is the Bundle key for the raw data of captured from
-     * the polling loop frame in the Bundle passed to {@link #processPollingFrames(List)}
-     * when the frame type isn't recognized.
-     */
-    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
-    public static final String KEY_POLLING_LOOP_DATA = "android.nfc.cardemulation.DATA";
-
-    /**
-     * KEY_POLLING_LOOP_GAIN is the Bundle key for the field strength of
-     * the polling loop frame in the Bundle passed to {@link #processPollingFrames(List)}
-     * when the frame type isn't recognized.
-     */
-    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
-    public static final String KEY_POLLING_LOOP_GAIN = "android.nfc.cardemulation.GAIN";
-
-    /**
-     * KEY_POLLING_LOOP_TIMESTAMP is the Bundle key for the timestamp of
-     * the polling loop frame in the Bundle passed to {@link #processPollingFrames(List)}
-     * when the frame type isn't recognized.
-     */
-    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
-    public static final String KEY_POLLING_LOOP_TIMESTAMP = "android.nfc.cardemulation.TIMESTAMP";
-
-    /**
      * @hide
      */
     public static final String KEY_POLLING_LOOP_FRAMES_BUNDLE =
@@ -407,7 +328,12 @@
                     ArrayList<Bundle> frames =
                             msg.getData().getParcelableArrayList(KEY_POLLING_LOOP_FRAMES_BUNDLE,
                             Bundle.class);
-                    processPollingFrames(frames);
+                    ArrayList<PollingFrame> pollingFrames =
+                            new ArrayList<PollingFrame>(frames.size());
+                    for (Bundle frame : frames) {
+                        pollingFrames.add(new PollingFrame(frame));
+                    }
+                    processPollingFrames(pollingFrames);
                     break;
             default:
                 super.handleMessage(msg);
@@ -482,7 +408,7 @@
      * @param frame A description of the polling frame.
      */
     @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
-    public void processPollingFrames(@NonNull List<Bundle> frame) {
+    public void processPollingFrames(@NonNull List<PollingFrame> frame) {
     }
 
     /**
diff --git a/nfc/java/android/nfc/cardemulation/PollingFrame.java b/nfc/java/android/nfc/cardemulation/PollingFrame.java
new file mode 100644
index 0000000..3383f3b
--- /dev/null
+++ b/nfc/java/android/nfc/cardemulation/PollingFrame.java
@@ -0,0 +1,243 @@
+/*
+ * 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 android.nfc.cardemulation;
+
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.HexFormat;
+import java.util.List;
+
+/**
+ * Polling Frames represent data about individual frames of an NFC polling loop. These frames will
+ * be deliverd to subclasses of {@link HostApduService} that have registered filters with
+ * {@link CardEmulation#registerPollingLoopFilterForService(ComponentName, String)} that match a
+ * given frame in a loop and will be delivered through calls to
+ * {@link HostApduService#processPollingFrames(List)}.
+ */
+@FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+public final class PollingFrame implements Parcelable{
+
+    /**
+     * @hide
+     */
+    @IntDef(prefix = { "POLLING_LOOP_TYPE_"}, value = { POLLING_LOOP_TYPE_A, POLLING_LOOP_TYPE_B,
+            POLLING_LOOP_TYPE_F, POLLING_LOOP_TYPE_OFF, POLLING_LOOP_TYPE_ON })
+    @Retention(RetentionPolicy.SOURCE)
+    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public @interface PollingFrameType {}
+
+    /**
+     * POLLING_LOOP_TYPE_A is the value associated with the key
+     * POLLING_LOOP_TYPE  in the Bundle passed to {@link HostApduService#processPollingFrames(List)}
+     * when the polling loop is for NFC-A.
+     */
+    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public static final int POLLING_LOOP_TYPE_A = 'A';
+
+    /**
+     * POLLING_LOOP_TYPE_B is the value associated with the key
+     * POLLING_LOOP_TYPE  in the Bundle passed to {@link HostApduService#processPollingFrames(List)}
+     * when the polling loop is for NFC-B.
+     */
+    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public static final int POLLING_LOOP_TYPE_B = 'B';
+
+    /**
+     * POLLING_LOOP_TYPE_F is the value associated with the key
+     * POLLING_LOOP_TYPE  in the Bundle passed to {@link HostApduService#processPollingFrames(List)}
+     * when the polling loop is for NFC-F.
+     */
+    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public static final int POLLING_LOOP_TYPE_F = 'F';
+
+    /**
+     * POLLING_LOOP_TYPE_ON is the value associated with the key
+     * POLLING_LOOP_TYPE  in the Bundle passed to {@link HostApduService#processPollingFrames(List)}
+     * when the polling loop turns on.
+     */
+    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public static final int POLLING_LOOP_TYPE_ON = 'O';
+
+    /**
+     * POLLING_LOOP_TYPE_OFF is the value associated with the key
+     * POLLING_LOOP_TYPE  in the Bundle passed to {@link HostApduService#processPollingFrames(List)}
+     * when the polling loop turns off.
+     */
+    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public static final int POLLING_LOOP_TYPE_OFF = 'X';
+
+    /**
+     * POLLING_LOOP_TYPE_UNKNOWN is the value associated with the key
+     * POLLING_LOOP_TYPE  in the Bundle passed to {@link HostApduService#processPollingFrames(List)}
+     * when the polling loop frame isn't recognized.
+     */
+    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public static final int POLLING_LOOP_TYPE_UNKNOWN = 'U';
+
+    /**
+     * KEY_POLLING_LOOP_TYPE is the Bundle key for the type of
+     * polling loop frame in the Bundle included in MSG_POLLING_LOOP.
+     *
+     * @hide
+     */
+    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public static final String KEY_POLLING_LOOP_TYPE = "android.nfc.cardemulation.TYPE";
+
+    /**
+     * KEY_POLLING_LOOP_DATA is the Bundle key for the raw data of captured from
+     * the polling loop frame in the Bundle included in MSG_POLLING_LOOP.
+     *
+     * @hide
+     */
+    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public static final String KEY_POLLING_LOOP_DATA = "android.nfc.cardemulation.DATA";
+
+    /**
+     * KEY_POLLING_LOOP_GAIN is the Bundle key for the field strength of
+     * the polling loop frame in the Bundle included in MSG_POLLING_LOOP.
+     *
+     * @hide
+     */
+    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public static final String KEY_POLLING_LOOP_GAIN = "android.nfc.cardemulation.GAIN";
+
+    /**
+     * KEY_POLLING_LOOP_TIMESTAMP is the Bundle key for the timestamp of
+     * the polling loop frame in the Bundle included in MSG_POLLING_LOOP.
+     *
+     * @hide
+     */
+    @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
+    public static final String KEY_POLLING_LOOP_TIMESTAMP = "android.nfc.cardemulation.TIMESTAMP";
+
+
+    @PollingFrameType
+    private final int mType;
+    private final byte[] mData;
+    private final int mGain;
+    private final int mTimestamp;
+
+    public static final @NonNull Parcelable.Creator<PollingFrame> CREATOR =
+            new Parcelable.Creator<>() {
+                @Override
+                public PollingFrame createFromParcel(Parcel source) {
+                    return new PollingFrame(source.readBundle());
+                }
+
+                @Override
+                public PollingFrame[] newArray(int size) {
+                    return new PollingFrame[size];
+                }
+            };
+
+    PollingFrame(Bundle frame) {
+        mType = frame.getInt(KEY_POLLING_LOOP_TYPE);
+        byte[] data = frame.getByteArray(KEY_POLLING_LOOP_DATA);
+        mData = (data == null) ? new byte[0] : data;
+        mGain = frame.getByte(KEY_POLLING_LOOP_GAIN);
+        mTimestamp = frame.getInt(KEY_POLLING_LOOP_TIMESTAMP);
+    }
+
+    public PollingFrame(@PollingFrameType int type, @Nullable byte[] data,
+            int gain, int timestamp) {
+        mType = type;
+        mData = data == null ? new byte[0] : data;
+        mGain = gain;
+        mTimestamp = timestamp;
+    }
+
+    /**
+     * Returns the type of frame for this polling loop frame.
+     * The possible return values are:
+     * <ul>
+     *   <li>{@link POLLING_LOOP_TYPE_ON}</li>
+     *   <li>{@link POLLING_LOOP_TYPE_OFF}</li>
+     *   <li>{@link POLLING_LOOP_TYPE_A}</li>
+     *   <li>{@link POLLING_LOOP_TYPE_B}</li>
+     *   <li>{@link POLLING_LOOP_TYPE_F}</li>
+     * </ul>
+     */
+    public @PollingFrameType int getType() {
+        return mType;
+    }
+
+    /**
+     * Returns the raw data from the polling type frame.
+     */
+    public @NonNull byte[] getData() {
+        return mData;
+    }
+
+    /**
+     * Returns the gain representing the field strength of the NFC field when this polling loop
+     * frame was observed.
+     */
+    public int getGain() {
+        return mGain;
+    }
+
+    /**
+     * Returns the timestamp of when the polling loop frame was observed in milliseconds. These
+     * timestamps are relative and not absolute and should only be used fro comparing the timing of
+     * frames relative to each other.
+     * @return the timestamp in milliseconds
+     */
+    public int getTimestamp() {
+        return mTimestamp;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeBundle(toBundle());
+    }
+
+    /**
+     *
+     * @hide
+     * @return a Bundle representing this frame
+     */
+    public Bundle toBundle() {
+        Bundle frame = new Bundle();
+        frame.putInt(KEY_POLLING_LOOP_TYPE, getType());
+        frame.putByte(KEY_POLLING_LOOP_GAIN, (byte) getGain());
+        frame.putByteArray(KEY_POLLING_LOOP_DATA, getData());
+        frame.putInt(KEY_POLLING_LOOP_TIMESTAMP, getTimestamp());
+        return frame;
+    }
+
+    @Override
+    public String toString() {
+        return "PollingFrame { Type: " + (char) getType()
+                + ", gain: " + getGain()
+                + ", timestamp: " + Integer.toUnsignedString(getTimestamp())
+                + ", data: [" + HexFormat.ofDelimiter(" ").formatHex(getData()) + "] }";
+    }
+}
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 4ed1965..acb1418 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -15,6 +15,16 @@
 }
 
 flag {
+   name: "udfps_view_performance"
+   namespace: "systemui"
+   description: "Decrease screen off blocking calls by waiting until the device is finished going to sleep before adding the udfps view."
+   bug: "225183106"
+   metadata {
+        purpose: PURPOSE_BUGFIX
+   }
+}
+
+flag {
     name: "notification_async_group_header_inflation"
     namespace: "systemui"
     description: "Inflates the notification group summary header views from the background thread."
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
index 7b21d09..dd043db 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
@@ -18,11 +18,14 @@
 
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
 import androidx.compose.ui.Modifier
 import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.animateSceneFloatAsState
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyguard.ui.viewmodel.LockscreenSceneViewModel
+import com.android.systemui.qs.ui.composable.QuickSettings
 import com.android.systemui.scene.shared.model.Direction
 import com.android.systemui.scene.shared.model.Edge
 import com.android.systemui.scene.shared.model.SceneKey
@@ -87,10 +90,15 @@
 }
 
 @Composable
-private fun LockscreenScene(
+private fun SceneScope.LockscreenScene(
     lockscreenContent: Lazy<LockscreenContent>,
     modifier: Modifier = Modifier,
 ) {
+    animateSceneFloatAsState(
+        value = QuickSettings.SharedValues.SquishinessValues.LockscreenSceneStarting,
+        key = QuickSettings.SharedValues.TilesSquishiness,
+    )
+
     lockscreenContent
         .get()
         .Content(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
index de8f2ec..5d0b9ba 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
@@ -16,7 +16,6 @@
 
 package com.android.systemui.qs.ui.composable
 
-import androidx.compose.foundation.background
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.fillMaxHeight
 import androidx.compose.foundation.layout.fillMaxWidth
@@ -32,14 +31,12 @@
 import com.android.compose.animation.scene.MovableElementScenePicker
 import com.android.compose.animation.scene.SceneScope
 import com.android.compose.animation.scene.TransitionState
+import com.android.compose.animation.scene.ValueKey
 import com.android.compose.modifiers.thenIf
-import com.android.compose.theme.colorAttr
 import com.android.systemui.qs.ui.adapter.QSSceneAdapter
 import com.android.systemui.qs.ui.adapter.QSSceneAdapter.State.Companion.Collapsing
 import com.android.systemui.qs.ui.adapter.QSSceneAdapter.State.Expanding
-import com.android.systemui.res.R
-import com.android.systemui.scene.ui.composable.Gone
-import com.android.systemui.scene.ui.composable.Lockscreen
+import com.android.systemui.qs.ui.adapter.QSSceneAdapter.State.Unsquishing
 import com.android.systemui.scene.ui.composable.QuickSettings as QuickSettingsSceneKey
 import com.android.systemui.scene.ui.composable.Shade
 
@@ -51,15 +48,24 @@
         )
 
     object Elements {
-        // TODO RENAME
         val Content =
             ElementKey("QuickSettingsContent", scenePicker = MovableElementScenePicker(SCENES))
-        val CollapsedGrid = ElementKey("QuickSettingsCollapsedGrid")
         val FooterActions = ElementKey("QuickSettingsFooterActions")
     }
+
+    object SharedValues {
+        val TilesSquishiness = ValueKey("QuickSettingsTileSquishiness")
+        object SquishinessValues {
+            val Default = 1f
+            val LockscreenSceneStarting = 0f
+            val GoneSceneStarting = 0.3f
+        }
+    }
 }
 
-private fun SceneScope.stateForQuickSettingsContent(): QSSceneAdapter.State {
+private fun SceneScope.stateForQuickSettingsContent(
+    squishiness: Float = QuickSettings.SharedValues.SquishinessValues.Default
+): QSSceneAdapter.State {
     return when (val transitionState = layoutState.transitionState) {
         is TransitionState.Idle -> {
             when (transitionState.currentScene) {
@@ -73,10 +79,10 @@
                 when {
                     fromScene == Shade && toScene == QuickSettingsSceneKey -> Expanding(progress)
                     fromScene == QuickSettingsSceneKey && toScene == Shade -> Collapsing(progress)
-                    toScene == Shade -> QSSceneAdapter.State.QQS
-                    toScene == QuickSettingsSceneKey -> QSSceneAdapter.State.QS
-                    toScene == Gone -> QSSceneAdapter.State.CLOSED
-                    toScene == Lockscreen -> QSSceneAdapter.State.CLOSED
+                    fromScene == Shade || toScene == Shade -> Unsquishing(squishiness)
+                    fromScene == QuickSettingsSceneKey || toScene == QuickSettingsSceneKey -> {
+                        QSSceneAdapter.State.QS
+                    }
                     else ->
                         error(
                             "Bad transition for QuickSettings: fromScene=$fromScene," +
@@ -90,14 +96,24 @@
 /**
  * This composable will show QuickSettingsContent in the correct state (as determined by its
  * [SceneScope]).
+ *
+ * If adding to scenes not in:
+ * * QuickSettingsScene
+ * * ShadeScene
+ *
+ * amend:
+ * * [stateForQuickSettingsContent],
+ * * [QuickSettings.SCENES],
+ * * this doc.
  */
 @Composable
 fun SceneScope.QuickSettings(
     qsSceneAdapter: QSSceneAdapter,
     heightProvider: () -> Int,
     modifier: Modifier = Modifier,
+    squishiness: Float = QuickSettings.SharedValues.SquishinessValues.Default,
 ) {
-    val contentState = stateForQuickSettingsContent()
+    val contentState = stateForQuickSettingsContent(squishiness)
 
     MovableElement(
         key = QuickSettings.Elements.Content,
@@ -136,7 +152,7 @@
                     modifier.fillMaxWidth().thenIf(isCustomizing) { Modifier.fillMaxHeight() }
             ) {
                 AndroidView(
-                    modifier = Modifier.fillMaxWidth().background(colorAttr(R.attr.underSurface)),
+                    modifier = Modifier.fillMaxWidth(),
                     factory = { _ ->
                         qsSceneAdapter.setState(state)
                         view
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
index d36345a3..66cef86 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
@@ -54,6 +54,7 @@
 import androidx.compose.ui.unit.dp
 import com.android.compose.animation.scene.SceneScope
 import com.android.compose.animation.scene.TransitionState
+import com.android.compose.animation.scene.animateSceneFloatAsState
 import com.android.compose.windowsizeclass.LocalWindowSizeClass
 import com.android.systemui.battery.BatteryMeterViewController
 import com.android.systemui.compose.modifiers.sysuiResTag
@@ -128,6 +129,7 @@
             remember(lifecycleOwner, viewModel) {
                 viewModel.getFooterActionsViewModel(lifecycleOwner)
             }
+        animateSceneFloatAsState(value = 1f, key = QuickSettings.SharedValues.TilesSquishiness)
 
         // ############## SCROLLING ################
 
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
index f90f29d..9ca751e 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
@@ -19,9 +19,12 @@
 import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
 import androidx.compose.ui.Modifier
 import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.animateSceneFloatAsState
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.qs.ui.composable.QuickSettings
 import com.android.systemui.scene.shared.model.Direction
 import com.android.systemui.scene.shared.model.Edge
 import com.android.systemui.scene.shared.model.SceneKey
@@ -63,6 +66,10 @@
     override fun SceneScope.Content(
         modifier: Modifier,
     ) {
+        animateSceneFloatAsState(
+            value = QuickSettings.SharedValues.SquishinessValues.GoneSceneStarting,
+            key = QuickSettings.SharedValues.TilesSquishiness,
+        )
         Spacer(modifier.fillMaxSize())
     }
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToShadeTransition.kt
index e71f996..48ab68a 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToShadeTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToShadeTransition.kt
@@ -1,11 +1,11 @@
 package com.android.systemui.scene.ui.composable.transitions
 
 import androidx.compose.animation.core.tween
-import com.android.compose.animation.scene.Edge
 import com.android.compose.animation.scene.TransitionBuilder
 import com.android.systemui.notifications.ui.composable.Notifications
 import com.android.systemui.qs.ui.composable.QuickSettings
 import com.android.systemui.shade.ui.composable.Shade
+import com.android.systemui.shade.ui.composable.ShadeHeader
 import kotlin.time.Duration.Companion.milliseconds
 
 fun TransitionBuilder.lockscreenToShadeTransition(
@@ -13,15 +13,12 @@
 ) {
     spec = tween(durationMillis = DefaultDuration.times(durationScale).inWholeMilliseconds.toInt())
 
-    fractionRange(end = 0.5f) {
-        fade(Shade.Elements.BackgroundScrim)
-        translate(
-            QuickSettings.Elements.CollapsedGrid,
-            Edge.Top,
-            startsOutsideLayoutBounds = false,
-        )
+    fractionRange(end = 0.5f) { fade(Shade.Elements.BackgroundScrim) }
+    translate(QuickSettings.Elements.Content, y = -ShadeHeader.Dimensions.CollapsedHeight * .66f)
+    fractionRange(start = 0.5f) {
+        fade(QuickSettings.Elements.Content)
+        fade(Notifications.Elements.NotificationScrim)
     }
-    fractionRange(start = 0.5f) { fade(Notifications.Elements.NotificationScrim) }
 }
 
 private val DefaultDuration = 500.milliseconds
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
index 25df3e4..8c6bf61 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
@@ -28,6 +28,7 @@
 import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.ui.Alignment
@@ -40,6 +41,7 @@
 import com.android.compose.animation.scene.ElementKey
 import com.android.compose.animation.scene.LowestZIndexScenePicker
 import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.animateSceneFloatAsState
 import com.android.systemui.battery.BatteryMeterViewController
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
@@ -73,7 +75,6 @@
 
 object Shade {
     object Elements {
-        val QuickSettings = ElementKey("ShadeQuickSettings")
         val MediaCarousel = ElementKey("ShadeMediaCarousel")
         val BackgroundScrim =
             ElementKey("ShadeBackgroundScrim", scenePicker = LowestZIndexScenePicker)
@@ -160,6 +161,8 @@
     val density = LocalDensity.current
     val layoutWidth = remember { mutableStateOf(0) }
     val maxNotifScrimTop = remember { mutableStateOf(0f) }
+    val tileSquishiness by
+        animateSceneFloatAsState(value = 1f, key = QuickSettings.SharedValues.TilesSquishiness)
 
     Box(
         modifier =
@@ -190,7 +193,11 @@
                             )
                             QuickSettings(
                                 viewModel.qsSceneAdapter,
-                                { viewModel.qsSceneAdapter.qqsHeight },
+                                {
+                                    (viewModel.qsSceneAdapter.qqsHeight * tileSquishiness)
+                                        .roundToInt()
+                                },
+                                squishiness = tileSquishiness,
                             )
 
                             if (viewModel.isMediaVisible()) {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterImplTest.kt
index f8573cc2..3c0ab24 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterImplTest.kt
@@ -259,6 +259,37 @@
         }
 
     @Test
+    fun state_unsquishing() =
+        testScope.runTest {
+            val qsImpl by collectLastValue(underTest.qsImpl)
+            val squishiness = 0.342f
+
+            underTest.inflate(context)
+            runCurrent()
+            clearInvocations(qsImpl!!)
+
+            underTest.setState(QSSceneAdapter.State.Unsquishing(squishiness))
+            with(qsImpl!!) {
+                verify(this).setQsVisible(true)
+                verify(this)
+                    .setQsExpansion(
+                        /* expansion= */ 0f,
+                        /* panelExpansionFraction= */ 1f,
+                        /* proposedTranslation= */ 0f,
+                        /* squishinessFraction= */ squishiness,
+                    )
+                verify(this).setListening(true)
+                verify(this).setExpanded(true)
+                verify(this)
+                    .setTransitionToFullShadeProgress(
+                        /* isTransitioningToFullShade= */ false,
+                        /* qsTransitionFraction= */ 1f,
+                        /* qsSquishinessFraction = */ squishiness,
+                    )
+            }
+        }
+
+    @Test
     fun customizing_QS() =
         testScope.runTest {
             val customizing by collectLastValue(underTest.isCustomizing)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterTest.kt
index d1bc686..e281383 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterTest.kt
@@ -29,6 +29,12 @@
 @EnabledOnRavenwood
 @RunWith(AndroidJUnit4::class)
 class QSSceneAdapterTest : SysuiTestCase() {
+
+    @Test
+    fun expanding_squishiness1() {
+        assertThat(QSSceneAdapter.State.Expanding(0.3f).squishiness).isEqualTo(1f)
+    }
+
     @Test
     fun expandingSpecialValues() {
         assertThat(QSSceneAdapter.State.QQS).isEqualTo(QSSceneAdapter.State.Expanding(0f))
@@ -41,4 +47,11 @@
         assertThat(Collapsing(collapsingProgress))
             .isEqualTo(QSSceneAdapter.State.Expanding(1 - collapsingProgress))
     }
+
+    @Test
+    fun unsquishing_expansionSameAsQQS() {
+        val squishiness = 0.6f
+        assertThat(QSSceneAdapter.State.Unsquishing(squishiness).expansion)
+            .isEqualTo(QSSceneAdapter.State.QQS.expansion)
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagDependenciesBase.kt b/packages/SystemUI/src/com/android/systemui/flags/FlagDependenciesBase.kt
index efbd59f..2fe1dd4 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FlagDependenciesBase.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/FlagDependenciesBase.kt
@@ -19,6 +19,7 @@
 import android.app.Notification
 import android.app.NotificationChannel
 import android.app.NotificationManager
+import android.app.NotificationManager.IMPORTANCE_DEFAULT
 import android.content.Context
 import android.util.Log
 import com.android.systemui.CoreStartable
@@ -150,7 +151,7 @@
         val title = "Invalid flag dependencies: ${unmet.size}"
         val details = unmet.joinToString("\n") { it.shortUnmetString() }
         Log.e("FlagDependencies", "$title:\n$details")
-        val channel = NotificationChannel("FLAGS", "Flags", NotificationManager.IMPORTANCE_DEFAULT)
+        val channel = NotificationChannel(CHANNEL_ID, CHANNEL_NAME, IMPORTANCE_DEFAULT)
         val notification =
             Notification.Builder(context, channel.id)
                 .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
@@ -160,7 +161,18 @@
                 .setVisibility(Notification.VISIBILITY_PUBLIC)
                 .build()
         notifManager.createNotificationChannel(channel)
-        notifManager.notify("flags", 0, notification)
+        notifManager.notify(NOTIF_TAG, NOTIF_ID, notification)
+    }
+
+    override fun onCollected(all: List<FlagDependenciesBase.Dependency>) {
+        notifManager.cancel(NOTIF_TAG, NOTIF_ID)
+    }
+
+    companion object {
+        private const val CHANNEL_ID = "FLAGS"
+        private const val CHANNEL_NAME = "Flags"
+        private const val NOTIF_TAG = "FlagDependenciesNotifier"
+        private const val NOTIF_ID = 0
     }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java
index 8ff0e36..e5d970d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java
@@ -207,6 +207,9 @@
         mFooterActionsViewBinder = footerActionsViewBinder;
         mListeningAndVisibilityLifecycleOwner = new ListeningAndVisibilityLifecycleOwner();
         mSceneContainerFlags = sceneContainerFlags;
+        if (mSceneContainerFlags.isEnabled()) {
+            mStatusBarState = StatusBarState.SHADE;
+        }
     }
 
     /**
@@ -506,10 +509,20 @@
         }
     }
 
-    private boolean isKeyguardState() {
-        // We want the freshest state here since otherwise we'll have some weirdness if earlier
-        // listeners trigger updates
-        return mStatusBarStateController.getCurrentOrUpcomingState() == KEYGUARD;
+    @VisibleForTesting
+    boolean isKeyguardState() {
+        if (mSceneContainerFlags.isEnabled()) {
+            return false;
+        } else {
+            // We want the freshest state here since otherwise we'll have some weirdness if earlier
+            // listeners trigger updates
+            return mStatusBarStateController.getCurrentOrUpcomingState() == KEYGUARD;
+        }
+    }
+
+    @VisibleForTesting
+    int getStatusBarState() {
+        return mStatusBarState;
     }
 
     private void updateShowCollapsedOnKeyguard() {
@@ -562,15 +575,17 @@
     }
 
     private void setKeyguardShowing(boolean keyguardShowing) {
-        if (DEBUG) Log.d(TAG, "setKeyguardShowing " + keyguardShowing);
-        mLastQSExpansion = -1;
+        if (!mSceneContainerFlags.isEnabled()) {
+            if (DEBUG) Log.d(TAG, "setKeyguardShowing " + keyguardShowing);
+            mLastQSExpansion = -1;
 
-        if (mQSAnimator != null) {
-            mQSAnimator.setOnKeyguard(keyguardShowing);
+            if (mQSAnimator != null) {
+                mQSAnimator.setOnKeyguard(keyguardShowing);
+            }
+
+            mFooter.setKeyguardShowing(keyguardShowing);
+            updateQsState();
         }
-
-        mFooter.setKeyguardShowing(keyguardShowing);
-        updateQsState();
     }
 
     @Override
@@ -971,7 +986,7 @@
 
     @Override
     public void onStateChanged(int newState) {
-        if (newState == mStatusBarState) {
+        if (mSceneContainerFlags.isEnabled() || newState == mStatusBarState) {
             return;
         }
         mStatusBarState = newState;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt
index 6e4f72d..72a5c46 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt
@@ -84,18 +84,36 @@
      */
     val qsHeight: Int
 
-    sealed class State(
-        val isVisible: Boolean,
-        val expansion: Float,
-    ) {
-        data object CLOSED : State(false, 0f)
-        data class Expanding(val progress: Float) : State(true, progress)
+    sealed interface State {
+
+        val isVisible: Boolean
+        val expansion: Float
+        val squishiness: Float
+
+        data object CLOSED : State {
+            override val isVisible = false
+            override val expansion = 0f
+            override val squishiness = 1f
+        }
+
+        /** State for expanding between QQS and QS */
+        data class Expanding(override val expansion: Float) : State {
+            override val isVisible = true
+            override val squishiness = 1f
+        }
+
+        /** State for appearing QQS from Lockscreen or Gone */
+        data class Unsquishing(override val squishiness: Float) : State {
+            override val isVisible = true
+            override val expansion = 0f
+        }
 
         companion object {
             // These are special cases of the expansion.
             val QQS = Expanding(0f)
             val QS = Expanding(1f)
 
+            /** Collapsing from QS to QQS. [progress] is 0f in QS and 1f in QQS. */
             fun Collapsing(progress: Float) = Expanding(1f - progress)
         }
     }
@@ -232,7 +250,7 @@
         setQsVisible(state.isVisible)
         setExpanded(state.isVisible)
         setListening(state.isVisible)
-        setQsExpansion(state.expansion, 1f, 0f, 1f)
-        setTransitionToFullShadeProgress(false, 1f, 1f)
+        setQsExpansion(state.expansion, 1f, 0f, state.squishiness)
+        setTransitionToFullShadeProgress(false, 1f, state.squishiness)
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt
index 4ccb18f..8408c51 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlags.kt
@@ -29,6 +29,7 @@
 import com.android.systemui.flags.FlagToken
 import com.android.systemui.flags.Flags.SCENE_CONTAINER_ENABLED
 import com.android.systemui.flags.RefactorFlagUtils
+import com.android.systemui.keyguard.shared.ComposeLockscreen
 import com.android.systemui.media.controls.util.MediaInSceneContainerFlag
 import dagger.Module
 import dagger.Provides
@@ -45,6 +46,7 @@
             sceneContainer() && // mainAconfigFlag
                 keyguardBottomAreaRefactor() &&
                 migrateClocksToBlueprint() &&
+                ComposeLockscreen.isEnabled &&
                 MediaInSceneContainerFlag.isEnabled &&
                 // NOTE: Changes should also be made in getSecondaryFlags and @EnableSceneContainer
                 ComposeFacade.isComposeAvailable()
@@ -65,6 +67,7 @@
         sequenceOf(
             FlagToken(FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR, keyguardBottomAreaRefactor()),
             FlagToken(FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT, migrateClocksToBlueprint()),
+            ComposeLockscreen.token,
             MediaInSceneContainerFlag.token,
             // NOTE: Changes should also be made in isEnabled and @EnableSceneContainer
         )
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSImplTest.java
index 563a3fe..8e72d06 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSImplTest.java
@@ -20,6 +20,7 @@
 
 import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
 import static com.android.systemui.statusbar.StatusBarState.SHADE;
+import static com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -511,6 +512,28 @@
         );
     }
 
+    @Test
+    public void testSceneContainerFlagsEnabled_statusBarStateIsShade() {
+        when(mSceneContainerFlags.isEnabled()).thenReturn(true);
+
+        mUnderTest.onStateChanged(KEYGUARD);
+        assertThat(mUnderTest.getStatusBarState()).isEqualTo(SHADE);
+
+        mUnderTest.onStateChanged(SHADE_LOCKED);
+        assertThat(mUnderTest.getStatusBarState()).isEqualTo(SHADE);
+    }
+
+    @Test
+    public void testSceneContainerFlagsEnabled_isKeyguardState_alwaysFalse() {
+        when(mSceneContainerFlags.isEnabled()).thenReturn(true);
+
+        mUnderTest.onStateChanged(KEYGUARD);
+        assertThat(mUnderTest.isKeyguardState()).isFalse();
+
+        when(mStatusBarStateController.getCurrentOrUpcomingState()).thenReturn(KEYGUARD);
+        assertThat(mUnderTest.isKeyguardState()).isFalse();
+    }
+
     private QSImpl instantiate() {
         setupQsComponent();
         setUpViews();
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/EnableSceneContainer.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/EnableSceneContainer.kt
index 43897c9..cceb3ff 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/EnableSceneContainer.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/EnableSceneContainer.kt
@@ -17,9 +17,10 @@
 package com.android.systemui.flags
 
 import android.platform.test.annotations.EnableFlags
+import com.android.systemui.Flags.FLAG_COMPOSE_LOCKSCREEN
 import com.android.systemui.Flags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR
-import com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT
 import com.android.systemui.Flags.FLAG_MEDIA_IN_SCENE_CONTAINER
+import com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT
 import com.android.systemui.Flags.FLAG_SCENE_CONTAINER
 
 /**
@@ -30,6 +31,7 @@
     FLAG_SCENE_CONTAINER,
     FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR,
     FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT,
+    FLAG_COMPOSE_LOCKSCREEN,
     FLAG_MEDIA_IN_SCENE_CONTAINER,
 )
 @Retention(AnnotationRetention.RUNTIME)
diff --git a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java
index 0bcb26d..252ea4b 100644
--- a/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java
+++ b/services/core/java/com/android/server/grammaticalinflection/GrammaticalInflectionService.java
@@ -222,7 +222,7 @@
         }
 
         final int uid = mPackageManagerInternal.getPackageUid(appPackageName, 0, userId);
-        FrameworkStatsLog.write(FrameworkStatsLog.GRAMMATICAL_INFLECTION_CHANGED,
+        FrameworkStatsLog.write(FrameworkStatsLog.APPLICATION_GRAMMATICAL_INFLECTION_CHANGED,
                 FrameworkStatsLog.APPLICATION_GRAMMATICAL_INFLECTION_CHANGED__SOURCE_ID__OTHERS,
                 uid,
                 gender != GRAMMATICAL_GENDER_NOT_SPECIFIED,
@@ -266,8 +266,14 @@
 
         try {
             Configuration config = new Configuration();
+            int preValue = config.getGrammaticalGender();
             config.setGrammaticalGender(grammaticalGender);
             ActivityTaskManager.getService().updateConfiguration(config);
+            FrameworkStatsLog.write(FrameworkStatsLog.SYSTEM_GRAMMATICAL_INFLECTION_CHANGED,
+                    FrameworkStatsLog.SYSTEM_GRAMMATICAL_INFLECTION_CHANGED__SOURCE_ID__SYSTEM,
+                    userId,
+                    grammaticalGender != GRAMMATICAL_GENDER_NOT_SPECIFIED,
+                    preValue != GRAMMATICAL_GENDER_NOT_SPECIFIED);
         } catch (RemoteException e) {
             Log.w(TAG, "Can not update configuration", e);
         }