Merge "Enable NOTIFICATION_SHELF_REFACTOR for Teamfood" into udc-dev
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 6592019..f673304 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -822,6 +822,10 @@
      */
     @TestApi
     public boolean isLockscreenLiveWallpaperEnabled() {
+        return isLockscreenLiveWallpaperEnabledHelper();
+    }
+
+    private static boolean isLockscreenLiveWallpaperEnabledHelper() {
         if (sGlobals == null) {
             sIsLockscreenLiveWallpaperEnabled = SystemProperties.getBoolean(
                     "persist.wm.debug.lockscreen_live_wallpaper", false);
@@ -2757,7 +2761,7 @@
     public static InputStream openDefaultWallpaper(Context context, @SetWallpaperFlags int which) {
         final String whichProp;
         final int defaultResId;
-        if (which == FLAG_LOCK && !sIsLockscreenLiveWallpaperEnabled) {
+        if (which == FLAG_LOCK && !isLockscreenLiveWallpaperEnabledHelper()) {
             /* Factory-default lock wallpapers are not yet supported
             whichProp = PROP_LOCK_WALLPAPER;
             defaultResId = com.android.internal.R.drawable.default_lock_wallpaper;
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 1ba84c5..d802b46 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -502,6 +502,8 @@
 
     boolean hasSystemFeature(String name, int version);
 
+    List<String> getInitialNonStoppedSystemPackages();
+
     void enterSafeMode();
     @UnsupportedAppUsage
     boolean isSafeMode();
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 295df5c..be40143 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -50,7 +50,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
 
-import java.lang.IllegalArgumentException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
@@ -285,6 +284,12 @@
      */
     public static final int DISABLED_REASON_OTHER_RESTORE_ISSUE = 103;
 
+    /**
+     * The maximum length of Shortcut ID. IDs will be truncated at this limit.
+     * @hide
+     */
+    public static final int MAX_ID_LENGTH = 1000;
+
     /** @hide */
     @IntDef(prefix = { "DISABLED_REASON_" }, value = {
             DISABLED_REASON_NOT_DISABLED,
@@ -477,8 +482,7 @@
 
     private ShortcutInfo(Builder b) {
         mUserId = b.mContext.getUserId();
-
-        mId = Preconditions.checkStringNotEmpty(b.mId, "Shortcut ID must be provided");
+        mId = getSafeId(Preconditions.checkStringNotEmpty(b.mId, "Shortcut ID must be provided"));
 
         // Note we can't do other null checks here because SM.updateShortcuts() takes partial
         // information.
@@ -584,6 +588,14 @@
         return ret;
     }
 
+    @NonNull
+    private static String getSafeId(@NonNull String id) {
+        if (id.length() > MAX_ID_LENGTH) {
+            return id.substring(0, MAX_ID_LENGTH);
+        }
+        return id;
+    }
+
     /**
      * Throws if any of the mandatory fields is not set.
      *
@@ -2342,7 +2354,8 @@
         final ClassLoader cl = getClass().getClassLoader();
 
         mUserId = source.readInt();
-        mId = source.readString8();
+        mId = getSafeId(Preconditions.checkStringNotEmpty(source.readString8(),
+                "Shortcut ID must be provided"));
         mPackageName = source.readString8();
         mActivity = source.readParcelable(cl, android.content.ComponentName.class);
         mFlags = source.readInt();
diff --git a/core/java/android/hardware/soundtrigger/ConversionUtil.java b/core/java/android/hardware/soundtrigger/ConversionUtil.java
index 888047d..21fe686 100644
--- a/core/java/android/hardware/soundtrigger/ConversionUtil.java
+++ b/core/java/android/hardware/soundtrigger/ConversionUtil.java
@@ -32,10 +32,12 @@
 import android.media.soundtrigger.RecognitionEvent;
 import android.media.soundtrigger.RecognitionMode;
 import android.media.soundtrigger.SoundModel;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
 import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
 import android.os.ParcelFileDescriptor;
-import android.system.ErrnoException;
 import android.os.SharedMemory;
+import android.system.ErrnoException;
 
 import java.nio.ByteBuffer;
 import java.util.Arrays;
@@ -219,36 +221,40 @@
         return new SoundTrigger.ConfidenceLevel(apiLevel.userId, apiLevel.levelPercent);
     }
 
-    public static SoundTrigger.RecognitionEvent aidl2apiRecognitionEvent(
-            int modelHandle, int captureSession, RecognitionEvent aidlEvent) {
+    public static SoundTrigger.RecognitionEvent aidl2apiRecognitionEvent(int modelHandle,
+            int captureSession, RecognitionEventSys aidlEvent) {
+        RecognitionEvent recognitionEvent = aidlEvent.recognitionEvent;
         // The API recognition event doesn't allow for a null audio format, even though it doesn't
         // always make sense. We thus replace it with a default.
-        AudioFormat audioFormat = aidl2apiAudioFormatWithDefault(aidlEvent.audioConfig,
+        AudioFormat audioFormat = aidl2apiAudioFormatWithDefault(recognitionEvent.audioConfig,
                 true /*isInput*/);
-        // TODO(b/265852186) propagate a timestamp from aidl interfaces
-        return new SoundTrigger.GenericRecognitionEvent(aidlEvent.status, modelHandle,
-                aidlEvent.captureAvailable, captureSession, aidlEvent.captureDelayMs,
-                aidlEvent.capturePreambleMs, aidlEvent.triggerInData, audioFormat, aidlEvent.data,
-                aidlEvent.recognitionStillActive, -1 /* halEventReceivedMillis */);
+        return new SoundTrigger.GenericRecognitionEvent(recognitionEvent.status, modelHandle,
+                recognitionEvent.captureAvailable, captureSession, recognitionEvent.captureDelayMs,
+                recognitionEvent.capturePreambleMs, recognitionEvent.triggerInData, audioFormat,
+                recognitionEvent.data,
+                recognitionEvent.recognitionStillActive, aidlEvent.halEventReceivedMillis);
     }
 
     public static SoundTrigger.RecognitionEvent aidl2apiPhraseRecognitionEvent(
-            int modelHandle, int captureSession,
-            PhraseRecognitionEvent aidlEvent) {
+            int modelHandle, int captureSession, PhraseRecognitionEventSys aidlEvent) {
+        PhraseRecognitionEvent recognitionEvent = aidlEvent.phraseRecognitionEvent;
         SoundTrigger.KeyphraseRecognitionExtra[] apiExtras =
-                new SoundTrigger.KeyphraseRecognitionExtra[aidlEvent.phraseExtras.length];
-        for (int i = 0; i < aidlEvent.phraseExtras.length; ++i) {
-            apiExtras[i] = aidl2apiPhraseRecognitionExtra(aidlEvent.phraseExtras[i]);
+                new SoundTrigger.KeyphraseRecognitionExtra[recognitionEvent.phraseExtras.length];
+        for (int i = 0; i < recognitionEvent.phraseExtras.length; ++i) {
+            apiExtras[i] = aidl2apiPhraseRecognitionExtra(recognitionEvent.phraseExtras[i]);
         }
         // The API recognition event doesn't allow for a null audio format, even though it doesn't
         // always make sense. We thus replace it with a default.
-        AudioFormat audioFormat = aidl2apiAudioFormatWithDefault(aidlEvent.common.audioConfig,
+        AudioFormat audioFormat = aidl2apiAudioFormatWithDefault(
+                recognitionEvent.common.audioConfig,
                 true /*isInput*/);
-        // TODO(b/265852186) propagate a timestamp from aidl interfaces
-        return new SoundTrigger.KeyphraseRecognitionEvent(aidlEvent.common.status, modelHandle,
-                aidlEvent.common.captureAvailable, captureSession, aidlEvent.common.captureDelayMs,
-                aidlEvent.common.capturePreambleMs, aidlEvent.common.triggerInData, audioFormat,
-                aidlEvent.common.data, apiExtras, -1 /* halEventReceivedMillis */);
+        return new SoundTrigger.KeyphraseRecognitionEvent(recognitionEvent.common.status,
+                modelHandle,
+                recognitionEvent.common.captureAvailable, captureSession,
+                recognitionEvent.common.captureDelayMs,
+                recognitionEvent.common.capturePreambleMs, recognitionEvent.common.triggerInData,
+                audioFormat,
+                recognitionEvent.common.data, apiExtras, aidlEvent.halEventReceivedMillis);
     }
 
     // In case of a null input returns a non-null valid output.
diff --git a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
index 37c5213..5cdbe23 100644
--- a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
+++ b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java
@@ -22,13 +22,13 @@
 import android.media.permission.ClearCallingIdentityContext;
 import android.media.permission.Identity;
 import android.media.permission.SafeCloseable;
-import android.media.soundtrigger.PhraseRecognitionEvent;
 import android.media.soundtrigger.PhraseSoundModel;
-import android.media.soundtrigger.RecognitionEvent;
 import android.media.soundtrigger.SoundModel;
 import android.media.soundtrigger_middleware.ISoundTriggerCallback;
 import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService;
 import android.media.soundtrigger_middleware.ISoundTriggerModule;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
 import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
@@ -398,7 +398,7 @@
         }
 
         @Override
-        public synchronized void onRecognition(int handle, RecognitionEvent event,
+        public synchronized void onRecognition(int handle, RecognitionEventSys event,
                 int captureSession)
                 throws RemoteException {
             Message m = mHandler.obtainMessage(EVENT_RECOGNITION,
@@ -407,7 +407,7 @@
         }
 
         @Override
-        public synchronized void onPhraseRecognition(int handle, PhraseRecognitionEvent event,
+        public synchronized void onPhraseRecognition(int handle, PhraseRecognitionEventSys event,
                 int captureSession)
                 throws RemoteException {
             Message m = mHandler.obtainMessage(EVENT_RECOGNITION,
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 4a46beb..329a2fa5 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7175,6 +7175,13 @@
         public static final String CREDENTIAL_SERVICE = "credential_service";
 
         /**
+         * The currently selected primary credential service flattened ComponentName.
+         *
+         * @hide
+         */
+        public static final String CREDENTIAL_SERVICE_PRIMARY = "credential_service_primary";
+
+        /**
          * The currently selected autofill service flattened ComponentName.
          * @hide
          */
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index e39b3a1..6ff4b74 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -1477,14 +1477,22 @@
         // to PCC classification service.
         if (AutofillFeatureFlags.isAutofillPccClassificationEnabled()) {
             synchronized (mLock) {
-                final boolean clientAdded = tryAddServiceClientIfNeededLocked();
-                if (clientAdded){
-                    startSessionLocked(/* id= */ AutofillId.NO_AUTOFILL_ID,
-                        /* bounds= */ null, /* value= */ null, /* flags= */ FLAG_PCC_DETECTION);
-                } else {
-                    if (sVerbose) {
-                        Log.v(TAG, "not starting session: no service client");
+                // If session has already been created, that'd mean we already have issued the
+                // detection request previously. It is possible in cases like autofocus that this
+                // method isn't invoked, so the server should still handle such cases where fill
+                // request comes in but PCC Detection hasn't been triggered. There is no benefit to
+                // trigger PCC Detection separately in those cases.
+                if (!isActiveLocked()) {
+                    final boolean clientAdded = tryAddServiceClientIfNeededLocked();
+                    if (clientAdded) {
+                        startSessionLocked(/* id= */ AutofillId.NO_AUTOFILL_ID, /* bounds= */ null,
+                                /* value= */ null, /* flags= */ FLAG_PCC_DETECTION);
+                    } else {
+                        if (sVerbose) {
+                            Log.v(TAG, "not starting session: no service client");
+                        }
                     }
+
                 }
             }
         }
diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp
index 6fcff99..0f41229 100644
--- a/core/jni/android_view_InputEventReceiver.cpp
+++ b/core/jni/android_view_InputEventReceiver.cpp
@@ -374,7 +374,7 @@
                     }
                     inputEventObj =
                             android_view_KeyEvent_fromNative(env,
-                                                             static_cast<KeyEvent*>(inputEvent));
+                                                             static_cast<KeyEvent&>(*inputEvent));
                     break;
 
                 case InputEventType::MOTION: {
diff --git a/core/jni/android_view_InputEventSender.cpp b/core/jni/android_view_InputEventSender.cpp
index ad54004..15270ef 100644
--- a/core/jni/android_view_InputEventSender.cpp
+++ b/core/jni/android_view_InputEventSender.cpp
@@ -353,8 +353,7 @@
         jint seq, jobject eventObj) {
     sp<NativeInputEventSender> sender =
             reinterpret_cast<NativeInputEventSender*>(senderPtr);
-    KeyEvent event;
-    android_view_KeyEvent_toNative(env, eventObj, &event);
+    const KeyEvent event = android_view_KeyEvent_toNative(env, eventObj);
     status_t status = sender->sendKeyEvent(seq, &event);
     return !status;
 }
diff --git a/core/jni/android_view_InputQueue.cpp b/core/jni/android_view_InputQueue.cpp
index 2c4966e..21db37e 100644
--- a/core/jni/android_view_InputQueue.cpp
+++ b/core/jni/android_view_InputQueue.cpp
@@ -221,12 +221,7 @@
         jboolean predispatch) {
     InputQueue* queue = reinterpret_cast<InputQueue*>(ptr);
     KeyEvent* event = queue->createKeyEvent();
-    status_t status = android_view_KeyEvent_toNative(env, eventObj, event);
-    if (status) {
-        queue->recycleInputEvent(event);
-        jniThrowRuntimeException(env, "Could not read contents of KeyEvent object.");
-        return -1;
-    }
+    *event = android_view_KeyEvent_toNative(env, eventObj);
 
     if (predispatch) {
         event->setFlags(event->getFlags() | AKEY_EVENT_FLAG_PREDISPATCH);
diff --git a/core/jni/android_view_KeyCharacterMap.cpp b/core/jni/android_view_KeyCharacterMap.cpp
index 469e577..8fa03cf 100644
--- a/core/jni/android_view_KeyCharacterMap.cpp
+++ b/core/jni/android_view_KeyCharacterMap.cpp
@@ -217,7 +217,7 @@
         result = env->NewObjectArray(jsize(events.size()), gKeyEventClassInfo.clazz, NULL);
         if (result) {
             for (size_t i = 0; i < events.size(); i++) {
-                jobject keyEventObj = android_view_KeyEvent_fromNative(env, &events.itemAt(i));
+                jobject keyEventObj = android_view_KeyEvent_fromNative(env, events.itemAt(i));
                 if (!keyEventObj) break; // threw OOM exception
                 env->SetObjectArrayElement(result, jsize(i), keyEventObj);
                 env->DeleteLocalRef(keyEventObj);
diff --git a/core/jni/android_view_KeyEvent.cpp b/core/jni/android_view_KeyEvent.cpp
index d5568df..a9c9919 100644
--- a/core/jni/android_view_KeyEvent.cpp
+++ b/core/jni/android_view_KeyEvent.cpp
@@ -94,16 +94,16 @@
 
 // ----------------------------------------------------------------------------
 
-jobject android_view_KeyEvent_fromNative(JNIEnv* env, const KeyEvent* event) {
-    ScopedLocalRef<jbyteArray> hmac = toJbyteArray(env, event->getHmac());
+jobject android_view_KeyEvent_fromNative(JNIEnv* env, const KeyEvent& event) {
+    ScopedLocalRef<jbyteArray> hmac = toJbyteArray(env, event.getHmac());
     jobject eventObj =
             env->CallStaticObjectMethod(gKeyEventClassInfo.clazz, gKeyEventClassInfo.obtain,
-                                        event->getId(), event->getDownTime(), event->getEventTime(),
-                                        event->getAction(), event->getKeyCode(),
-                                        event->getRepeatCount(), event->getMetaState(),
-                                        event->getDeviceId(), event->getScanCode(),
-                                        event->getFlags(), event->getSource(),
-                                        event->getDisplayId(), hmac.get(), nullptr);
+                                        event.getId(), event.getDownTime(), event.getEventTime(),
+                                        event.getAction(), event.getKeyCode(),
+                                        event.getRepeatCount(), event.getMetaState(),
+                                        event.getDeviceId(), event.getScanCode(), event.getFlags(),
+                                        event.getSource(), event.getDisplayId(), hmac.get(),
+                                        nullptr);
     if (env->ExceptionCheck()) {
         ALOGE("An exception occurred while obtaining a key event.");
         LOGE_EX(env);
@@ -113,8 +113,7 @@
     return eventObj;
 }
 
-status_t android_view_KeyEvent_toNative(JNIEnv* env, jobject eventObj,
-        KeyEvent* event) {
+KeyEvent android_view_KeyEvent_toNative(JNIEnv* env, jobject eventObj) {
     jint id = env->GetIntField(eventObj, gKeyEventClassInfo.mId);
     jint deviceId = env->GetIntField(eventObj, gKeyEventClassInfo.mDeviceId);
     jint source = env->GetIntField(eventObj, gKeyEventClassInfo.mSource);
@@ -133,9 +132,10 @@
     jlong downTime = env->GetLongField(eventObj, gKeyEventClassInfo.mDownTime);
     jlong eventTime = env->GetLongField(eventObj, gKeyEventClassInfo.mEventTime);
 
-    event->initialize(id, deviceId, source, displayId, *hmac, action, flags, keyCode, scanCode,
-                      metaState, repeatCount, downTime, eventTime);
-    return OK;
+    KeyEvent event;
+    event.initialize(id, deviceId, source, displayId, *hmac, action, flags, keyCode, scanCode,
+                     metaState, repeatCount, downTime, eventTime);
+    return event;
 }
 
 status_t android_view_KeyEvent_recycle(JNIEnv* env, jobject eventObj) {
diff --git a/core/jni/android_view_KeyEvent.h b/core/jni/android_view_KeyEvent.h
index dab6bb7..bc4876a 100644
--- a/core/jni/android_view_KeyEvent.h
+++ b/core/jni/android_view_KeyEvent.h
@@ -27,12 +27,11 @@
 
 /* Obtains an instance of a DVM KeyEvent object as a copy of a native KeyEvent instance.
  * Returns NULL on error. */
-extern jobject android_view_KeyEvent_fromNative(JNIEnv* env, const KeyEvent* event);
+extern jobject android_view_KeyEvent_fromNative(JNIEnv* env, const KeyEvent& event);
 
 /* Copies the contents of a DVM KeyEvent object to a native KeyEvent instance.
  * Returns non-zero on error. */
-extern status_t android_view_KeyEvent_toNative(JNIEnv* env, jobject eventObj,
-        KeyEvent* event);
+extern KeyEvent android_view_KeyEvent_toNative(JNIEnv* env, jobject eventObj);
 
 /* Recycles a DVM KeyEvent object.
  * Key events should only be recycled if they are owned by the system since user
diff --git a/core/proto/android/companion/telecom.proto b/core/proto/android/companion/telecom.proto
index 3a9e5ee..02ba7c5 100644
--- a/core/proto/android/companion/telecom.proto
+++ b/core/proto/android/companion/telecom.proto
@@ -25,7 +25,7 @@
   // Next index: 6
   message Call {
     // UUID representing this call
-    int64 id = 1;
+    string id = 1;
 
     message Origin {
       // Caller's name and/or phone number; what a user would see displayed when receiving an
@@ -48,22 +48,23 @@
     }
     Status status = 3;
 
-    enum Control {
-      UNKNOWN_CONTROL = 0;
-      ACCEPT = 1;
-      REJECT = 2;
-      SILENCE = 3;
-      MUTE = 4;
-      UNMUTE = 5;
-      END = 6;
-      PUT_ON_HOLD = 7;
-      TAKE_OFF_HOLD = 8;
-      REJECT_AND_BLOCK = 9;
-      IGNORE = 10;
-    }
     repeated Control controls = 4;
   }
 
+  enum Control {
+    UNKNOWN_CONTROL = 0;
+    ACCEPT = 1;
+    REJECT = 2;
+    SILENCE = 3;
+    MUTE = 4;
+    UNMUTE = 5;
+    END = 6;
+    PUT_ON_HOLD = 7;
+    TAKE_OFF_HOLD = 8;
+    REJECT_AND_BLOCK = 9;
+    IGNORE = 10;
+  }
+
   // The list of active calls.
   repeated Call calls = 1;
   // The list of requested calls or call changes.
diff --git a/core/res/res/drawable-hdpi/pointer_context_menu.png b/core/res/res/drawable-hdpi/pointer_context_menu.png
index c45d29b..60d37c4 100644
--- a/core/res/res/drawable-hdpi/pointer_context_menu.png
+++ b/core/res/res/drawable-hdpi/pointer_context_menu.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/pointer_help.png b/core/res/res/drawable-hdpi/pointer_help.png
index a3afdb6..2d9d20c 100644
--- a/core/res/res/drawable-hdpi/pointer_help.png
+++ b/core/res/res/drawable-hdpi/pointer_help.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_context_menu.png b/core/res/res/drawable-mdpi/pointer_context_menu.png
index e0e849d..d87d040 100644
--- a/core/res/res/drawable-mdpi/pointer_context_menu.png
+++ b/core/res/res/drawable-mdpi/pointer_context_menu.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_context_menu_large.png b/core/res/res/drawable-mdpi/pointer_context_menu_large.png
index e8c9be4..15266a6 100644
--- a/core/res/res/drawable-mdpi/pointer_context_menu_large.png
+++ b/core/res/res/drawable-mdpi/pointer_context_menu_large.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_help.png b/core/res/res/drawable-mdpi/pointer_help.png
index 286242c..bd04bbd 100644
--- a/core/res/res/drawable-mdpi/pointer_help.png
+++ b/core/res/res/drawable-mdpi/pointer_help.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_help_large.png b/core/res/res/drawable-mdpi/pointer_help_large.png
index 27f4a84..f9bd2b7 100644
--- a/core/res/res/drawable-mdpi/pointer_help_large.png
+++ b/core/res/res/drawable-mdpi/pointer_help_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_context_menu.png b/core/res/res/drawable-xhdpi/pointer_context_menu.png
index d4b2bde..15d1e33 100644
--- a/core/res/res/drawable-xhdpi/pointer_context_menu.png
+++ b/core/res/res/drawable-xhdpi/pointer_context_menu.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_context_menu_large.png b/core/res/res/drawable-xhdpi/pointer_context_menu_large.png
index 977df10..e4ff7a6 100644
--- a/core/res/res/drawable-xhdpi/pointer_context_menu_large.png
+++ b/core/res/res/drawable-xhdpi/pointer_context_menu_large.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_help.png b/core/res/res/drawable-xhdpi/pointer_help.png
index 5a6805c..952a4ee 100644
--- a/core/res/res/drawable-xhdpi/pointer_help.png
+++ b/core/res/res/drawable-xhdpi/pointer_help.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_help_large.png b/core/res/res/drawable-xhdpi/pointer_help_large.png
index 4bdc3d1..1d68437 100644
--- a/core/res/res/drawable-xhdpi/pointer_help_large.png
+++ b/core/res/res/drawable-xhdpi/pointer_help_large.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/pointer_context_menu.png b/core/res/res/drawable-xxhdpi/pointer_context_menu.png
index 6ebfaab..4cd20f5 100644
--- a/core/res/res/drawable-xxhdpi/pointer_context_menu.png
+++ b/core/res/res/drawable-xxhdpi/pointer_context_menu.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/pointer_help.png b/core/res/res/drawable-xxhdpi/pointer_help.png
index 96b2a71..0c7a264 100644
--- a/core/res/res/drawable-xxhdpi/pointer_help.png
+++ b/core/res/res/drawable-xxhdpi/pointer_help.png
Binary files differ
diff --git a/core/res/res/drawable/pointer_context_menu_large_icon.xml b/core/res/res/drawable/pointer_context_menu_large_icon.xml
index e07e5b6..325ea669 100644
--- a/core/res/res/drawable/pointer_context_menu_large_icon.xml
+++ b/core/res/res/drawable/pointer_context_menu_large_icon.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
     android:bitmap="@drawable/pointer_context_menu_large"
-    android:hotSpotX="13.5dp"
-    android:hotSpotY="10.5dp" />
+    android:hotSpotX="10.5dp"
+    android:hotSpotY="8dp" />
diff --git a/core/res/res/drawable/pointer_help_large_icon.xml b/core/res/res/drawable/pointer_help_large_icon.xml
index 43a1261..20f0c5336 100644
--- a/core/res/res/drawable/pointer_help_large_icon.xml
+++ b/core/res/res/drawable/pointer_help_large_icon.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
     android:bitmap="@drawable/pointer_help_large"
-    android:hotSpotX="13.5dp"
-    android:hotSpotY="10.5dp" />
+    android:hotSpotX="10.5dp"
+    android:hotSpotY="8dp" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 7bc3ab8..50aec83 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -991,6 +991,25 @@
         <!-- Nominal White Z --> <item>1.089058</item>
     </string-array>
 
+    <!-- The CCT closest to the white coordinates (primary) above and in SurfaceControl. -->
+    <integer name="config_displayWhiteBalanceDisplayNominalWhiteCct">6500</integer>
+
+    <!-- Range minimums corresponding to config_displayWhiteBalanceDisplaySteps. For example, if the
+         range minimums are [0, 3000] and the steps are [10, 20] then between 0 and 3000, exclusive,
+         the step between them will be 10 (i.e. 0, 10, 20, etc.) and the step between 3000 and the
+         maximum value is 20 (i.e. 3000, 3020, 3040, etc.). -->
+    <integer-array name="config_displayWhiteBalanceDisplayRangeMinimums">
+        <item>0</item>
+    </integer-array>
+
+    <!-- Steps corresponding to config_displayWhiteBalanceDisplayRangeMinimums. For example, if the
+         range minimums are [0, 3000] and the steps are [10, 20] then between 0 and 3000, exclusive,
+         the step between them will be 10 (i.e. 0, 10, 20, etc.) and the step between 3000 and the
+         maximum value is 20 (i.e. 3000, 3020, 3040, etc.). -->
+    <integer-array name="config_displayWhiteBalanceDisplaySteps">
+        <item>1</item>
+    </integer-array>
+
     <!-- Boolean indicating whether light mode is allowed when DWB is turned on. -->
     <bool name="config_displayWhiteBalanceLightModeAllowed">true</bool>
 
@@ -6396,7 +6415,7 @@
         Packages can be added by OEMs in an allowlist, to prevent them from being scanned as
         "stopped" during initial boot of a device, or after an OTA update. Stopped state of
         an app is not changed during subsequent reboots.  -->
-    <bool name="config_stopSystemPackagesByDefault">false</bool>
+    <bool name="config_stopSystemPackagesByDefault">true</bool>
 
     <!-- Whether to show weather on the lock screen by default. -->
     <bool name="config_lockscreenWeatherEnabledByDefault">false</bool>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e25425d..218bbc2 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3423,6 +3423,9 @@
   <java-symbol type="integer" name="config_displayWhiteBalanceColorTemperatureDefault" />
   <java-symbol type="array" name="config_displayWhiteBalanceDisplayPrimaries" />
   <java-symbol type="array" name="config_displayWhiteBalanceDisplayNominalWhite" />
+  <java-symbol type="integer" name="config_displayWhiteBalanceDisplayNominalWhiteCct" />
+  <java-symbol type="array" name="config_displayWhiteBalanceDisplayRangeMinimums" />
+  <java-symbol type="array" name="config_displayWhiteBalanceDisplaySteps" />
   <java-symbol type="bool" name="config_displayWhiteBalanceLightModeAllowed" />
   <java-symbol type="integer" name="config_displayWhiteBalanceTransitionTime" />
 
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 40cb7f2..1f1239e 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -520,6 +520,10 @@
         <permission name="android.permission.SOUND_TRIGGER_RUN_IN_BATTERY_SAVER"/>
         <!-- Permission required for CTS test - SatelliteManagerTest -->
         <permission name="android.permission.SATELLITE_COMMUNICATION"/>
+        <!-- Permission required for GTS test - GtsAttestationVerificationDeviceSideTestCases -->
+        <permission name="android.permission.USE_ATTESTATION_VERIFICATION_SERVICE" />
+        <!-- Permission required for GTS test - GtsCredentialsTestCases -->
+        <permission name="android.permission.LAUNCH_CREDENTIAL_SELECTOR"/>
     </privapp-permissions>
 
     <privapp-permissions package="com.android.statementservice">
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index 6a79bc1..54978bd 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -125,34 +125,6 @@
 
 // End ProtoLog
 
-gensrcs {
-    name: "wm-shell-protos",
-
-    tools: [
-        "aprotoc",
-        "protoc-gen-javastream",
-        "soong_zip",
-    ],
-
-    tool_files: [
-        ":libprotobuf-internal-protos",
-    ],
-
-    cmd: "mkdir -p $(genDir)/$(in) " +
-        "&& $(location aprotoc) " +
-        "  --plugin=$(location protoc-gen-javastream) " +
-        "  --javastream_out=$(genDir)/$(in) " +
-        "  -Iexternal/protobuf/src " +
-        "  -I . " +
-        "  $(in) " +
-        "&& $(location soong_zip) -jar -o $(out) -C $(genDir)/$(in) -D $(genDir)/$(in)",
-
-    srcs: [
-        "proto/**/*.proto",
-    ],
-    output_extension: "srcjar",
-}
-
 java_library {
     name: "WindowManager-Shell-proto",
 
@@ -170,7 +142,6 @@
         // TODO(b/168581922) protologtool do not support kotlin(*.kt)
         ":wm_shell-sources-kt",
         ":wm_shell-aidls",
-        ":wm-shell-protos",
     ],
     resource_dirs: [
         "res",
diff --git a/libs/WindowManager/Shell/res/color/taskbar_background.xml b/libs/WindowManager/Shell/res/color/taskbar_background.xml
deleted file mode 100644
index 876ee02..0000000
--- a/libs/WindowManager/Shell/res/color/taskbar_background.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.
-  -->
-<!-- Should be the same as in packages/apps/Launcher3/res/color-v31/taskbar_background.xml -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="@android:color/system_neutral1_500" android:lStar="98" />
-</selector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/color-night/taskbar_background.xml b/libs/WindowManager/Shell/res/color/taskbar_background_dark.xml
similarity index 100%
rename from libs/WindowManager/Shell/res/color-night/taskbar_background.xml
rename to libs/WindowManager/Shell/res/color/taskbar_background_dark.xml
diff --git a/libs/WindowManager/Shell/res/values-night/colors.xml b/libs/WindowManager/Shell/res/values-night/colors.xml
index 5c6bb57..83c4d93 100644
--- a/libs/WindowManager/Shell/res/values-night/colors.xml
+++ b/libs/WindowManager/Shell/res/values-night/colors.xml
@@ -15,7 +15,6 @@
   -->
 
 <resources>
-    <color name="docked_divider_handle">#ffffff</color>
     <!-- Bubbles -->
     <color name="bubbles_icon_tint">@color/GM2_grey_200</color>
     <!-- Splash screen-->
diff --git a/libs/WindowManager/Shell/res/values/colors.xml b/libs/WindowManager/Shell/res/values/colors.xml
index c487e4a..54a8f33 100644
--- a/libs/WindowManager/Shell/res/values/colors.xml
+++ b/libs/WindowManager/Shell/res/values/colors.xml
@@ -17,8 +17,8 @@
  */
 -->
 <resources>
-    <color name="docked_divider_handle">#000000</color>
-    <color name="split_divider_background">@color/taskbar_background</color>
+    <color name="docked_divider_handle">#ffffff</color>
+    <color name="split_divider_background">@color/taskbar_background_dark</color>
     <drawable name="forced_resizable_background">#59000000</drawable>
     <color name="minimize_dock_shadow_start">#60000000</color>
     <color name="minimize_dock_shadow_end">#00000000</color>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index f3efaad..e7ec7aa 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -3320,7 +3320,9 @@
      * @return the normalized x-axis position of the bubble stack rounded to 4 decimal places.
      */
     public float getNormalizedXPosition() {
-        return new BigDecimal(getStackPosition().x / mPositioner.getAvailableRect().width())
+        int width = mPositioner.getAvailableRect().width();
+        float stackPosition = width > 0 ? getStackPosition().x / width : 0;
+        return new BigDecimal(stackPosition)
                 .setScale(4, RoundingMode.CEILING.HALF_UP)
                 .floatValue();
     }
@@ -3329,7 +3331,9 @@
      * @return the normalized y-axis position of the bubble stack rounded to 4 decimal places.
      */
     public float getNormalizedYPosition() {
-        return new BigDecimal(getStackPosition().y / mPositioner.getAvailableRect().height())
+        int height = mPositioner.getAvailableRect().height();
+        float stackPosition = height > 0 ? getStackPosition().y / height : 0;
+        return new BigDecimal(stackPosition)
                 .setScale(4, RoundingMode.CEILING.HALF_UP)
                 .floatValue();
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
index fb0a91f..0f0d572 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
@@ -162,7 +162,7 @@
     /**
      * Release the indicator and its components when it is no longer needed.
      */
-    public void releaseVisualIndicator() {
+    public void releaseVisualIndicator(SurfaceControl.Transaction t) {
         if (mViewHost == null) return;
         if (mViewHost != null) {
             mViewHost.release();
@@ -170,13 +170,8 @@
         }
 
         if (mLeash != null) {
-            final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
             t.remove(mLeash);
             mLeash = null;
-            mSyncQueue.runInSync(transaction -> {
-                transaction.merge(t);
-                t.close();
-            });
         }
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 73a0e36..ee94f30 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -78,6 +78,11 @@
 
     private val desktopMode: DesktopModeImpl
     private var visualIndicator: DesktopModeVisualIndicator? = null
+    private val mOnAnimationFinishedCallback = Consumer<SurfaceControl.Transaction> {
+        t: SurfaceControl.Transaction ->
+        visualIndicator?.releaseVisualIndicator(t)
+        visualIndicator = null
+    }
 
     init {
         desktopMode = DesktopModeImpl()
@@ -154,14 +159,14 @@
 
         if (Transitions.ENABLE_SHELL_TRANSITIONS) {
             enterDesktopTaskTransitionHandler.startTransition(
-                    Transitions.TRANSIT_ENTER_FREEFORM, wct)
+                    Transitions.TRANSIT_ENTER_FREEFORM, wct, mOnAnimationFinishedCallback)
         } else {
             shellTaskOrganizer.applyTransaction(wct)
         }
     }
 
     /** Brings apps to front and sets freeform task bounds */
-    fun moveToDesktopWithAnimation(
+    private fun moveToDesktopWithAnimation(
             taskInfo: RunningTaskInfo,
             freeformBounds: Rect
     ) {
@@ -172,9 +177,10 @@
 
         if (Transitions.ENABLE_SHELL_TRANSITIONS) {
             enterDesktopTaskTransitionHandler.startTransition(
-                Transitions.TRANSIT_ENTER_DESKTOP_MODE, wct)
+                Transitions.TRANSIT_ENTER_DESKTOP_MODE, wct, mOnAnimationFinishedCallback)
         } else {
             shellTaskOrganizer.applyTransaction(wct)
+            releaseVisualIndicator()
         }
     }
 
@@ -205,21 +211,24 @@
         val wct = WindowContainerTransaction()
         addMoveToFullscreenChanges(wct, task.token)
         if (Transitions.ENABLE_SHELL_TRANSITIONS) {
-            enterDesktopTaskTransitionHandler.startCancelMoveToDesktopMode(wct, startPosition)
+            enterDesktopTaskTransitionHandler.startCancelMoveToDesktopMode(wct, startPosition,
+                    mOnAnimationFinishedCallback)
         } else {
             shellTaskOrganizer.applyTransaction(wct)
+            releaseVisualIndicator()
         }
     }
 
-    fun moveToFullscreenWithAnimation(task: ActivityManager.RunningTaskInfo) {
+    private fun moveToFullscreenWithAnimation(task: ActivityManager.RunningTaskInfo) {
         val wct = WindowContainerTransaction()
         addMoveToFullscreenChanges(wct, task.token)
 
         if (Transitions.ENABLE_SHELL_TRANSITIONS) {
             exitDesktopTaskTransitionHandler.startTransition(
-            Transitions.TRANSIT_EXIT_DESKTOP_MODE, wct)
+            Transitions.TRANSIT_EXIT_DESKTOP_MODE, wct, mOnAnimationFinishedCallback)
         } else {
             shellTaskOrganizer.applyTransaction(wct)
+            releaseVisualIndicator()
         }
     }
 
@@ -330,6 +339,16 @@
             ?.let { homeTask -> wct.reorder(homeTask.getToken(), true /* onTop */) }
     }
 
+    private fun releaseVisualIndicator() {
+        val t = SurfaceControl.Transaction()
+        visualIndicator?.releaseVisualIndicator(t)
+        visualIndicator = null
+        syncQueue.runInSync { transaction ->
+            transaction.merge(t)
+            t.close()
+        }
+    }
+
     override fun getContext(): Context {
         return context
     }
@@ -471,8 +490,7 @@
                         rootTaskDisplayAreaOrganizer)
                 visualIndicator?.createFullscreenIndicatorWithAnimatedBounds()
             } else if (y > statusBarHeight && visualIndicator != null) {
-                visualIndicator?.releaseVisualIndicator()
-                visualIndicator = null
+                releaseVisualIndicator()
             }
         }
     }
@@ -489,8 +507,6 @@
     ) {
         val statusBarHeight = getStatusBarHeight(taskInfo)
         if (y <= statusBarHeight && taskInfo.windowingMode == WINDOWING_MODE_FREEFORM) {
-            visualIndicator?.releaseVisualIndicator()
-            visualIndicator = null
             moveToFullscreenWithAnimation(taskInfo)
         }
     }
@@ -508,6 +524,11 @@
             taskSurface: SurfaceControl,
             y: Float
     ) {
+        // If the motion event is above the status bar, return since we do not need to show the
+        // visual indicator at this point.
+        if (y < getStatusBarHeight(taskInfo)) {
+            return
+        }
         if (visualIndicator == null) {
             visualIndicator = DesktopModeVisualIndicator(syncQueue, taskInfo,
                     displayController, context, taskSurface, shellTaskOrganizer,
@@ -535,11 +556,8 @@
             freeformBounds: Rect
     ) {
         moveToDesktopWithAnimation(taskInfo, freeformBounds)
-        visualIndicator?.releaseVisualIndicator()
-        visualIndicator = null
     }
 
-
     private fun getStatusBarHeight(taskInfo: RunningTaskInfo): Int {
         return displayController.getDisplayLayout(taskInfo.displayId)?.stableInsets()?.top ?: 0
     }
@@ -566,7 +584,6 @@
         desktopModeTaskRepository.removeTaskCorners(taskId)
     }
 
-
     /**
      * Adds a listener to find out about changes in the visibility of freeform tasks.
      *
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
index 9467578..d55fddd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
@@ -39,6 +39,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.function.Consumer;
 import java.util.function.Supplier;
 
 /**
@@ -58,6 +59,7 @@
 
     private final List<IBinder> mPendingTransitionTokens = new ArrayList<>();
     private Point mStartPosition;
+    private Consumer<SurfaceControl.Transaction> mOnAnimationFinishedCallback;
 
     public EnterDesktopTaskTransitionHandler(
             Transitions transitions) {
@@ -75,9 +77,12 @@
      * Starts Transition of a given type
      * @param type Transition type
      * @param wct WindowContainerTransaction for transition
+     * @param onAnimationEndCallback to be called after animation
      */
     public void startTransition(@WindowManager.TransitionType int type,
-                @NonNull WindowContainerTransaction wct) {
+            @NonNull WindowContainerTransaction wct,
+            Consumer<SurfaceControl.Transaction> onAnimationEndCallback) {
+        mOnAnimationFinishedCallback = onAnimationEndCallback;
         final IBinder token = mTransitions.startTransition(type, wct, this);
         mPendingTransitionTokens.add(token);
     }
@@ -86,11 +91,14 @@
      * Starts Transition of type TRANSIT_CANCEL_ENTERING_DESKTOP_MODE
      * @param wct WindowContainerTransaction for transition
      * @param startPosition Position of task when transition is triggered
+     * @param onAnimationEndCallback to be called after animation
      */
     public void startCancelMoveToDesktopMode(@NonNull WindowContainerTransaction wct,
-            Point startPosition) {
+            Point startPosition,
+            Consumer<SurfaceControl.Transaction> onAnimationEndCallback) {
         mStartPosition = startPosition;
-        startTransition(Transitions.TRANSIT_CANCEL_ENTERING_DESKTOP_MODE, wct);
+        startTransition(Transitions.TRANSIT_CANCEL_ENTERING_DESKTOP_MODE, wct,
+                mOnAnimationFinishedCallback);
     }
 
     @Override
@@ -111,7 +119,7 @@
 
             if (change.getMode() == WindowManager.TRANSIT_CHANGE) {
                 transitionHandled |= startChangeTransition(
-                        transition, info.getType(), change, startT, finishCallback);
+                        transition, info.getType(), change, startT, finishT, finishCallback);
             }
         }
 
@@ -125,6 +133,7 @@
             @WindowManager.TransitionType int type,
             @NonNull TransitionInfo.Change change,
             @NonNull SurfaceControl.Transaction startT,
+            @NonNull SurfaceControl.Transaction finishT,
             @NonNull Transitions.TransitionFinishCallback finishCallback) {
         if (!mPendingTransitionTokens.contains(transition)) {
             return false;
@@ -178,6 +187,9 @@
             animator.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
+                    if (mOnAnimationFinishedCallback != null) {
+                        mOnAnimationFinishedCallback.accept(finishT);
+                    }
                     mTransitions.getMainExecutor().execute(
                             () -> finishCallback.onTransitionFinished(null, null));
                 }
@@ -204,7 +216,7 @@
             animator.setDuration(FREEFORM_ANIMATION_DURATION);
             final SurfaceControl.Transaction t = mTransactionSupplier.get();
             animator.addUpdateListener(animation -> {
-                final float scale = animation.getAnimatedFraction();
+                final float scale = (float) animation.getAnimatedValue();
                 t.setPosition(sc, mStartPosition.x * (1 - scale), mStartPosition.y * (1 - scale))
                         .setScale(sc, scale, scale)
                         .show(sc)
@@ -213,6 +225,9 @@
             animator.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
+                    if (mOnAnimationFinishedCallback != null) {
+                        mOnAnimationFinishedCallback.accept(finishT);
+                    }
                     mTransitions.getMainExecutor().execute(
                             () -> finishCallback.onTransitionFinished(null, null));
                 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
index fa3eee2..160a83d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
@@ -42,6 +42,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.function.Consumer;
 import java.util.function.Supplier;
 
 
@@ -54,7 +55,7 @@
     private final Context mContext;
     private final Transitions mTransitions;
     private final List<IBinder> mPendingTransitionTokens = new ArrayList<>();
-
+    private Consumer<SurfaceControl.Transaction> mOnAnimationFinishedCallback;
     private Supplier<SurfaceControl.Transaction> mTransactionSupplier;
 
     public ExitDesktopTaskTransitionHandler(
@@ -76,9 +77,12 @@
      * Starts Transition of a given type
      * @param type Transition type
      * @param wct WindowContainerTransaction for transition
+     * @param onAnimationEndCallback to be called after animation
      */
     public void startTransition(@WindowManager.TransitionType int type,
-            @NonNull WindowContainerTransaction wct) {
+            @NonNull WindowContainerTransaction wct,
+            Consumer<SurfaceControl.Transaction> onAnimationEndCallback) {
+        mOnAnimationFinishedCallback = onAnimationEndCallback;
         final IBinder token = mTransitions.startTransition(type, wct, this);
         mPendingTransitionTokens.add(token);
     }
@@ -101,7 +105,7 @@
 
             if (change.getMode() == WindowManager.TRANSIT_CHANGE) {
                 transitionHandled |= startChangeTransition(
-                        transition, info.getType(), change, startT, finishCallback);
+                        transition, info.getType(), change, startT, finishT, finishCallback);
             }
         }
 
@@ -116,6 +120,7 @@
             @WindowManager.TransitionType int type,
             @NonNull TransitionInfo.Change change,
             @NonNull SurfaceControl.Transaction startT,
+            @NonNull SurfaceControl.Transaction finishT,
             @NonNull Transitions.TransitionFinishCallback finishCallback) {
         if (!mPendingTransitionTokens.contains(transition)) {
             return false;
@@ -156,6 +161,9 @@
             animator.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
+                    if (mOnAnimationFinishedCallback != null) {
+                        mOnAnimationFinishedCallback.accept(finishT);
+                    }
                     mTransitions.getMainExecutor().execute(
                             () -> finishCallback.onTransitionFinished(null, null));
                 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
index 28f59b5..724a130 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
@@ -104,7 +104,7 @@
         setContainerMargin(0, 0, 0, 0); // make sure it's populated
 
         mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context);
-        mMarginColor = getResources().getColor(R.color.taskbar_background);
+        mMarginColor = getResources().getColor(R.color.taskbar_background_dark);
         int c = getResources().getColor(android.R.color.system_accent1_500);
         mHighlightColor =  Color.argb(HIGHLIGHT_ALPHA, Color.red(c), Color.green(c), Color.blue(c));
         mSplashScreenColor = Color.argb(SPLASHSCREEN_ALPHA, 0, 0, 0);
@@ -125,7 +125,7 @@
 
     public void onThemeChange() {
         mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(getContext());
-        mMarginColor = getResources().getColor(R.color.taskbar_background);
+        mMarginColor = getResources().getColor(R.color.taskbar_background_dark);
         mHighlightColor = getResources().getColor(android.R.color.system_accent1_500);
 
         if (mMarginPercent > 0) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index d3e7f9c..6cedcf5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -27,6 +27,7 @@
 import static com.android.wm.shell.ShellTaskOrganizer.taskListenerTypeToString;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
 import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA;
 import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_BOUNDS;
 import static com.android.wm.shell.pip.PipAnimationController.FRACTION_START;
@@ -524,12 +525,18 @@
             }
         }
 
-        final Rect destinationBounds = getExitDestinationBounds();
+        final Rect displayBounds = mPipBoundsState.getDisplayBounds();
+        final Rect destinationBounds = new Rect(displayBounds);
         final int direction = syncWithSplitScreenBounds(destinationBounds, requestEnterSplit)
                 ? TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN
                 : TRANSITION_DIRECTION_LEAVE_PIP;
+        // For exiting to fullscreen, the windowing mode of task will be changed to fullscreen
+        // until the animation is finished. Otherwise if the activity is resumed and focused at the
+        // begin of aniamtion, the app may do something too early to distub the animation.
+        final boolean toFullscreen = destinationBounds.equals(displayBounds);
 
-        if (Transitions.ENABLE_SHELL_TRANSITIONS && direction == TRANSITION_DIRECTION_LEAVE_PIP) {
+        if (Transitions.SHELL_TRANSITIONS_ROTATION || (Transitions.ENABLE_SHELL_TRANSITIONS
+                && !toFullscreen)) {
             // When exit to fullscreen with Shell transition enabled, we update the Task windowing
             // mode directly so that it can also trigger display rotation and visibility update in
             // the same transition if there will be any.
@@ -605,7 +612,7 @@
         removePip();
     }
 
-    private void applyWindowingModeChangeOnExit(WindowContainerTransaction wct, int direction) {
+    void applyWindowingModeChangeOnExit(WindowContainerTransaction wct, int direction) {
         // Reset the final windowing mode.
         wct.setWindowingMode(mToken, getOutPipWindowingMode());
         // Simply reset the activity mode set prior to the animation running.
@@ -1771,14 +1778,26 @@
      * @return {@code true} if destinationBounds is altered for split screen
      */
     private boolean syncWithSplitScreenBounds(Rect destinationBoundsOut, boolean enterSplit) {
-        if (!enterSplit || !mSplitScreenOptional.isPresent()) {
+        if (mSplitScreenOptional.isEmpty()) {
+            return false;
+        }
+        final SplitScreenController split = mSplitScreenOptional.get();
+        final int position = mTaskInfo.lastParentTaskIdBeforePip > 0
+                ? split.getSplitPosition(mTaskInfo.lastParentTaskIdBeforePip)
+                : SPLIT_POSITION_UNDEFINED;
+        if (position == SPLIT_POSITION_UNDEFINED && !enterSplit) {
             return false;
         }
         final Rect topLeft = new Rect();
         final Rect bottomRight = new Rect();
-        mSplitScreenOptional.get().getStageBounds(topLeft, bottomRight);
-        destinationBoundsOut.set(isPipToTopLeft()  ? topLeft : bottomRight);
-        return true;
+        split.getStageBounds(topLeft, bottomRight);
+        if (enterSplit) {
+            destinationBoundsOut.set(isPipToTopLeft() ? topLeft : bottomRight);
+            return true;
+        }
+        // Moving to an existing split task.
+        destinationBoundsOut.set(position == SPLIT_POSITION_TOP_OR_LEFT ? topLeft : bottomRight);
+        return false;
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index 99cb6f7..98db707 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -508,8 +508,16 @@
         currentBounds.offset(-offset.x, -offset.y);
         startTransaction.setPosition(pipLeash, currentBounds.left, currentBounds.top);
 
+        final WindowContainerToken pipTaskToken = pipChange.getContainer();
+        final boolean toFullscreen = pipChange.getEndAbsBounds().equals(
+                mPipBoundsState.getDisplayBounds());
         mFinishCallback = (wct, wctCB) -> {
             mPipOrganizer.onExitPipFinished(taskInfo);
+            if (!Transitions.SHELL_TRANSITIONS_ROTATION && toFullscreen) {
+                wct = wct != null ? wct : new WindowContainerTransaction();
+                wct.setBounds(pipTaskToken, null);
+                mPipOrganizer.applyWindowingModeChangeOnExit(wct, TRANSITION_DIRECTION_LEAVE_PIP);
+            }
             finishCallback.onTransitionFinished(wct, wctCB);
         };
         mFinishTransaction = finishTransaction;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
index c7e534a..2faed3a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
@@ -202,6 +202,7 @@
     }
 
     void setTaskViewVisible(TaskViewTaskController taskView, boolean visible) {
+        if (mTaskViews.get(taskView) == null) return;
         if (mTaskViews.get(taskView).mVisible == visible) return;
         if (taskView.getTaskInfo() == null) {
             // Nothing to update, task is not yet available
@@ -220,17 +221,19 @@
 
     void updateBoundsState(TaskViewTaskController taskView, Rect boundsOnScreen) {
         TaskViewRequestedState state = mTaskViews.get(taskView);
+        if (state == null) return;
         state.mBounds.set(boundsOnScreen);
     }
 
     void updateVisibilityState(TaskViewTaskController taskView, boolean visible) {
         TaskViewRequestedState state = mTaskViews.get(taskView);
+        if (state == null) return;
         state.mVisible = visible;
     }
 
     void setTaskBounds(TaskViewTaskController taskView, Rect boundsOnScreen) {
         TaskViewRequestedState state = mTaskViews.get(taskView);
-        if (Objects.equals(boundsOnScreen, state.mBounds)) {
+        if (state == null || Objects.equals(boundsOnScreen, state.mBounds)) {
             return;
         }
         state.mBounds.set(boundsOnScreen);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Tracer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Tracer.java
index ba364f8..0cede90 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Tracer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Tracer.java
@@ -18,25 +18,29 @@
 
 import static android.os.Build.IS_USER;
 
-import static com.android.wm.shell.WmShellTransitionTraceProto.MAGIC_NUMBER;
-import static com.android.wm.shell.WmShellTransitionTraceProto.MAGIC_NUMBER_H;
-import static com.android.wm.shell.WmShellTransitionTraceProto.MAGIC_NUMBER_L;
+import static com.android.wm.shell.nano.WmShellTransitionTraceProto.MAGIC_NUMBER_H;
+import static com.android.wm.shell.nano.WmShellTransitionTraceProto.MAGIC_NUMBER_L;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.SystemClock;
 import android.os.Trace;
 import android.util.Log;
-import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.util.TraceBuffer;
+import com.android.wm.shell.nano.HandlerMapping;
 import com.android.wm.shell.sysui.ShellCommandHandler;
 
+import com.google.protobuf.nano.MessageNano;
+
 import java.io.File;
 import java.io.IOException;
+import java.io.OutputStream;
 import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Queue;
 
 /**
  * Helper class to collect and dump transition traces.
@@ -54,8 +58,35 @@
     private final Object mEnabledLock = new Object();
     private boolean mActiveTracingEnabled = false;
 
-    private final TraceBuffer mTraceBuffer = new TraceBuffer(ALWAYS_ON_TRACING_CAPACITY,
-            (proto) -> handleOnEntryRemovedFromTrace(proto));
+    private final TraceBuffer.ProtoProvider mProtoProvider =
+            new TraceBuffer.ProtoProvider<MessageNano,
+                com.android.wm.shell.nano.WmShellTransitionTraceProto,
+                com.android.wm.shell.nano.Transition>() {
+        @Override
+        public int getItemSize(MessageNano proto) {
+            return proto.getCachedSize();
+        }
+
+        @Override
+        public byte[] getBytes(MessageNano proto) {
+            return MessageNano.toByteArray(proto);
+        }
+
+        @Override
+        public void write(
+                com.android.wm.shell.nano.WmShellTransitionTraceProto encapsulatingProto,
+                Queue<com.android.wm.shell.nano.Transition> buffer, OutputStream os)
+                        throws IOException {
+            encapsulatingProto.transitions = buffer.toArray(
+                    new com.android.wm.shell.nano.Transition[0]);
+            os.write(getBytes(encapsulatingProto));
+        }
+    };
+    private final TraceBuffer<MessageNano,
+            com.android.wm.shell.nano.WmShellTransitionTraceProto,
+            com.android.wm.shell.nano.Transition> mTraceBuffer
+                    = new TraceBuffer(ALWAYS_ON_TRACING_CAPACITY, mProtoProvider,
+                            (proto) -> handleOnEntryRemovedFromTrace(proto));
     private final Map<Object, Runnable> mRemovedFromTraceCallbacks = new HashMap<>();
 
     private final Map<Transitions.TransitionHandler, Integer> mHandlerIds = new HashMap<>();
@@ -78,26 +109,20 @@
             mHandlerIds.put(handler, handlerId);
         }
 
-        ProtoOutputStream outputStream = new ProtoOutputStream();
-        final long protoToken =
-                outputStream.start(com.android.wm.shell.WmShellTransitionTraceProto.TRANSITIONS);
-
-        outputStream.write(com.android.wm.shell.Transition.ID, transitionId);
-        outputStream.write(com.android.wm.shell.Transition.DISPATCH_TIME_NS,
-                SystemClock.elapsedRealtimeNanos());
-        outputStream.write(com.android.wm.shell.Transition.HANDLER, handlerId);
-
-        outputStream.end(protoToken);
+        com.android.wm.shell.nano.Transition proto = new com.android.wm.shell.nano.Transition();
+        proto.id = transitionId;
+        proto.dispatchTimeNs = SystemClock.elapsedRealtimeNanos();
+        proto.handler = handlerId;
 
         final int useCountAfterAdd = mHandlerUseCountInTrace.getOrDefault(handler, 0) + 1;
         mHandlerUseCountInTrace.put(handler, useCountAfterAdd);
 
-        mRemovedFromTraceCallbacks.put(outputStream, () -> {
+        mRemovedFromTraceCallbacks.put(proto, () -> {
             final int useCountAfterRemove = mHandlerUseCountInTrace.get(handler) - 1;
             mHandlerUseCountInTrace.put(handler, useCountAfterRemove);
         });
 
-        mTraceBuffer.add(outputStream);
+        mTraceBuffer.add(proto);
     }
 
     /**
@@ -107,18 +132,12 @@
      * @param playingTransitionId The id of the transition we was to merge the transition into.
      */
     public void logMergeRequested(int mergeRequestedTransitionId, int playingTransitionId) {
-        ProtoOutputStream outputStream = new ProtoOutputStream();
-        final long protoToken =
-                outputStream.start(com.android.wm.shell.WmShellTransitionTraceProto.TRANSITIONS);
+        com.android.wm.shell.nano.Transition proto = new com.android.wm.shell.nano.Transition();
+        proto.id = mergeRequestedTransitionId;
+        proto.mergeRequestTimeNs = SystemClock.elapsedRealtimeNanos();
+        proto.mergedInto = playingTransitionId;
 
-        outputStream.write(com.android.wm.shell.Transition.ID, mergeRequestedTransitionId);
-        outputStream.write(com.android.wm.shell.Transition.MERGE_REQUEST_TIME_NS,
-                SystemClock.elapsedRealtimeNanos());
-        outputStream.write(com.android.wm.shell.Transition.MERGED_INTO, playingTransitionId);
-
-        outputStream.end(protoToken);
-
-        mTraceBuffer.add(outputStream);
+        mTraceBuffer.add(proto);
     }
 
     /**
@@ -128,18 +147,12 @@
      * @param playingTransitionId The id of the transition the transition was merged into.
      */
     public void logMerged(int mergedTransitionId, int playingTransitionId) {
-        ProtoOutputStream outputStream = new ProtoOutputStream();
-        final long protoToken =
-                outputStream.start(com.android.wm.shell.WmShellTransitionTraceProto.TRANSITIONS);
+        com.android.wm.shell.nano.Transition proto = new com.android.wm.shell.nano.Transition();
+        proto.id = mergedTransitionId;
+        proto.mergeTimeNs = SystemClock.elapsedRealtimeNanos();
+        proto.mergedInto = playingTransitionId;
 
-        outputStream.write(com.android.wm.shell.Transition.ID, mergedTransitionId);
-        outputStream.write(
-                com.android.wm.shell.Transition.MERGE_TIME_NS, SystemClock.elapsedRealtimeNanos());
-        outputStream.write(com.android.wm.shell.Transition.MERGED_INTO, playingTransitionId);
-
-        outputStream.end(protoToken);
-
-        mTraceBuffer.add(outputStream);
+        mTraceBuffer.add(proto);
     }
 
     /**
@@ -148,17 +161,11 @@
      * @param transitionId The id of the transition that was aborted.
      */
     public void logAborted(int transitionId) {
-        ProtoOutputStream outputStream = new ProtoOutputStream();
-        final long protoToken =
-                outputStream.start(com.android.wm.shell.WmShellTransitionTraceProto.TRANSITIONS);
+        com.android.wm.shell.nano.Transition proto = new com.android.wm.shell.nano.Transition();
+        proto.id = transitionId;
+        proto.abortTimeNs = SystemClock.elapsedRealtimeNanos();
 
-        outputStream.write(com.android.wm.shell.Transition.ID, transitionId);
-        outputStream.write(
-                com.android.wm.shell.Transition.ABORT_TIME_NS, SystemClock.elapsedRealtimeNanos());
-
-        outputStream.end(protoToken);
-
-        mTraceBuffer.add(outputStream);
+        mTraceBuffer.add(proto);
     }
 
     /**
@@ -230,8 +237,9 @@
     private void writeTraceToFileLocked(@Nullable PrintWriter pw, File file) {
         Trace.beginSection("TransitionTracer#writeTraceToFileLocked");
         try {
-            ProtoOutputStream proto = new ProtoOutputStream();
-            proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
+            com.android.wm.shell.nano.WmShellTransitionTraceProto proto =
+                    new com.android.wm.shell.nano.WmShellTransitionTraceProto();
+            proto.magicNumber = MAGIC_NUMBER_VALUE;
             writeHandlerMappingToProto(proto);
             int pid = android.os.Process.myPid();
             LogAndPrintln.i(pw, "Writing file to " + file.getAbsolutePath()
@@ -243,19 +251,21 @@
         Trace.endSection();
     }
 
-    private void writeHandlerMappingToProto(ProtoOutputStream outputStream) {
+    private void writeHandlerMappingToProto(
+            com.android.wm.shell.nano.WmShellTransitionTraceProto proto) {
+        ArrayList<com.android.wm.shell.nano.HandlerMapping> handlerMappings = new ArrayList<>();
         for (Transitions.TransitionHandler handler : mHandlerUseCountInTrace.keySet()) {
             final int count = mHandlerUseCountInTrace.get(handler);
             if (count > 0) {
-                final long protoToken = outputStream.start(
-                        com.android.wm.shell.WmShellTransitionTraceProto.HANDLER_MAPPINGS);
-                outputStream.write(com.android.wm.shell.HandlerMapping.ID,
-                        mHandlerIds.get(handler));
-                outputStream.write(com.android.wm.shell.HandlerMapping.NAME,
-                        handler.getClass().getName());
-                outputStream.end(protoToken);
+                com.android.wm.shell.nano.HandlerMapping mapping =
+                        new com.android.wm.shell.nano.HandlerMapping();
+                mapping.id = mHandlerIds.get(handler);
+                mapping.name = handler.getClass().getName();
+                handlerMappings.add(mapping);
             }
         }
+        proto.handlerMappings = handlerMappings.toArray(
+                new com.android.wm.shell.nano.HandlerMapping[0]);
     }
 
     private void handleOnEntryRemovedFromTrace(Object proto) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index 12edc35..dffbedd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -111,7 +111,6 @@
     private ValueAnimator mDragToDesktopValueAnimator;
     private final Rect mDragToDesktopAnimationStartBounds = new Rect();
     private boolean mDragToDesktopAnimationStarted;
-    private float mCaptionDragStartX;
 
     public DesktopModeWindowDecorViewModel(
             Context context,
@@ -525,7 +524,6 @@
             DesktopModeWindowDecoration relevantDecor) {
         switch (ev.getActionMasked()) {
             case MotionEvent.ACTION_DOWN: {
-                mCaptionDragStartX = ev.getX();
                 // Begin drag through status bar if applicable.
                 if (relevantDecor != null) {
                     mDragToDesktopAnimationStartBounds.set(
@@ -580,8 +578,9 @@
                 }
                 if (mTransitionDragActive) {
                     mDesktopTasksController.ifPresent(
-                            c -> c.onDragPositioningMoveThroughStatusBar(relevantDecor.mTaskInfo,
-                            relevantDecor.mTaskSurface, ev.getY()));
+                            c -> c.onDragPositioningMoveThroughStatusBar(
+                                    relevantDecor.mTaskInfo,
+                                    relevantDecor.mTaskSurface, ev.getY()));
                     final int statusBarHeight = getStatusBarHeight(
                             relevantDecor.mTaskInfo.displayId);
                     if (ev.getY() > statusBarHeight) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
index 11c5951..6178156 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
@@ -18,15 +18,18 @@
 
 import android.content.Context
 import android.system.helpers.CommandsHelper
+import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.flicker.legacy.FlickerBuilder
 import android.tools.device.flicker.legacy.FlickerTest
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.helpers.LetterboxAppHelper
 import android.tools.device.flicker.legacy.FlickerTestFactory
 import android.tools.device.flicker.legacy.IFlickerTestData
-import com.android.server.wm.flicker.helpers.LetterboxAppHelper
-import com.android.server.wm.flicker.helpers.setRotation
 import com.android.wm.shell.flicker.BaseTest
-import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
 import com.android.wm.shell.flicker.appWindowIsVisibleAtStart
+import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
+import com.android.wm.shell.flicker.layerKeepVisible
+import org.junit.After
 import org.junit.Assume
 import org.junit.Before
 import org.junit.runners.Parameterized
@@ -35,7 +38,7 @@
     protected val context: Context = instrumentation.context
     protected val letterboxApp = LetterboxAppHelper(instrumentation)
     lateinit var cmdHelper: CommandsHelper
-    lateinit var letterboxStyle: HashMap<String, String>
+    private lateinit var letterboxStyle: HashMap<String, String>
 
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit
@@ -45,12 +48,22 @@
                 letterboxApp.launchViaIntent(wmHelper)
                 setEndRotation()
             }
+            teardown {
+                letterboxApp.exit(wmHelper)
+            }
         }
 
     @Before
     fun before() {
         cmdHelper = CommandsHelper.getInstance(instrumentation)
         Assume.assumeTrue(tapl.isTablet && isIgnoreOrientationRequest())
+        letterboxStyle = mapLetterboxStyle()
+        setLetterboxEducationEnabled(false)
+    }
+
+    @After
+    fun after() {
+        resetLetterboxEducationEnabled()
     }
 
     private fun mapLetterboxStyle(): HashMap<String, String> {
@@ -67,6 +80,22 @@
         return map
     }
 
+    private fun getLetterboxStyle(): HashMap<String, String> {
+        if (!::letterboxStyle.isInitialized) {
+            letterboxStyle = mapLetterboxStyle()
+        }
+        return letterboxStyle
+    }
+
+    private fun resetLetterboxEducationEnabled() {
+        val enabled = getLetterboxStyle().getValue("Is education enabled")
+        cmdHelper.executeShellCommand("wm set-letterbox-style --isEducationEnabled $enabled")
+    }
+
+    private fun setLetterboxEducationEnabled(enabled: Boolean) {
+        cmdHelper.executeShellCommand("wm set-letterbox-style --isEducationEnabled $enabled")
+    }
+
     private fun isIgnoreOrientationRequest(): Boolean {
         val res = cmdHelper.executeShellCommand("wm get-ignore-orientation-request")
         return res != null && res.contains("true")
@@ -89,10 +118,7 @@
 
     /** Only run on tests with config_letterboxActivityCornersRadius != 0 in devices */
     private fun assumeLetterboxRoundedCornersEnabled() {
-        if (!::letterboxStyle.isInitialized) {
-            letterboxStyle = mapLetterboxStyle()
-        }
-        Assume.assumeTrue(letterboxStyle.getValue("Corner radius") != "0")
+        Assume.assumeTrue(getLetterboxStyle().getValue("Corner radius") != "0")
     }
 
     fun assertLetterboxAppVisibleAtStartAndEnd() {
@@ -100,12 +126,20 @@
         flicker.appWindowIsVisibleAtEnd(letterboxApp)
     }
 
+    fun assertAppLetterboxedAtEnd() =
+            flicker.assertLayersEnd { isVisible(ComponentNameMatcher.LETTERBOX) }
+
+    fun assertAppLetterboxedAtStart() =
+            flicker.assertLayersStart { isVisible(ComponentNameMatcher.LETTERBOX) }
+
+    fun assertLetterboxAppLayerKeepVisible() = flicker.layerKeepVisible(letterboxApp)
+
     companion object {
         /**
          * Creates the test configurations.
          *
-         * See [FlickerTestFactory.rotationTests] for configuring screen orientation and navigation
-         * modes.
+         * See [FlickerTestFactory.rotationTests] for configuring screen orientation and
+         * navigation modes.
          */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
index f212a4e..c2141a3 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
@@ -70,6 +70,10 @@
     @Test
     fun letterboxedAppHasRoundedCorners() = assertLetterboxAppAtEndHasRoundedCorners()
 
+    @Postsubmit
+    @Test
+    fun appIsLetterboxedAtEnd() = assertAppLetterboxedAtEnd()
+
     /**
      * Checks that the [ComponentNameMatcher.ROTATION] layer appears during the transition, doesn't
      * flicker, and disappears before the transition is complete
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
index 8e75439..b0e1a42 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
@@ -53,25 +53,32 @@
         get() = {
             super.transition(this)
             transitions { letterboxApp.clickRestart(wmHelper) }
-            teardown { letterboxApp.exit(wmHelper) }
         }
 
     @Postsubmit @Test fun appVisibleAtStartAndEnd() = assertLetterboxAppVisibleAtStartAndEnd()
 
     @Postsubmit
     @Test
-    fun appLayerVisibilityChanges() {
-        flicker.assertLayers {
-            this.isVisible(letterboxApp)
+    fun appWindowVisibilityChanges() {
+        flicker.assertWm {
+            this.isAppWindowVisible(letterboxApp)
                 .then()
-                .isInvisible(letterboxApp)
+                .isAppWindowInvisible(letterboxApp) // animatingExit true
                 .then()
-                .isVisible(letterboxApp)
+                .isAppWindowVisible(letterboxApp) // Activity finish relaunching
         }
     }
 
     @Postsubmit
     @Test
+    fun appLayerKeepVisible() = assertLetterboxAppLayerKeepVisible()
+
+    @Postsubmit
+    @Test
+    fun appIsLetterboxedAtStart() = assertAppLetterboxedAtStart()
+
+    @Postsubmit
+    @Test
     fun letterboxedAppHasRoundedCorners() = assertLetterboxAppAtStartHasRoundedCorners()
 
     /** Checks that the visible region of [letterboxApp] is still within display bounds */
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandlerTest.java
index 6199e0b..8592dea 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandlerTest.java
@@ -94,7 +94,7 @@
         WindowContainerTransaction wct = new WindowContainerTransaction();
         doReturn(mToken).when(mTransitions)
                 .startTransition(transitionType, wct, mEnterDesktopTaskTransitionHandler);
-        mEnterDesktopTaskTransitionHandler.startTransition(transitionType, wct);
+        mEnterDesktopTaskTransitionHandler.startTransition(transitionType, wct, null);
 
         TransitionInfo.Change change =
                 createChange(WindowManager.TRANSIT_CHANGE, taskId, WINDOWING_MODE_FREEFORM);
@@ -115,7 +115,7 @@
         WindowContainerTransaction wct = new WindowContainerTransaction();
         doReturn(mToken).when(mTransitions)
                 .startTransition(transitionType, wct, mEnterDesktopTaskTransitionHandler);
-        mEnterDesktopTaskTransitionHandler.startTransition(transitionType, wct);
+        mEnterDesktopTaskTransitionHandler.startTransition(transitionType, wct, null);
 
         TransitionInfo.Change change =
                 createChange(WindowManager.TRANSIT_CHANGE, taskId, WINDOWING_MODE_FREEFORM);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandlerTest.java
index 4fad054..265b10d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandlerTest.java
@@ -100,7 +100,7 @@
         doReturn(mToken).when(mTransitions)
                 .startTransition(transitionType, wct, mExitDesktopTaskTransitionHandler);
 
-        mExitDesktopTaskTransitionHandler.startTransition(transitionType, wct);
+        mExitDesktopTaskTransitionHandler.startTransition(transitionType, wct, null);
 
         TransitionInfo.Change change =
                 createChange(WindowManager.TRANSIT_CHANGE, taskId, WINDOWING_MODE_FULLSCREEN);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java
index 4559095..9d56686 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java
@@ -179,4 +179,23 @@
                 mTaskViewTransitions.findPending(mTaskViewTaskController, TRANSIT_CHANGE);
         assertThat(pendingBounds2).isNull();
     }
+
+    @Test
+    public void testSetTaskVisibility_taskRemoved_noNPE() {
+        mTaskViewTransitions.removeTaskView(mTaskViewTaskController);
+
+        assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
+
+        mTaskViewTransitions.setTaskViewVisible(mTaskViewTaskController, false);
+    }
+
+    @Test
+    public void testSetTaskBounds_taskRemoved_noNPE() {
+        mTaskViewTransitions.removeTaskView(mTaskViewTaskController);
+
+        assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
+
+        mTaskViewTransitions.setTaskBounds(mTaskViewTaskController,
+                new Rect(0, 0, 100, 100));
+    }
 }
diff --git a/libs/hwui/Tonemapper.cpp b/libs/hwui/Tonemapper.cpp
index 0d39f0e..974a5d0 100644
--- a/libs/hwui/Tonemapper.cpp
+++ b/libs/hwui/Tonemapper.cpp
@@ -97,7 +97,6 @@
                 .inputDataspace = sourceDataspace,
                 .outputDataspace = destinationDataspace,
                 .undoPremultipliedAlpha = source.alphaType() == kPremul_SkAlphaType,
-                .fakeInputDataspace = destinationDataspace,
                 .type = shaders::LinearEffect::SkSLType::ColorFilter};
         constexpr float kMaxDisplayBrightnessNits = 1000.f;
         constexpr float kCurrentDisplayBrightnessNits = 500.f;
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index 7e9d44f..c00a270 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -29,6 +29,7 @@
 #include "Layer.h"
 #include "Properties.h"
 #include "RenderThread.h"
+#include "VulkanManager.h"
 #include "pipeline/skia/ATraceMemoryDump.h"
 #include "pipeline/skia/ShaderCache.h"
 #include "pipeline/skia/SkiaMemoryTracer.h"
@@ -182,8 +183,14 @@
     }
     log.appendFormat("Contexts: %zu (stopped = %zu)\n", mCanvasContexts.size(), stoppedContexts);
 
+    auto vkInstance = VulkanManager::peekInstance();
     if (!mGrContext) {
-        log.appendFormat("No GPU context.\n");
+        if (!vkInstance) {
+            log.appendFormat("No GPU context.\n");
+        } else {
+            log.appendFormat("No GrContext; however %d remaining Vulkan refs",
+                             vkInstance->getStrongCount() - 1);
+        }
         return;
     }
     std::vector<skiapipeline::ResourcePair> cpuResourceMap = {
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index f198bca..4cffc6c 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -107,11 +107,11 @@
 #define GET_INST_PROC(F) m##F = (PFN_vk##F)vkGetInstanceProcAddr(mInstance, "vk" #F)
 #define GET_DEV_PROC(F) m##F = (PFN_vk##F)vkGetDeviceProcAddr(mDevice, "vk" #F)
 
-sp<VulkanManager> VulkanManager::getInstance() {
-    // cache a weakptr to the context to enable a second thread to share the same vulkan state
-    static wp<VulkanManager> sWeakInstance = nullptr;
-    static std::mutex sLock;
+// cache a weakptr to the context to enable a second thread to share the same vulkan state
+static wp<VulkanManager> sWeakInstance = nullptr;
+static std::mutex sLock;
 
+sp<VulkanManager> VulkanManager::getInstance() {
     std::lock_guard _lock{sLock};
     sp<VulkanManager> vulkanManager = sWeakInstance.promote();
     if (!vulkanManager.get()) {
@@ -122,6 +122,11 @@
     return vulkanManager;
 }
 
+sp<VulkanManager> VulkanManager::peekInstance() {
+    std::lock_guard _lock{sLock};
+    return sWeakInstance.promote();
+}
+
 VulkanManager::~VulkanManager() {
     if (mDevice != VK_NULL_HANDLE) {
         mDeviceWaitIdle(mDevice);
@@ -404,9 +409,13 @@
     }
 }
 
-sk_sp<GrDirectContext> VulkanManager::createContext(const GrContextOptions& options,
-                                                    ContextType contextType) {
+static void onGrContextReleased(void* context) {
+    VulkanManager* manager = (VulkanManager*)context;
+    manager->decStrong((void*)onGrContextReleased);
+}
 
+sk_sp<GrDirectContext> VulkanManager::createContext(GrContextOptions& options,
+                                                    ContextType contextType) {
     GrVkBackendContext backendContext;
     backendContext.fInstance = mInstance;
     backendContext.fPhysicalDevice = mPhysicalDevice;
@@ -418,6 +427,11 @@
     backendContext.fDeviceFeatures2 = &mPhysicalDeviceFeatures2;
     backendContext.fGetProc = sSkiaGetProp;
 
+    LOG_ALWAYS_FATAL_IF(options.fContextDeleteProc != nullptr, "Conflicting fContextDeleteProcs!");
+    this->incStrong((void*)onGrContextReleased);
+    options.fContextDeleteContext = this;
+    options.fContextDeleteProc = onGrContextReleased;
+
     return GrDirectContext::MakeVulkan(backendContext, options);
 }
 
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index c5196ee..00a40c0 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -66,6 +66,7 @@
 class VulkanManager final : public RefBase {
 public:
     static sp<VulkanManager> getInstance();
+    static sp<VulkanManager> peekInstance();
 
     // Sets up the vulkan context that is shared amonst all clients of the VulkanManager. This must
     // be call once before use of the VulkanManager. Multiple calls after the first will simiply
@@ -109,7 +110,7 @@
     };
 
     // returns a Skia graphic context used to draw content on the specified thread
-    sk_sp<GrDirectContext> createContext(const GrContextOptions& options,
+    sk_sp<GrDirectContext> createContext(GrContextOptions& options,
                                          ContextType contextType = ContextType::kRenderThread);
 
     uint32_t getDriverVersion() const { return mDriverVersion; }
diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp
index bffe137..913af8a 100644
--- a/libs/hwui/utils/Color.cpp
+++ b/libs/hwui/utils/Color.cpp
@@ -284,7 +284,9 @@
         case HAL_DATASPACE_TRANSFER_GAMMA2_8:
             return SkColorSpace::MakeRGB({2.8f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut);
         case HAL_DATASPACE_TRANSFER_ST2084:
-            return SkColorSpace::MakeRGB(SkNamedTransferFn::kPQ, gamut);
+            return SkColorSpace::MakeRGB({-2.0, -1.555223, 1.860454, 32 / 2523.0, 2413 / 128.0,
+                                          -2392 / 128.0, 8192 / 1305.0},
+                                         gamut);
         case HAL_DATASPACE_TRANSFER_SMPTE_170M:
             return SkColorSpace::MakeRGB(SkNamedTransferFn::kRec2020, gamut);
         case HAL_DATASPACE_TRANSFER_UNSPECIFIED:
@@ -427,10 +429,10 @@
 }
 
 // Skia skcms' default HLG maps encoded [0, 1] to linear [1, 12] in order to follow ARIB
-// but LinearEffect expects a decoded [0, 1] range instead to follow Rec 2100.
+// but LinearEffect expects to map 1.0 == 203 nits
 std::optional<skcms_TransferFunction> GetHLGScaleTransferFunction() {
     skcms_TransferFunction hlgFn;
-    if (skcms_TransferFunction_makeScaledHLGish(&hlgFn, 1.f / 12.f, 2.f, 2.f, 1.f / 0.17883277f,
+    if (skcms_TransferFunction_makeScaledHLGish(&hlgFn, 0.314509843, 2.f, 2.f, 1.f / 0.17883277f,
                                                 0.28466892f, 0.55991073f)) {
         return std::make_optional<skcms_TransferFunction>(hlgFn);
     }
diff --git a/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl b/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl
index 6092ac5..82fc33e 100644
--- a/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl
+++ b/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl
@@ -15,8 +15,8 @@
  */
 package android.media.soundtrigger_middleware;
 
-import android.media.soundtrigger.RecognitionEvent;
-import android.media.soundtrigger.PhraseRecognitionEvent;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
 
 /**
  * Main interface for a client to get notifications of events coming from this module.
@@ -31,7 +31,7 @@
      * In case of abortion, the caller may retry after the next onRecognitionAvailabilityChange()
      * callback.
      */
-    void onRecognition(int modelHandle, in RecognitionEvent event, int captureSession);
+    void onRecognition(int modelHandle, in RecognitionEventSys event, int captureSession);
      /**
       * Invoked whenever a phrase recognition event is triggered (typically, on recognition, but
       * also in case of external aborting of a recognition or a forced recognition event - see the
@@ -39,7 +39,7 @@
       * In case of abortion, the caller may retry after the next onRecognitionAvailabilityChange()
       * callback.
       */
-    void onPhraseRecognition(int modelHandle, in PhraseRecognitionEvent event, int captureSession);
+    void onPhraseRecognition(int modelHandle, in PhraseRecognitionEventSys event, int captureSession);
     /**
      * Notifies the client that some start/load operations that have previously failed for resource
      * reasons (threw a ServiceSpecificException(RESOURCE_CONTENTION) or have been preempted) may
diff --git a/media/aidl/android/media/soundtrigger_middleware/PhraseRecognitionEventSys.aidl b/media/aidl/android/media/soundtrigger_middleware/PhraseRecognitionEventSys.aidl
new file mode 100644
index 0000000..6c912ed
--- /dev/null
+++ b/media/aidl/android/media/soundtrigger_middleware/PhraseRecognitionEventSys.aidl
@@ -0,0 +1,36 @@
+/*
+ * 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.media.soundtrigger_middleware;
+
+import android.media.soundtrigger.PhraseRecognitionEvent;
+
+/**
+ * Wrapper to android.media.soundtrigger.RecognitionEvent providing additional fields used by the
+ * framework.
+ */
+parcelable PhraseRecognitionEventSys {
+
+    PhraseRecognitionEvent phraseRecognitionEvent;
+    /**
+     * Timestamp of when the trigger event from SoundTriggerHal was received by the
+     * framework.
+     *
+     * <p>same units and timebase as {@link SystemClock#elapsedRealtime()}.
+     * The value will be -1 if the event was not generated from the HAL.
+     */
+    // @ElapsedRealtimeLong
+    long halEventReceivedMillis = -1;
+}
diff --git a/media/aidl/android/media/soundtrigger_middleware/RecognitionEventSys.aidl b/media/aidl/android/media/soundtrigger_middleware/RecognitionEventSys.aidl
new file mode 100644
index 0000000..84e327d
--- /dev/null
+++ b/media/aidl/android/media/soundtrigger_middleware/RecognitionEventSys.aidl
@@ -0,0 +1,36 @@
+/*
+ * 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.media.soundtrigger_middleware;
+
+import android.media.soundtrigger.RecognitionEvent;
+
+/**
+ * Wrapper to android.media.soundtrigger.RecognitionEvent providing additional fields used by the
+ * framework.
+ */
+parcelable RecognitionEventSys {
+
+    RecognitionEvent recognitionEvent;
+    /**
+     * Timestamp of when the trigger event from SoundTriggerHal was received by the
+     * framework.
+     *
+     * <p>same units and timebase as {@link SystemClock#elapsedRealtime()}.
+     * The value will be -1 if the event was not generated from the HAL.
+     */
+    // @ElapsedRealtimeLong
+    long halEventReceivedMillis = -1;
+}
diff --git a/native/android/input.cpp b/native/android/input.cpp
index 1bff97d..64e8efe 100644
--- a/native/android/input.cpp
+++ b/native/android/input.cpp
@@ -87,11 +87,8 @@
 
 const AInputEvent* AKeyEvent_fromJava(JNIEnv* env, jobject keyEvent) {
     std::unique_ptr<KeyEvent> event = std::make_unique<KeyEvent>();
-    android::status_t ret = android::android_view_KeyEvent_toNative(env, keyEvent, event.get());
-    if (ret == android::OK) {
-        return event.release();
-    }
-    return nullptr;
+    *event = android::android_view_KeyEvent_toNative(env, keyEvent);
+    return event.release();
 }
 
 int64_t AKeyEvent_getEventTime(const AInputEvent* key_event) {
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseActivity.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseActivity.java
index 5f067e9..b8887390 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseActivity.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SlicePurchaseActivity.java
@@ -60,6 +60,7 @@
     @NonNull private Intent mIntent;
     @NonNull private URL mUrl;
     @TelephonyManager.PremiumCapability protected int mCapability;
+    private boolean mIsUserTriggeredFinish;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -71,6 +72,7 @@
                 SlicePurchaseController.PREMIUM_CAPABILITY_INVALID);
         String url = mIntent.getStringExtra(SlicePurchaseController.EXTRA_PURCHASE_URL);
         mApplicationContext = getApplicationContext();
+        mIsUserTriggeredFinish = true;
         logd("onCreate: subId=" + subId + ", capability="
                 + TelephonyManager.convertPremiumCapabilityToString(mCapability) + ", url=" + url);
 
@@ -153,12 +155,20 @@
 
     @Override
     protected void onDestroy() {
-        logd("onDestroy: User canceled the purchase by closing the application.");
-        SlicePurchaseBroadcastReceiver.sendSlicePurchaseAppResponse(
-                mIntent, SlicePurchaseController.EXTRA_INTENT_CANCELED);
+        if (mIsUserTriggeredFinish) {
+            logd("onDestroy: User canceled the purchase by closing the application.");
+            SlicePurchaseBroadcastReceiver.sendSlicePurchaseAppResponse(
+                    mIntent, SlicePurchaseController.EXTRA_INTENT_CANCELED);
+        }
         super.onDestroy();
     }
 
+    @Override
+    public void finishAndRemoveTask() {
+        mIsUserTriggeredFinish = false;
+        super.finishAndRemoveTask();
+    }
+
     private void setupWebView() {
         // Create WebView
         mWebView = new WebView(this);
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java
index f594bf2..7ed1816 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/PermissionListAdapter.java
@@ -123,12 +123,11 @@
             viewHolder.mExpandButton.setTag(R.drawable.btn_expand_more);
         }
 
-        setAccessibility(view, viewType,
-                AccessibilityNodeInfo.ACTION_CLICK, R.string.permission_expand, 0);
-
         // Add expand buttons if the permissions are more than PERMISSION_SIZE in this list also
         // make the summary invisible by default.
         if (mPermissions.size() > PERMISSION_SIZE) {
+            setAccessibility(view, viewType,
+                    AccessibilityNodeInfo.ACTION_CLICK, R.string.permission_expand, 0);
 
             viewHolder.mPermissionSummary.setVisibility(View.GONE);
 
diff --git a/packages/CredentialManager/res/values/strings.xml b/packages/CredentialManager/res/values/strings.xml
index 7d71bd5..6df0778 100644
--- a/packages/CredentialManager/res/values/strings.xml
+++ b/packages/CredentialManager/res/values/strings.xml
@@ -24,8 +24,8 @@
   <string name="string_cancel">Cancel</string>
   <!-- This is a label for a button that takes user to the next screen. [CHAR LIMIT=20] -->
   <string name="string_continue">Continue</string>
-  <!-- This is a label for a button that links to different places where the user can save their passkeys. [CHAR LIMIT=20] -->
-  <string name="string_more_options">More options</string>
+  <!-- This is a label for a button that leads to a holistic view of all different options where the user can save their new app credential. [CHAR LIMIT=20] -->
+  <string name="string_more_options">Save another way</string>
   <!-- This is a label for a button that links to additional information about passkeys. [CHAR LIMIT=20] -->
   <string name="string_learn_more">Learn more</string>
   <!-- This is a label for content description for show password icon button. -->
@@ -120,6 +120,8 @@
   <!-- Strings for the get flow. -->
   <!-- This appears as the title of the modal bottom sheet asking for user confirmation to use the single previously saved passkey to sign in to the app. [CHAR LIMIT=200] -->
   <string name="get_dialog_title_use_passkey_for">Use your saved passkey for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g>?</string>
+  <!-- This appears as the title of the modal bottom sheet asking for user confirmation to use the single previously saved password to sign in to the app. [CHAR LIMIT=200] -->
+  <string name="get_dialog_title_use_password_for">Use your saved password for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g>?</string>
   <!-- This appears as the title of the dialog asking for user confirmation to use the single user credential (previously saved or to be created) to sign in to the app. [CHAR LIMIT=200] -->
   <string name="get_dialog_title_use_sign_in_for">Use your sign-in for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g>?</string>
   <!-- This appears as the title of the dialog asking for user to make a choice from various available user credentials (previously saved or to be created) to sign in to the app. [CHAR LIMIT=200] -->
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
index 1fb5e3f..54a8678d 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
@@ -25,6 +25,7 @@
 import android.os.ResultReceiver
 import android.util.Log
 import androidx.activity.ComponentActivity
+import androidx.activity.OnBackPressedCallback
 import androidx.activity.compose.rememberLauncherForActivityResult
 import androidx.activity.compose.setContent
 import androidx.activity.viewModels
@@ -48,11 +49,12 @@
 class CredentialSelectorActivity : ComponentActivity() {
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
+        Log.d(Constants.LOG_TAG, "Creating new CredentialSelectorActivity")
         overrideActivityTransition(Activity.OVERRIDE_TRANSITION_OPEN,
             0, 0)
         overrideActivityTransition(Activity.OVERRIDE_TRANSITION_CLOSE,
             0, 0)
-        Log.d(Constants.LOG_TAG, "Creating new CredentialSelectorActivity")
+
         try {
             val (isCancellationRequest, shouldShowCancellationUi, _) =
                 maybeCancelUIUponRequest(intent)
@@ -61,6 +63,18 @@
             }
             val userConfigRepo = UserConfigRepo(this)
             val credManRepo = CredentialManagerRepo(this, intent, userConfigRepo)
+
+            val backPressedCallback = object : OnBackPressedCallback(
+                true // default to enabled
+            ) {
+                override fun handleOnBackPressed() {
+                    credManRepo.onUserCancel()
+                    Log.d(Constants.LOG_TAG, "Activity back triggered: finish the activity.")
+                    this@CredentialSelectorActivity.finish()
+                }
+            }
+            onBackPressedDispatcher.addCallback(this, backPressedCallback)
+
             setContent {
                 PlatformTheme {
                     CredentialManagerBottomSheet(
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
index 00c2f1a..a35310c 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
@@ -482,7 +482,8 @@
                     CredentialType.PASSWORD,
                     appLabel,
                     context.getDrawable(R.drawable.ic_password_24) ?: return null,
-                    preferImmediatelyAvailableCredentials = false,
+                    preferImmediatelyAvailableCredentials =
+                    createCredentialRequestJetpack.preferImmediatelyAvailableCredentials,
                     appPreferredDefaultProviderId = appPreferredDefaultProviderId,
                     userSetDefaultProviderIds = requestInfo.defaultProviderIds.toSet(),
                 )
@@ -509,7 +510,8 @@
                         appName = appLabel,
                         typeIcon = displayInfo.credentialTypeIcon?.loadDrawable(context)
                             ?: context.getDrawable(R.drawable.ic_other_sign_in_24) ?: return null,
-                        preferImmediatelyAvailableCredentials = false,
+                        preferImmediatelyAvailableCredentials =
+                        createCredentialRequestJetpack.preferImmediatelyAvailableCredentials,
                         appPreferredDefaultProviderId = appPreferredDefaultProviderId,
                         userSetDefaultProviderIds = requestInfo.defaultProviderIds.toSet(),
                     )
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 706666c..2e49dd5 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -841,7 +841,8 @@
                  Settings.Secure.ACCESSIBILITY_SHOW_WINDOW_MAGNIFICATION_PROMPT,
                  Settings.Secure.ACCESSIBILITY_FLOATING_MENU_MIGRATION_TOOLTIP_PROMPT,
                  Settings.Secure.UI_TRANSLATION_ENABLED,
-                 Settings.Secure.CREDENTIAL_SERVICE);
+                 Settings.Secure.CREDENTIAL_SERVICE,
+                 Settings.Secure.CREDENTIAL_SERVICE_PRIMARY);
 
     @Test
     public void systemSettingsBackedUpOrDenied() {
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index a110f56..8b3fd41 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -17,12 +17,12 @@
  */
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.shell"
-        coreApp="true"
-        android:sharedUserId="android.uid.shell"
-        >
+   package="com.android.shell"
+   coreApp="true"
+   android:sharedUserId="android.uid.shell"
+   >
 
-        <!-- Standard permissions granted to the shell. -->
+    <!-- Standard permissions granted to the shell. -->
     <uses-permission android:name="android.permission.MANAGE_HEALTH_PERMISSIONS" />
     <uses-permission android:name="android.permission.MANAGE_HEALTH_DATA" />
     <uses-permission android:name="android.permission.health.READ_EXERCISE_ROUTE" />
@@ -125,7 +125,7 @@
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
     <uses-permission android:name="android.permission.BLUETOOTH" />
     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
-    <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE"/>
+    <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
     <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
     <!-- BLUETOOTH_PRIVILEGED is needed for testing purposes only. -->
     <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
@@ -136,7 +136,7 @@
     <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
     <uses-permission android:name="android.permission.MANAGE_USB" />
     <uses-permission android:name="android.permission.USE_RESERVED_DISK" />
-    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
+    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
     <!-- System tool permissions granted to the shell. -->
     <uses-permission android:name="android.permission.REAL_GET_TASKS" />
     <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
@@ -231,16 +231,16 @@
     <uses-permission android:name="android.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS" />
     <uses-permission android:name="android.permission.CLEAR_FREEZE_PERIOD" />
     <uses-permission android:name="android.permission.MODIFY_QUIET_MODE" />
-    <uses-permission android:name="android.permission.ACCESS_LOWPAN_STATE"/>
-    <uses-permission android:name="android.permission.CHANGE_LOWPAN_STATE"/>
-    <uses-permission android:name="android.permission.READ_LOWPAN_CREDENTIAL"/>
+    <uses-permission android:name="android.permission.ACCESS_LOWPAN_STATE" />
+    <uses-permission android:name="android.permission.CHANGE_LOWPAN_STATE" />
+    <uses-permission android:name="android.permission.READ_LOWPAN_CREDENTIAL" />
     <uses-permission android:name="android.permission.BLUETOOTH_STACK" />
     <uses-permission android:name="android.permission.GET_ACCOUNTS" />
     <uses-permission android:name="android.permission.RETRIEVE_WINDOW_TOKEN" />
     <uses-permission android:name="android.permission.FRAME_STATS" />
     <uses-permission android:name="android.permission.BIND_APPWIDGET" />
     <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
-    <uses-permission android:name="android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS"/>
+    <uses-permission android:name="android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS" />
     <uses-permission android:name="android.permission.CHANGE_APP_IDLE_STATE" />
     <uses-permission android:name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST" />
     <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
@@ -304,7 +304,7 @@
     <uses-permission android:name="android.permission.CAMERA" />
     <uses-permission android:name="android.permission.BACKGROUND_CAMERA" />
     <uses-permission android:name="android.permission.SYSTEM_CAMERA" />
-      <!-- Permissions needed to test onCameraOpened/Closed callbacks -->
+    <!-- Permissions needed to test onCameraOpened/Closed callbacks -->
     <uses-permission android:name="android.permission.CAMERA_OPEN_CLOSE_LISTENER" />
     <!-- Permissions needed for CTS camera test: RecordingTest.java when assuming shell id -->
     <uses-permission android:name="android.permission.RECORD_AUDIO" />
@@ -344,7 +344,7 @@
     <uses-permission android:name="android.permission.LOADER_USAGE_STATS" />
 
     <!-- Permission required for storage tests - FuseDaemonHostTest -->
-    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
+    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
 
     <!-- Permission needed to run network tests in CTS -->
     <uses-permission android:name="android.permission.MANAGE_TEST_NETWORKS" />
@@ -386,54 +386,54 @@
     <uses-permission android:name="android.permission.BIND_EXPLICIT_HEALTH_CHECK_SERVICE" />
 
     <!-- Permission required for CTS test - CrossProfileAppsHostSideTest -->
-    <uses-permission android:name="android.permission.INTERACT_ACROSS_PROFILES"/>
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_PROFILES" />
 
     <!-- Permission required for CTS test - CrossProfileAppsHostSideTest -->
-    <uses-permission android:name="android.permission.START_CROSS_PROFILE_ACTIVITIES"/>
+    <uses-permission android:name="android.permission.START_CROSS_PROFILE_ACTIVITIES" />
 
     <!-- permissions required for CTS test - PhoneStateListenerTest -->
     <uses-permission android:name="android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH" />
 
     <!-- Permissions required for granting and logging -->
-    <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE"/>
-    <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG"/>
-    <uses-permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG"/>
-    <uses-permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD"/>
+    <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE" />
+    <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
+    <uses-permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG" />
+    <uses-permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD" />
 
     <!-- Permission required for CTS test - BatterySaverTest -->
-    <uses-permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE"/>
+    <uses-permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE" />
 
     <!-- Permission required for CTS test - UiModeManagerTest -->
-    <uses-permission android:name="android.permission.ENTER_CAR_MODE_PRIORITIZED"/>
-    <uses-permission android:name="android.permission.READ_PROJECTION_STATE"/>
+    <uses-permission android:name="android.permission.ENTER_CAR_MODE_PRIORITIZED" />
+    <uses-permission android:name="android.permission.READ_PROJECTION_STATE" />
 
     <!-- Permission required for CTS tests - UiModeManagerTest, CarModeInCallServiceTest -->
-    <uses-permission android:name="android.permission.TOGGLE_AUTOMOTIVE_PROJECTION"/>
+    <uses-permission android:name="android.permission.TOGGLE_AUTOMOTIVE_PROJECTION" />
 
     <!-- Permission required for CTS test - SystemConfigTest -->
-    <uses-permission android:name="android.permission.READ_CARRIER_APP_INFO"/>
+    <uses-permission android:name="android.permission.READ_CARRIER_APP_INFO" />
 
     <!-- Permission required for CTS test - CarModeInCallServiceTest -->
-    <uses-permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE"/>
+    <uses-permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE" />
 
     <!-- Permission requried for CTS test - CellBroadcastIntentsTest -->
-    <uses-permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS"/>
+    <uses-permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS" />
 
     <!-- Permission required for CTS test - TetheringManagerTest -->
-    <uses-permission android:name="android.permission.TETHER_PRIVILEGED"/>
+    <uses-permission android:name="android.permission.TETHER_PRIVILEGED" />
 
     <!-- Permission required for CTS test - CtsOsTestCases -->
-    <uses-permission android:name="android.permission.MANAGE_CRATES"/>
+    <uses-permission android:name="android.permission.MANAGE_CRATES" />
 
     <!-- Allows setting brightness from the shell -->
-    <uses-permission android:name="android.permission.CONTROL_DISPLAY_BRIGHTNESS"/>
+    <uses-permission android:name="android.permission.CONTROL_DISPLAY_BRIGHTNESS" />
 
     <!-- Permission required for CTS test - ShortcutManagerUsageTest -->
-    <uses-permission android:name="android.permission.ACCESS_SHORTCUTS"/>
+    <uses-permission android:name="android.permission.ACCESS_SHORTCUTS" />
 
     <!-- Permissions required for CTS test - UsageStatsTest -->
-    <uses-permission android:name="android.permission.MANAGE_NOTIFICATIONS"/>
-    <uses-permission android:name="android.permission.ACCESS_LOCUS_ID_USAGE_STATS"/>
+    <uses-permission android:name="android.permission.MANAGE_NOTIFICATIONS" />
+    <uses-permission android:name="android.permission.ACCESS_LOCUS_ID_USAGE_STATS" />
 
     <!-- Permission needed for CTS test - MusicRecognitionManagerTest -->
     <uses-permission android:name="android.permission.MANAGE_MUSIC_RECOGNITION" />
@@ -442,8 +442,8 @@
     <uses-permission android:name="android.permission.MANAGE_SPEECH_RECOGNITION" />
 
     <!-- Permissions required to test ambient display. -->
-    <uses-permission android:name="android.permission.READ_DREAM_STATE"/>
-    <uses-permission android:name="android.permission.WRITE_DREAM_STATE"/>
+    <uses-permission android:name="android.permission.READ_DREAM_STATE" />
+    <uses-permission android:name="android.permission.WRITE_DREAM_STATE" />
 
     <!-- Permission required for CTS test - CtsLightsManagerTest -->
     <uses-permission android:name="android.permission.CONTROL_DEVICE_LIGHTS" />
@@ -470,7 +470,7 @@
     <uses-permission android:name="android.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE" />
 
     <!-- Permission required for testing system audio effect APIs. -->
-    <uses-permission android:name="android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS"/>
+    <uses-permission android:name="android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS" />
 
     <!-- Permission required for running networking unit tests -->
     <uses-permission android:name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS" />
@@ -495,7 +495,7 @@
     <uses-permission android:name="android.permission.TV_INPUT_HARDWARE" />
     <uses-permission android:name="android.permission.TIS_EXTENSION_INTERFACE" />
     <uses-permission android:name="com.android.providers.tv.permission.ACCESS_WATCHED_PROGRAMS" />
-    <uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA"/>
+    <uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />
 
     <!-- Permission needed for CTS test - PrivilegedLocationPermissionTest -->
     <uses-permission android:name="android.permission.LOCATION_HARDWARE" />
@@ -560,14 +560,14 @@
     <uses-permission android:name="android.permission.BIND_CARRIER_SERVICES" />
 
     <!-- Allows overriding the system's device state from the shell -->
-    <uses-permission android:name="android.permission.CONTROL_DEVICE_STATE"/>
+    <uses-permission android:name="android.permission.CONTROL_DEVICE_STATE" />
 
     <!-- Permissions required for CTS tests to close system dialogs -->
     <uses-permission android:name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS" />
 
     <!-- Permissions required for CTS test - HideOverlayWindowsTest -->
-    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
-    <uses-permission android:name="android.permission.SYSTEM_APPLICATION_OVERLAY"/>
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+    <uses-permission android:name="android.permission.SYSTEM_APPLICATION_OVERLAY" />
 
     <!-- Permission required for CTS test - CtsHdmiCecHostTestCases -->
     <uses-permission android:name="android.permission.HDMI_CEC" />
@@ -630,21 +630,21 @@
     <uses-permission android:name="android.permission.UPDATE_FONTS" />
 
     <!-- Permission required for Launcher testing - DigitalWellbeingToastTest -->
-    <uses-permission android:name="android.permission.GET_TOP_ACTIVITY_INFO"/>
+    <uses-permission android:name="android.permission.GET_TOP_ACTIVITY_INFO" />
 
     <!-- Permission required for hotword detection service CTS tests -->
     <uses-permission android:name="android.permission.MANAGE_HOTWORD_DETECTION" />
     <uses-permission android:name="android.permission.BIND_HOTWORD_DETECTION_SERVICE" />
 
     <!-- Permission required for CTS test - CtsVoiceInteractionTestCases -->
-    <uses-permission android:name="android.permission.SOUND_TRIGGER_RUN_IN_BATTERY_SAVER"/>
+    <uses-permission android:name="android.permission.SOUND_TRIGGER_RUN_IN_BATTERY_SAVER" />
 
     <uses-permission android:name="android.permission.BIND_VISUAL_QUERY_DETECTION_SERVICE" />
 
     <!-- Permission required for CTS test - KeyguardLockedStateApiTest -->
     <uses-permission android:name="android.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE" />
 
-    <uses-permission android:name="android.permission.MANAGE_APP_HIBERNATION"/>
+    <uses-permission android:name="android.permission.MANAGE_APP_HIBERNATION" />
 
     <!-- Permission required for CTS test - MediaCodecResourceTest -->
     <uses-permission android:name="android.permission.MEDIA_RESOURCE_OVERRIDE_PID" />
@@ -820,8 +820,8 @@
     <uses-permission android:name="android.permission.DELETE_STAGED_HEALTH_CONNECT_REMOTE_DATA" />
     <uses-permission android:name="android.permission.STAGE_HEALTH_CONNECT_REMOTE_DATA" />
 
-    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
-    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED"/>
+    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
+    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED" />
 
     <!-- Permissions required for CTS test - CtsBroadcastRadioTestCases -->
     <uses-permission android:name="android.permission.ACCESS_BROADCAST_RADIO" />
@@ -832,12 +832,17 @@
     <!-- Permission required for CTS test - CtsTelephonyProviderTestCases -->
     <uses-permission android:name="android.permission.WRITE_APN_SETTINGS" />
 
-    <uses-permission android:name="android.permission.LOG_FOREGROUND_RESOURCE_USE"/>
+    <uses-permission android:name="android.permission.LOG_FOREGROUND_RESOURCE_USE" />
+    <!-- Permission required for GTS test - GtsAttestationVerificationDeviceSideTestCases -->
+    <uses-permission android:name="android.permission.USE_ATTESTATION_VERIFICATION_SERVICE" />
+    <!-- Permission required for GTS test - GtsCredentialsTestCases -->
+    <uses-permission android:name="android.permission.LAUNCH_CREDENTIAL_SELECTOR" />
 
-    <application android:label="@string/app_label"
-                android:theme="@android:style/Theme.DeviceDefault.DayNight"
-                android:defaultToDeviceProtectedStorage="true"
-                android:directBootAware="true">
+    <application
+        android:label="@string/app_label"
+        android:theme="@android:style/Theme.DeviceDefault.DayNight"
+        android:defaultToDeviceProtectedStorage="true"
+        android:directBootAware="true">
         <provider
             android:name="androidx.core.content.FileProvider"
             android:authorities="com.android.shell"
@@ -860,10 +865,11 @@
             </intent-filter>
         </provider>
 
-        <provider android:name=".HeapDumpProvider"
-                  android:authorities="com.android.shell.heapdump"
-                  android:grantUriPermissions="true"
-                  android:exported="false" />
+        <provider
+            android:name=".HeapDumpProvider"
+            android:authorities="com.android.shell.heapdump"
+            android:grantUriPermissions="true"
+            android:exported="false" />
 
         <activity
             android:name=".BugreportWarningActivity"
@@ -872,13 +878,14 @@
             android:excludeFromRecents="true"
             android:exported="false" />
 
-        <activity android:name=".HeapDumpActivity"
-                  android:theme="@*android:style/Theme.Translucent.NoTitleBar"
-                  android:label="@*android:string/dump_heap_title"
-                  android:finishOnCloseSystemDialogs="true"
-                  android:noHistory="true"
-                  android:excludeFromRecents="true"
-                  android:exported="false" />
+        <activity
+            android:name=".HeapDumpActivity"
+            android:theme="@*android:style/Theme.Translucent.NoTitleBar"
+            android:label="@*android:string/dump_heap_title"
+            android:finishOnCloseSystemDialogs="true"
+            android:noHistory="true"
+            android:excludeFromRecents="true"
+            android:exported="false" />
 
         <receiver
             android:name=".BugreportRequestedReceiver"
@@ -903,7 +910,7 @@
         <receiver
             android:name=".ProfcollectUploadReceiver"
             android:exported="true"
-            android:permission="android.permission.TRIGGER_SHELL_PROFCOLLECT_UPLOAD" >
+            android:permission="android.permission.TRIGGER_SHELL_PROFCOLLECT_UPLOAD">
             <intent-filter>
                 <action android:name="com.android.shell.action.PROFCOLLECT_UPLOAD" />
             </intent-filter>
@@ -912,6 +919,6 @@
         <service
             android:name=".BugreportProgressService"
             android:foregroundServiceType="systemExempted"
-            android:exported="false"/>
+            android:exported="false" />
     </application>
 </manifest>
diff --git a/packages/SystemUI/animation/Android.bp b/packages/SystemUI/animation/Android.bp
index 5b5871f..8eb012d 100644
--- a/packages/SystemUI/animation/Android.bp
+++ b/packages/SystemUI/animation/Android.bp
@@ -43,6 +43,7 @@
         "androidx.core_core-ktx",
         "androidx.annotation_annotation",
         "SystemUIShaderLib",
+        "animationlib",
     ],
 
     manifest: "AndroidManifest.xml",
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
index 94b3740..4037fd4 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -39,9 +39,9 @@
 import android.view.animation.PathInterpolator
 import androidx.annotation.BinderThread
 import androidx.annotation.UiThread
+import com.android.app.animation.Interpolators
 import com.android.internal.annotations.VisibleForTesting
 import com.android.internal.policy.ScreenDecorationsUtils
-import java.lang.IllegalArgumentException
 import kotlin.math.roundToInt
 
 private const val TAG = "ActivityLaunchAnimator"
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
index 42a8636..48dd08f 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
@@ -33,10 +33,10 @@
 import android.view.WindowManager
 import android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
 import android.widget.FrameLayout
+import com.android.app.animation.Interpolators
 import com.android.internal.jank.InteractionJankMonitor
 import com.android.internal.jank.InteractionJankMonitor.CujType
 import com.android.systemui.util.registerAnimationOnBackInvoked
-import java.lang.IllegalArgumentException
 import kotlin.math.roundToInt
 
 private const val TAG = "DialogLaunchAnimator"
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java b/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
deleted file mode 100644
index 9dbb920..0000000
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Copyright (C) 2016 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.animation;
-
-import android.graphics.Path;
-import android.util.MathUtils;
-import android.view.animation.AccelerateDecelerateInterpolator;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.BounceInterpolator;
-import android.view.animation.DecelerateInterpolator;
-import android.view.animation.Interpolator;
-import android.view.animation.LinearInterpolator;
-import android.view.animation.PathInterpolator;
-
-/**
- * Utility class to receive interpolators from.
- *
- * Make sure that changes made to this class are also reflected in {@link InterpolatorsAndroidX}.
- * Please consider using the androidx dependencies featuring better testability altogether.
- */
-public class Interpolators {
-
-    /*
-     * ============================================================================================
-     * Emphasized interpolators.
-     * ============================================================================================
-     */
-
-    /**
-     * The default emphasized interpolator. Used for hero / emphasized movement of content.
-     */
-    public static final Interpolator EMPHASIZED = createEmphasizedInterpolator();
-
-    /**
-     * The accelerated emphasized interpolator. Used for hero / emphasized movement of content that
-     * is disappearing e.g. when moving off screen.
-     */
-    public static final Interpolator EMPHASIZED_ACCELERATE = new PathInterpolator(
-            0.3f, 0f, 0.8f, 0.15f);
-
-    /**
-     * The decelerating emphasized interpolator. Used for hero / emphasized movement of content that
-     * is appearing e.g. when coming from off screen
-     */
-    public static final Interpolator EMPHASIZED_DECELERATE = new PathInterpolator(
-            0.05f, 0.7f, 0.1f, 1f);
-
-
-    /*
-     * ============================================================================================
-     * Standard interpolators.
-     * ============================================================================================
-     */
-
-    /**
-     * The standard interpolator that should be used on every normal animation
-     */
-    public static final Interpolator STANDARD = new PathInterpolator(
-            0.2f, 0f, 0f, 1f);
-
-    /**
-     * The standard accelerating interpolator that should be used on every regular movement of
-     * content that is disappearing e.g. when moving off screen.
-     */
-    public static final Interpolator STANDARD_ACCELERATE = new PathInterpolator(
-            0.3f, 0f, 1f, 1f);
-
-    /**
-     * The standard decelerating interpolator that should be used on every regular movement of
-     * content that is appearing e.g. when coming from off screen.
-     */
-    public static final Interpolator STANDARD_DECELERATE = new PathInterpolator(
-            0f, 0f, 0f, 1f);
-
-    /*
-     * ============================================================================================
-     * Legacy
-     * ============================================================================================
-     */
-
-    /**
-     * The default legacy interpolator as defined in Material 1. Also known as FAST_OUT_SLOW_IN.
-     */
-    public static final Interpolator LEGACY = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
-
-    /**
-     * The default legacy accelerating interpolator as defined in Material 1.
-     * Also known as FAST_OUT_LINEAR_IN.
-     */
-    public static final Interpolator LEGACY_ACCELERATE = new PathInterpolator(0.4f, 0f, 1f, 1f);
-
-    /**
-     * The default legacy decelerating interpolator as defined in Material 1.
-     * Also known as LINEAR_OUT_SLOW_IN.
-     */
-    public static final Interpolator LEGACY_DECELERATE = new PathInterpolator(0f, 0f, 0.2f, 1f);
-
-    /**
-     * Linear interpolator. Often used if the interpolator is for different properties who need
-     * different interpolations.
-     */
-    public static final Interpolator LINEAR = new LinearInterpolator();
-
-    /*
-    * ============================================================================================
-    * Custom interpolators
-    * ============================================================================================
-    */
-
-    public static final Interpolator FAST_OUT_SLOW_IN = LEGACY;
-    public static final Interpolator FAST_OUT_LINEAR_IN = LEGACY_ACCELERATE;
-    public static final Interpolator LINEAR_OUT_SLOW_IN = LEGACY_DECELERATE;
-
-    /**
-     * Like {@link #FAST_OUT_SLOW_IN}, but used in case the animation is played in reverse (i.e. t
-     * goes from 1 to 0 instead of 0 to 1).
-     */
-    public static final Interpolator FAST_OUT_SLOW_IN_REVERSE =
-            new PathInterpolator(0.8f, 0f, 0.6f, 1f);
-    public static final Interpolator SLOW_OUT_LINEAR_IN = new PathInterpolator(0.8f, 0f, 1f, 1f);
-    public static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
-    public static final Interpolator ALPHA_OUT = new PathInterpolator(0f, 0f, 0.8f, 1f);
-    public static final Interpolator ACCELERATE = new AccelerateInterpolator();
-    public static final Interpolator ACCELERATE_DECELERATE = new AccelerateDecelerateInterpolator();
-    public static final Interpolator DECELERATE_QUINT = new DecelerateInterpolator(2.5f);
-    public static final Interpolator CUSTOM_40_40 = new PathInterpolator(0.4f, 0f, 0.6f, 1f);
-    public static final Interpolator ICON_OVERSHOT = new PathInterpolator(0.4f, 0f, 0.2f, 1.4f);
-    public static final Interpolator ICON_OVERSHOT_LESS = new PathInterpolator(0.4f, 0f, 0.2f,
-            1.1f);
-    public static final Interpolator PANEL_CLOSE_ACCELERATED = new PathInterpolator(0.3f, 0, 0.5f,
-            1);
-    public static final Interpolator BOUNCE = new BounceInterpolator();
-    /**
-     * For state transitions on the control panel that lives in GlobalActions.
-     */
-    public static final Interpolator CONTROL_STATE = new PathInterpolator(0.4f, 0f, 0.2f,
-            1.0f);
-
-    /**
-     * Interpolator to be used when animating a move based on a click. Pair with enough duration.
-     */
-    public static final Interpolator TOUCH_RESPONSE =
-            new PathInterpolator(0.3f, 0f, 0.1f, 1f);
-
-    /**
-     * Like {@link #TOUCH_RESPONSE}, but used in case the animation is played in reverse (i.e. t
-     * goes from 1 to 0 instead of 0 to 1).
-     */
-    public static final Interpolator TOUCH_RESPONSE_REVERSE =
-            new PathInterpolator(0.9f, 0f, 0.7f, 1f);
-
-    /*
-     * ============================================================================================
-     * Functions / Utilities
-     * ============================================================================================
-     */
-
-    /**
-     * Calculate the amount of overshoot using an exponential falloff function with desired
-     * properties, where the overshoot smoothly transitions at the 1.0f boundary into the
-     * overshoot, retaining its acceleration.
-     *
-     * @param progress a progress value going from 0 to 1
-     * @param overshootAmount the amount > 0 of overshoot desired. A value of 0.1 means the max
-     *                        value of the overall progress will be at 1.1.
-     * @param overshootStart the point in (0,1] where the result should reach 1
-     * @return the interpolated overshoot
-     */
-    public static float getOvershootInterpolation(float progress, float overshootAmount,
-            float overshootStart) {
-        if (overshootAmount == 0.0f || overshootStart == 0.0f) {
-            throw new IllegalArgumentException("Invalid values for overshoot");
-        }
-        float b = MathUtils.log((overshootAmount + 1) / (overshootAmount)) / overshootStart;
-        return MathUtils.max(0.0f,
-                (float) (1.0f - Math.exp(-b * progress)) * (overshootAmount + 1.0f));
-    }
-
-    /**
-     * Similar to {@link #getOvershootInterpolation(float, float, float)} but the overshoot
-     * starts immediately here, instead of first having a section of non-overshooting
-     *
-     * @param progress a progress value going from 0 to 1
-     */
-    public static float getOvershootInterpolation(float progress) {
-        return MathUtils.max(0.0f, (float) (1.0f - Math.exp(-4 * progress)));
-    }
-
-    // Create the default emphasized interpolator
-    private static PathInterpolator createEmphasizedInterpolator() {
-        Path path = new Path();
-        // Doing the same as fast_out_extra_slow_in
-        path.moveTo(0f, 0f);
-        path.cubicTo(0.05f, 0f, 0.133333f, 0.06f, 0.166666f, 0.4f);
-        path.cubicTo(0.208333f, 0.82f, 0.25f, 1f, 1f, 1f);
-        return new PathInterpolator(path);
-    }
-}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/InterpolatorsAndroidX.java b/packages/SystemUI/animation/src/com/android/systemui/animation/InterpolatorsAndroidX.java
deleted file mode 100644
index 8da87feb..0000000
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/InterpolatorsAndroidX.java
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.systemui.animation;
-
-import android.graphics.Path;
-import android.util.MathUtils;
-
-import androidx.core.animation.AccelerateDecelerateInterpolator;
-import androidx.core.animation.AccelerateInterpolator;
-import androidx.core.animation.BounceInterpolator;
-import androidx.core.animation.DecelerateInterpolator;
-import androidx.core.animation.Interpolator;
-import androidx.core.animation.LinearInterpolator;
-import androidx.core.animation.PathInterpolator;
-
-/**
- * Utility class to receive interpolators from. (androidx compatible version)
- *
- * This is the androidx compatible version of {@link Interpolators}. Make sure that changes made to
- * this class are also reflected in {@link Interpolators}.
- *
- * Using the androidx versions of {@link androidx.core.animation.ValueAnimator} or
- * {@link androidx.core.animation.ObjectAnimator} improves animation testability. This file provides
- * the androidx compatible versions of the interpolators defined in {@link Interpolators}.
- * AnimatorTestRule can be used in Tests to manipulate the animation under test (e.g. artificially
- * advancing the time).
- */
-public class InterpolatorsAndroidX {
-
-    /*
-     * ============================================================================================
-     * Emphasized interpolators.
-     * ============================================================================================
-     */
-
-    /**
-     * The default emphasized interpolator. Used for hero / emphasized movement of content.
-     */
-    public static final Interpolator EMPHASIZED = createEmphasizedInterpolator();
-
-    /**
-     * The accelerated emphasized interpolator. Used for hero / emphasized movement of content that
-     * is disappearing e.g. when moving off screen.
-     */
-    public static final Interpolator EMPHASIZED_ACCELERATE = new PathInterpolator(
-            0.3f, 0f, 0.8f, 0.15f);
-
-    /**
-     * The decelerating emphasized interpolator. Used for hero / emphasized movement of content that
-     * is appearing e.g. when coming from off screen
-     */
-    public static final Interpolator EMPHASIZED_DECELERATE = new PathInterpolator(
-            0.05f, 0.7f, 0.1f, 1f);
-
-
-    /*
-     * ============================================================================================
-     * Standard interpolators.
-     * ============================================================================================
-     */
-
-    /**
-     * The standard interpolator that should be used on every normal animation
-     */
-    public static final Interpolator STANDARD = new PathInterpolator(
-            0.2f, 0f, 0f, 1f);
-
-    /**
-     * The standard accelerating interpolator that should be used on every regular movement of
-     * content that is disappearing e.g. when moving off screen.
-     */
-    public static final Interpolator STANDARD_ACCELERATE = new PathInterpolator(
-            0.3f, 0f, 1f, 1f);
-
-    /**
-     * The standard decelerating interpolator that should be used on every regular movement of
-     * content that is appearing e.g. when coming from off screen.
-     */
-    public static final Interpolator STANDARD_DECELERATE = new PathInterpolator(
-            0f, 0f, 0f, 1f);
-
-    /*
-     * ============================================================================================
-     * Legacy
-     * ============================================================================================
-     */
-
-    /**
-     * The default legacy interpolator as defined in Material 1. Also known as FAST_OUT_SLOW_IN.
-     */
-    public static final Interpolator LEGACY = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
-
-    /**
-     * The default legacy accelerating interpolator as defined in Material 1.
-     * Also known as FAST_OUT_LINEAR_IN.
-     */
-    public static final Interpolator LEGACY_ACCELERATE = new PathInterpolator(0.4f, 0f, 1f, 1f);
-
-    /**
-     * The default legacy decelerating interpolator as defined in Material 1.
-     * Also known as LINEAR_OUT_SLOW_IN.
-     */
-    public static final Interpolator LEGACY_DECELERATE = new PathInterpolator(0f, 0f, 0.2f, 1f);
-
-    /**
-     * Linear interpolator. Often used if the interpolator is for different properties who need
-     * different interpolations.
-     */
-    public static final Interpolator LINEAR = new LinearInterpolator();
-
-    /*
-    * ============================================================================================
-    * Custom interpolators
-    * ============================================================================================
-    */
-
-    public static final Interpolator FAST_OUT_SLOW_IN = LEGACY;
-    public static final Interpolator FAST_OUT_LINEAR_IN = LEGACY_ACCELERATE;
-    public static final Interpolator LINEAR_OUT_SLOW_IN = LEGACY_DECELERATE;
-
-    /**
-     * Like {@link #FAST_OUT_SLOW_IN}, but used in case the animation is played in reverse (i.e. t
-     * goes from 1 to 0 instead of 0 to 1).
-     */
-    public static final Interpolator FAST_OUT_SLOW_IN_REVERSE =
-            new PathInterpolator(0.8f, 0f, 0.6f, 1f);
-    public static final Interpolator SLOW_OUT_LINEAR_IN = new PathInterpolator(0.8f, 0f, 1f, 1f);
-    public static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
-    public static final Interpolator ALPHA_OUT = new PathInterpolator(0f, 0f, 0.8f, 1f);
-    public static final Interpolator ACCELERATE = new AccelerateInterpolator();
-    public static final Interpolator ACCELERATE_DECELERATE = new AccelerateDecelerateInterpolator();
-    public static final Interpolator DECELERATE_QUINT = new DecelerateInterpolator(2.5f);
-    public static final Interpolator CUSTOM_40_40 = new PathInterpolator(0.4f, 0f, 0.6f, 1f);
-    public static final Interpolator ICON_OVERSHOT = new PathInterpolator(0.4f, 0f, 0.2f, 1.4f);
-    public static final Interpolator ICON_OVERSHOT_LESS = new PathInterpolator(0.4f, 0f, 0.2f,
-            1.1f);
-    public static final Interpolator PANEL_CLOSE_ACCELERATED = new PathInterpolator(0.3f, 0, 0.5f,
-            1);
-    public static final Interpolator BOUNCE = new BounceInterpolator();
-    /**
-     * For state transitions on the control panel that lives in GlobalActions.
-     */
-    public static final Interpolator CONTROL_STATE = new PathInterpolator(0.4f, 0f, 0.2f,
-            1.0f);
-
-    /**
-     * Interpolator to be used when animating a move based on a click. Pair with enough duration.
-     */
-    public static final Interpolator TOUCH_RESPONSE =
-            new PathInterpolator(0.3f, 0f, 0.1f, 1f);
-
-    /**
-     * Like {@link #TOUCH_RESPONSE}, but used in case the animation is played in reverse (i.e. t
-     * goes from 1 to 0 instead of 0 to 1).
-     */
-    public static final Interpolator TOUCH_RESPONSE_REVERSE =
-            new PathInterpolator(0.9f, 0f, 0.7f, 1f);
-
-    /*
-     * ============================================================================================
-     * Functions / Utilities
-     * ============================================================================================
-     */
-
-    /**
-     * Calculate the amount of overshoot using an exponential falloff function with desired
-     * properties, where the overshoot smoothly transitions at the 1.0f boundary into the
-     * overshoot, retaining its acceleration.
-     *
-     * @param progress a progress value going from 0 to 1
-     * @param overshootAmount the amount > 0 of overshoot desired. A value of 0.1 means the max
-     *                        value of the overall progress will be at 1.1.
-     * @param overshootStart the point in (0,1] where the result should reach 1
-     * @return the interpolated overshoot
-     */
-    public static float getOvershootInterpolation(float progress, float overshootAmount,
-            float overshootStart) {
-        if (overshootAmount == 0.0f || overshootStart == 0.0f) {
-            throw new IllegalArgumentException("Invalid values for overshoot");
-        }
-        float b = MathUtils.log((overshootAmount + 1) / (overshootAmount)) / overshootStart;
-        return MathUtils.max(0.0f,
-                (float) (1.0f - Math.exp(-b * progress)) * (overshootAmount + 1.0f));
-    }
-
-    /**
-     * Similar to {@link #getOvershootInterpolation(float, float, float)} but the overshoot
-     * starts immediately here, instead of first having a section of non-overshooting
-     *
-     * @param progress a progress value going from 0 to 1
-     */
-    public static float getOvershootInterpolation(float progress) {
-        return MathUtils.max(0.0f, (float) (1.0f - Math.exp(-4 * progress)));
-    }
-
-    // Create the default emphasized interpolator
-    private static PathInterpolator createEmphasizedInterpolator() {
-        Path path = new Path();
-        // Doing the same as fast_out_extra_slow_in
-        path.moveTo(0f, 0f);
-        path.cubicTo(0.05f, 0f, 0.133333f, 0.06f, 0.166666f, 0.4f);
-        path.cubicTo(0.208333f, 0.82f, 0.25f, 1f, 1f, 1f);
-        return new PathInterpolator(path);
-    }
-}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt
index 3417ffd..142fd21 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt
@@ -28,7 +28,7 @@
 import android.view.View
 import android.view.ViewGroup
 import android.view.animation.Interpolator
-import com.android.systemui.animation.Interpolators.LINEAR
+import com.android.app.animation.Interpolators.LINEAR
 import kotlin.math.roundToInt
 
 private const val TAG = "LaunchAnimator"
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
index 58ffef2..8e79e3c 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
@@ -25,6 +25,7 @@
 import android.view.View
 import android.view.ViewGroup
 import android.view.animation.Interpolator
+import com.android.app.animation.Interpolators
 import kotlin.math.max
 import kotlin.math.min
 
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt
index f3d8b17..dd32851 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/back/BackAnimationSpec.kt
@@ -19,7 +19,7 @@
 import android.util.DisplayMetrics
 import android.view.animation.Interpolator
 import android.window.BackEvent
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
 import com.android.systemui.util.dpToPx
 
 /** Used to convert [BackEvent] into a [BackTransformation]. */
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
index 941a925..8dd2c39 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
@@ -28,9 +28,9 @@
 import android.util.AttributeSet
 import android.util.MathUtils.constrainedMap
 import android.widget.TextView
+import com.android.app.animation.Interpolators
 import com.android.internal.annotations.VisibleForTesting
 import com.android.systemui.animation.GlyphCallback
-import com.android.systemui.animation.Interpolators
 import com.android.systemui.animation.TextAnimator
 import com.android.systemui.customization.R
 import com.android.systemui.log.LogBuffer
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/quickaffordance/shared/model/KeyguardPreviewConstants.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/quickaffordance/shared/model/KeyguardPreviewConstants.kt
index 08ee602..6f363a4 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/quickaffordance/shared/model/KeyguardPreviewConstants.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/quickaffordance/shared/model/KeyguardPreviewConstants.kt
@@ -20,6 +20,8 @@
 object KeyguardPreviewConstants {
     const val MESSAGE_ID_HIDE_SMART_SPACE = 1111
     const val KEY_HIDE_SMART_SPACE = "hide_smart_space"
+    const val MESSAGE_ID_COLOR_OVERRIDE = 1234
+    const val KEY_COLOR_OVERRIDE = "color_override" // ColorInt Encoded as string
     const val MESSAGE_ID_SLOT_SELECTED = 1337
     const val KEY_SLOT_ID = "slot_id"
     const val KEY_INITIALLY_SELECTED_SLOT_ID = "initially_selected_slot_id"
diff --git a/packages/SystemUI/res/drawable/ic_keyboard_backlight.xml b/packages/SystemUI/res/drawable/ic_keyboard_backlight.xml
index d123caf..cff2839 100644
--- a/packages/SystemUI/res/drawable/ic_keyboard_backlight.xml
+++ b/packages/SystemUI/res/drawable/ic_keyboard_backlight.xml
@@ -2,11 +2,11 @@
     android:viewportWidth="22" android:width="20.166666dp" xmlns:android="http://schemas.android.com/apk/res/android">
     <group>
         <clip-path android:pathData="M0,0.5h22v11h-22z"/>
-        <path android:fillColor="#231F20" android:pathData="M6.397,9.908H0V11.5H6.397V9.908Z"/>
-        <path android:fillColor="#231F20" android:pathData="M14.199,9.908H7.801V11.5H14.199V9.908Z"/>
-        <path android:fillColor="#231F20" android:pathData="M11.858,0.5H10.142V6.434H11.858V0.5Z"/>
-        <path android:fillColor="#231F20" android:pathData="M8.348,7.129L3.885,2.975L3.823,2.932L2.668,4.003L2.621,4.046L7.084,8.2L7.146,8.243L8.301,7.172L8.348,7.129Z"/>
-        <path android:fillColor="#231F20" android:pathData="M18.224,2.975L18.177,2.932L13.653,7.129L14.807,8.2L14.854,8.243L19.379,4.046L18.224,2.975Z"/>
-        <path android:fillColor="#231F20" android:pathData="M22,9.908H15.603V11.5H22V9.908Z"/>
+        <path android:fillColor="@android:color/white" android:pathData="M6.397,9.908H0V11.5H6.397V9.908Z"/>
+        <path android:fillColor="@android:color/white" android:pathData="M14.199,9.908H7.801V11.5H14.199V9.908Z"/>
+        <path android:fillColor="@android:color/white" android:pathData="M11.858,0.5H10.142V6.434H11.858V0.5Z"/>
+        <path android:fillColor="@android:color/white" android:pathData="M8.348,7.129L3.885,2.975L3.823,2.932L2.668,4.003L2.621,4.046L7.084,8.2L7.146,8.243L8.301,7.172L8.348,7.129Z"/>
+        <path android:fillColor="@android:color/white" android:pathData="M18.224,2.975L18.177,2.932L13.653,7.129L14.807,8.2L14.854,8.243L19.379,4.046L18.224,2.975Z"/>
+        <path android:fillColor="@android:color/white" android:pathData="M22,9.908H15.603V11.5H22V9.908Z"/>
     </group>
 </vector>
diff --git a/packages/SystemUI/res/layout/combined_qs_header.xml b/packages/SystemUI/res/layout/combined_qs_header.xml
index 441f963..386c9d6 100644
--- a/packages/SystemUI/res/layout/combined_qs_header.xml
+++ b/packages/SystemUI/res/layout/combined_qs_header.xml
@@ -14,12 +14,17 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
+
+<!--
+keep split_shade_status_bar height constant to avoid requestLayout calls on each
+frame when animating QS <-> QQS transition
+-->
 <com.android.systemui.util.NoRemeasureMotionLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:id="@+id/split_shade_status_bar"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content"
+    android:layout_height="@dimen/qs_header_height"
     android:minHeight="@dimen/large_screen_shade_header_min_height"
     android:clickable="false"
     android:focusable="true"
@@ -30,6 +35,14 @@
     app:layoutDescription="@xml/combined_qs_header_scene">
 
     <androidx.constraintlayout.widget.Guideline
+        android:id="@+id/qqs_header_bottom_guideline"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        app:layout_constraintGuide_begin="@dimen/large_screen_shade_header_min_height"
+        />
+
+    <androidx.constraintlayout.widget.Guideline
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:id="@+id/begin_guide"
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index cb8c2a7..db7eb7a 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -207,11 +207,6 @@
     <color name="controls_task_view_bg">#CC191C1D</color>
     <color name="control_popup_dim">#8A000000</color>
 
-    <!-- Keyboard backlight indicator-->
-    <color name="backlight_indicator_step_filled">#F6E388</color>
-    <color name="backlight_indicator_step_empty">#494740</color>
-    <color name="backlight_indicator_background">#32302A</color>
-
     <!-- Docked misalignment message -->
     <color name="misalignment_text_color">#F28B82</color>
 
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 1602189..1252695 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -889,4 +889,8 @@
     -->
     <dimen name="shade_swipe_collapse_threshold">0.5</dimen>
     <!-- [END] MULTI SHADE -->
+
+    <!-- Time (in ms) to delay the bouncer views from showing when passive auth may be used for
+    device entry. -->
+    <integer name="primary_bouncer_passive_auth_delay">250</integer>
 </resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 0aa880f..aff0e80 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -615,6 +615,7 @@
     <dimen name="qs_header_carrier_separator_width">6dp</dimen>
     <dimen name="qs_carrier_margin_width">4dp</dimen>
     <dimen name="qs_footer_icon_size">20dp</dimen>
+    <dimen name="qs_header_height">120dp</dimen>
     <dimen name="qs_header_row_min_height">48dp</dimen>
 
     <dimen name="qs_header_non_clickable_element_height">24dp</dimen>
diff --git a/packages/SystemUI/res/xml/qqs_header.xml b/packages/SystemUI/res/xml/qqs_header.xml
index 00a0444..1950965 100644
--- a/packages/SystemUI/res/xml/qqs_header.xml
+++ b/packages/SystemUI/res/xml/qqs_header.xml
@@ -28,7 +28,7 @@
             android:layout_height="@dimen/large_screen_shade_header_min_height"
             app:layout_constraintStart_toStartOf="@id/begin_guide"
             app:layout_constraintTop_toTopOf="parent"
-            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintBottom_toBottomOf="@id/qqs_header_bottom_guideline"
             app:layout_constraintEnd_toStartOf="@id/date"
             app:layout_constraintHorizontal_bias="0"
             app:layout_constraintHorizontal_chainStyle="packed"
@@ -62,7 +62,7 @@
             app:layout_constraintStart_toEndOf="@id/date"
             app:layout_constraintEnd_toStartOf="@id/batteryRemainingIcon"
             app:layout_constraintTop_toTopOf="parent"
-            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintBottom_toBottomOf="@id/qqs_header_bottom_guideline"
             app:layout_constraintHorizontal_bias="1"
             app:layout_constraintHorizontal_chainStyle="packed"
             />
@@ -77,7 +77,7 @@
             app:layout_constraintStart_toEndOf="@id/statusIcons"
             app:layout_constraintEnd_toEndOf="@id/end_guide"
             app:layout_constraintTop_toTopOf="parent"
-            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintBottom_toBottomOf="@id/qqs_header_bottom_guideline"
             app:layout_constraintHorizontal_bias="1"
             app:layout_constraintHorizontal_chainStyle="packed"
             />
@@ -105,7 +105,7 @@
             app:layout_constraintStart_toEndOf="@id/date"
             app:layout_constraintEnd_toEndOf="@id/end_guide"
             app:layout_constraintTop_toTopOf="parent"
-            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintBottom_toBottomOf="@id/qqs_header_bottom_guideline"
             app:layout_constraintHorizontal_bias="1"
         />
     </Constraint>
diff --git a/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt b/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt
index 62f4f22..a82f0e3 100644
--- a/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt
+++ b/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt
@@ -26,8 +26,8 @@
 import android.graphics.Color
 import android.util.AttributeSet
 import android.view.View
+import com.android.app.animation.Interpolators
 import com.android.settingslib.Utils
-import com.android.systemui.animation.Interpolators
 import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.ColorId.TITLE
 
 /** Displays security messages for the keyguard bouncer. */
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 4629e8b..644a9bc 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -15,12 +15,13 @@
 import androidx.annotation.IntDef;
 import androidx.annotation.VisibleForTesting;
 
+import com.android.app.animation.Interpolators;
 import com.android.keyguard.dagger.KeyguardStatusViewScope;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.log.LogBuffer;
 import com.android.systemui.log.LogLevel;
 import com.android.systemui.plugins.ClockController;
+import com.android.systemui.shared.clocks.DefaultClockController;
 
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
@@ -46,6 +47,9 @@
 
     public static final int LARGE = 0;
     public static final int SMALL = 1;
+    // compensate for translation of parents subject to device screen
+    // In this case, the translation comes from KeyguardStatusView
+    public int screenOffsetYPadding = 0;
 
     /** Returns a region for the large clock to position itself, based on the given parent. */
     public static Rect getLargeClockRegion(ViewGroup parent) {
@@ -161,8 +165,18 @@
             }
 
             if (mLargeClockFrame.isLaidOut()) {
-                mClock.getLargeClock().getEvents().onTargetRegionChanged(
-                        getLargeClockRegion(mLargeClockFrame));
+                Rect targetRegion = getLargeClockRegion(mLargeClockFrame);
+                if (mClock instanceof DefaultClockController) {
+                    mClock.getLargeClock().getEvents().onTargetRegionChanged(
+                            targetRegion);
+                } else {
+                    mClock.getLargeClock().getEvents().onTargetRegionChanged(
+                            new Rect(
+                                    targetRegion.left,
+                                    targetRegion.top - screenOffsetYPadding,
+                                    targetRegion.right,
+                                    targetRegion.bottom - screenOffsetYPadding));
+                }
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 50dac32..d8bf570 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -169,6 +169,16 @@
     }
 
     /**
+     * Used for status view to pass the screen offset from parent view
+     */
+    public void setLockscreenClockY(int clockY) {
+        if (mView.screenOffsetYPadding != clockY) {
+            mView.screenOffsetYPadding = clockY;
+            mView.updateClockTargetRegions();
+        }
+    }
+
+    /**
      * Attach the controller to the view it relates to.
      */
     @Override
@@ -394,13 +404,6 @@
             PropertyAnimator.setProperty(mStatusArea, AnimatableProperty.TRANSLATION_X,
                     x, props, animate);
         }
-
-    }
-
-    void updateKeyguardStatusViewOffset() {
-        // updateClockTargetRegions will call onTargetRegionChanged
-        // which will require the correct translationY property of keyguardStatusView after updating
-        mView.updateClockTargetRegions();
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
index 0394754..58807e4 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
@@ -16,6 +16,7 @@
 
 package com.android.keyguard;
 
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_PIN_APPEAR;
 import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_PIN_DISAPPEAR;
 import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_HALF_OPENED;
 import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_UNKNOWN;
@@ -32,9 +33,9 @@
 import androidx.constraintlayout.widget.ConstraintLayout;
 import androidx.constraintlayout.widget.ConstraintSet;
 
+import com.android.app.animation.Interpolators;
 import com.android.settingslib.animation.DisappearAnimationUtils;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.statusbar.policy.DevicePostureController.DevicePostureInt;
 
 /**
@@ -184,6 +185,7 @@
         }
         mAppearAnimator.setDuration(ANIMATION_DURATION);
         mAppearAnimator.addUpdateListener(animation -> animate(animation.getAnimatedFraction()));
+        mAppearAnimator.addListener(getAnimationListener(CUJ_LOCKSCREEN_PIN_APPEAR));
         mAppearAnimator.start();
     }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index 33bea02..1d7c35d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -45,11 +45,11 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.widget.LockscreenCredential;
 import com.android.internal.widget.TextViewInputDisabler;
 import com.android.systemui.DejankUtils;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 /**
  * Displays an alphanumeric (latin-1) key entry for the user to enter
  * an unlock password
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
index 0a91150..b4ddc9a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -34,9 +34,9 @@
 import android.view.KeyEvent;
 import android.view.View;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.widget.LockscreenCredential;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index b88d85c..5cc0547 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -32,7 +32,7 @@
 import static androidx.constraintlayout.widget.ConstraintSet.TOP;
 import static androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT;
 
-import static com.android.systemui.animation.InterpolatorsAndroidX.DECELERATE_QUINT;
+import static com.android.app.animation.InterpolatorsAndroidX.DECELERATE_QUINT;
 import static com.android.systemui.plugins.FalsingManager.LOW_PENALTY;
 
 import static java.lang.Integer.max;
@@ -87,6 +87,7 @@
 import androidx.dynamicanimation.animation.DynamicAnimation;
 import androidx.dynamicanimation.animation.SpringAnimation;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.UiEvent;
 import com.android.internal.logging.UiEventLogger;
@@ -97,7 +98,6 @@
 import com.android.settingslib.drawable.CircleFramedDrawable;
 import com.android.systemui.Gefingerpoken;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.classifier.FalsingA11yDelegate;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.shared.system.SysUiStatsLog;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewTransition.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewTransition.kt
index c9128e5..96ac8ad 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewTransition.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewTransition.kt
@@ -26,9 +26,9 @@
 import android.view.View
 import android.view.ViewGroup
 import android.view.animation.AnimationUtils
+import com.android.app.animation.Interpolators
 import com.android.internal.R.interpolator.fast_out_extra_slow_in
 import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
 
 /** Animates constraint layout changes for the security view. */
 class KeyguardSecurityViewTransition : Transition() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index 65a7166..b4f124a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -44,11 +44,11 @@
 import androidx.slice.widget.RowContent;
 import androidx.slice.widget.SliceContent;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.graphics.ColorUtils;
 import com.android.settingslib.Utils;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.util.wakelock.KeepAwakeAnimationListener;
 
 import java.io.PrintWriter;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index 0826f8a..794eeda 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -40,11 +40,11 @@
 import androidx.constraintlayout.widget.ConstraintLayout;
 import androidx.constraintlayout.widget.ConstraintSet;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.keyguard.KeyguardClockSwitch.ClockSize;
 import com.android.keyguard.logging.KeyguardLogger;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
 import com.android.systemui.plugins.ClockController;
@@ -215,6 +215,15 @@
     }
 
     /**
+     * Pass top margin from ClockPositionAlgorithm in NotificationPanelViewController
+     * Use for clock view in LS to compensate for top margin to align to the screen
+     * Regardless of translation from AOD and unlock gestures
+     */
+    public void setLockscreenClockY(int clockY) {
+        mKeyguardClockSwitchController.setLockscreenClockY(clockY);
+    }
+
+    /**
      * Set whether the view accessibility importance mode.
      */
     public void setStatusAccessibilityImportance(int mode) {
@@ -230,7 +239,6 @@
      * Update position of the view with an optional animation
      */
     public void updatePosition(int x, int y, float scale, boolean animate) {
-        float oldY = mView.getY();
         setProperty(AnimatableProperty.Y, y, animate);
 
         ClockController clock = mKeyguardClockSwitchController.getClock();
@@ -246,10 +254,6 @@
             setProperty(AnimatableProperty.SCALE_X, 1f, animate);
             setProperty(AnimatableProperty.SCALE_Y, 1f, animate);
         }
-
-        if (oldY != y) {
-            mKeyguardClockSwitchController.updateKeyguardStatusViewOffset();
-        }
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 7d7b276..c1f70fb 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -2884,7 +2884,19 @@
         updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
     }
 
+    /**
+     * If the current state of the device allows for triggering active unlock. This does not
+     * include active unlock availability.
+     */
+    public boolean canTriggerActiveUnlockBasedOnDeviceState() {
+        return shouldTriggerActiveUnlock(/* shouldLog */ false);
+    }
+
     private boolean shouldTriggerActiveUnlock() {
+        return shouldTriggerActiveUnlock(/* shouldLog */ true);
+    }
+
+    private boolean shouldTriggerActiveUnlock(boolean shouldLog) {
         // Triggers:
         final boolean triggerActiveUnlockForAssistant = shouldTriggerActiveUnlockForAssistant();
         final boolean awakeKeyguard = mPrimaryBouncerFullyShown || mAlternateBouncerShowing
@@ -2914,19 +2926,21 @@
                         && !mKeyguardGoingAway
                         && !mSecureCameraLaunched;
 
-        // Aggregate relevant fields for debug logging.
-        logListenerModelData(
-                new KeyguardActiveUnlockModel(
-                        System.currentTimeMillis(),
-                        user,
-                        shouldTriggerActiveUnlock,
-                        awakeKeyguard,
-                        mAuthInterruptActive,
-                        fpLockedOut,
-                        primaryAuthRequired,
-                        mSwitchingUser,
-                        triggerActiveUnlockForAssistant,
-                        userCanDismissLockScreen));
+        if (shouldLog) {
+            // Aggregate relevant fields for debug logging.
+            logListenerModelData(
+                    new KeyguardActiveUnlockModel(
+                            System.currentTimeMillis(),
+                            user,
+                            shouldTriggerActiveUnlock,
+                            awakeKeyguard,
+                            mAuthInterruptActive,
+                            fpLockedOut,
+                            primaryAuthRequired,
+                            mSwitchingUser,
+                            triggerActiveUnlockForAssistant,
+                            userCanDismissLockScreen));
+        }
 
         return shouldTriggerActiveUnlock;
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
index d8568ba..61af722 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
@@ -21,7 +21,7 @@
 import android.util.Property;
 import android.view.View;
 
-import com.android.systemui.animation.Interpolators;
+import com.android.app.animation.Interpolators;
 import com.android.systemui.log.LogBuffer;
 import com.android.systemui.log.LogLevel;
 import com.android.systemui.statusbar.StatusBarState;
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
index c6c7113..7d76f12 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
@@ -37,7 +37,7 @@
 
 import androidx.annotation.StyleRes;
 
-import com.android.systemui.animation.Interpolators;
+import com.android.app.animation.Interpolators;
 
 /**
  * Provides background color and radius animations for key pad buttons.
diff --git a/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java b/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java
index 4aeab97..4557b34 100644
--- a/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java
+++ b/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java
@@ -37,9 +37,9 @@
 
 import androidx.core.graphics.drawable.DrawableCompat;
 
+import com.android.app.animation.Interpolators;
 import com.android.settingslib.Utils;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 
 /**
  * This class contains implementation for methods that will be used when user has set a
diff --git a/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt b/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt
index de82ca0..c1871e0 100644
--- a/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt
+++ b/packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt
@@ -36,7 +36,7 @@
 import android.view.View
 import androidx.annotation.VisibleForTesting
 import com.android.systemui.RegionInterceptingFrameLayout.RegionInterceptableView
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
 import com.android.systemui.util.asIndenting
 import java.io.PrintWriter
 
diff --git a/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt b/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt
index 48805be..76086df 100644
--- a/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt
+++ b/packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt
@@ -34,7 +34,7 @@
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.keyguard.KeyguardUpdateMonitorCallback
 import com.android.settingslib.Utils
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
 import com.android.systemui.biometrics.AuthController
 import com.android.systemui.log.ScreenDecorationsLogger
 import com.android.systemui.plugins.statusbar.StatusBarStateController
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index aa94ad9..99d4662 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -43,8 +43,8 @@
 
 import androidx.annotation.VisibleForTesting;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.dynamicanimation.animation.SpringForce;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
 import com.android.systemui.plugins.FalsingManager;
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java b/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java
index d6f0b59..d491975 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java
@@ -32,8 +32,8 @@
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
 
+import com.android.app.animation.Interpolators;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 
 /**
  * Visually discloses that contextual data was provided to an assistant.
diff --git a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
index 0002ae9..2aac056 100644
--- a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
@@ -45,9 +45,9 @@
 import androidx.annotation.StyleRes;
 import androidx.annotation.VisibleForTesting;
 
+import com.android.app.animation.Interpolators;
 import com.android.systemui.DualToneHandler;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.statusbar.policy.BatteryController;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index b386bc9..ce85124 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -59,11 +59,11 @@
 import android.window.OnBackInvokedCallback;
 import android.window.OnBackInvokedDispatcher;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.biometrics.AuthController.ScaleFactorProvider;
 import com.android.systemui.biometrics.domain.interactor.BiometricPromptCredentialInteractor;
 import com.android.systemui.biometrics.ui.CredentialView;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index 55f6d07..6f0f633 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -32,7 +32,7 @@
 import com.android.settingslib.udfps.UdfpsOverlayParams
 import com.android.systemui.CoreStartable
 import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
index b007134..5ede16d 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
@@ -28,7 +28,7 @@
 import android.view.View
 import android.view.animation.PathInterpolator
 import com.android.internal.graphics.ColorUtils
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
 import com.android.systemui.surfaceeffects.ripple.RippleShader
 
 private const val RIPPLE_SPARKLE_STRENGTH: Float = 0.3f
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
index ef7dcb7..1dbafc6 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
@@ -19,7 +19,7 @@
 import android.graphics.PointF
 import android.graphics.RectF
 import com.android.systemui.Dumpable
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.shade.ShadeExpansionListener
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 7a23759..5ee38c3 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -553,6 +553,10 @@
                     + mOverlay.getRequestId());
             return false;
         }
+        if (mLockscreenShadeTransitionController.getQSDragProgress() != 0f
+                || mPrimaryBouncerInteractor.isInTransit()) {
+            return false;
+        }
 
         final TouchProcessorResult result = mTouchProcessor.processTouch(event, mActivePointerId,
                 mOverlayParams);
@@ -626,9 +630,8 @@
             shouldPilfer = true;
         }
 
-        // Execute the pilfer, never pilfer if a vertical swipe is in progress
-        if (shouldPilfer && mLockscreenShadeTransitionController.getQSDragProgress() == 0f
-                && !mPrimaryBouncerInteractor.isInTransit()) {
+        // Execute the pilfer
+        if (shouldPilfer) {
             mInputManager.pilferPointers(
                     mOverlay.getOverlayView().getViewRootImpl().getInputToken());
         }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
index ba8e60a..52db4ab 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
@@ -40,9 +40,9 @@
 import androidx.annotation.Nullable;
 import androidx.asynclayoutinflater.view.AsyncLayoutInflater;
 
+import com.android.app.animation.Interpolators;
 import com.android.settingslib.Utils;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 
 import com.airbnb.lottie.LottieAnimationView;
 import com.airbnb.lottie.LottieProperty;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
index 935de02..9f5669f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
@@ -23,11 +23,11 @@
 import androidx.annotation.VisibleForTesting
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
+import com.android.app.animation.Interpolators
 import com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.systemui.R
 import com.android.systemui.animation.ActivityLaunchAnimator
-import com.android.systemui.animation.Interpolators
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt
index e2d36dc..9292bd7 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt
@@ -6,8 +6,8 @@
 import android.widget.TextView
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
+import com.android.app.animation.Interpolators
 import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
 import com.android.systemui.biometrics.AuthDialog
 import com.android.systemui.biometrics.AuthPanelController
 import com.android.systemui.biometrics.ui.CredentialPasswordView
diff --git a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
index 11ef749..7bf8f4d 100644
--- a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
@@ -30,9 +30,9 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import com.android.app.animation.Interpolators;
 import com.android.settingslib.Utils;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.shared.recents.utilities.Utilities;
 import com.android.systemui.surfaceeffects.ripple.RippleShader;
 import com.android.systemui.surfaceeffects.ripple.RippleShader.RippleShape;
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsAnimations.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsAnimations.kt
index 8d0edf8..b447d66 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsAnimations.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsAnimations.kt
@@ -32,7 +32,7 @@
 import androidx.lifecycle.LifecycleObserver
 import androidx.lifecycle.OnLifecycleEvent
 import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
 import com.android.systemui.controls.ui.ControlsUiController
 
 object ControlsAnimations {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
index 6a9aaf8..e6361f4 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
@@ -50,7 +50,7 @@
 import androidx.annotation.VisibleForTesting
 import com.android.internal.graphics.ColorUtils
 import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
 import com.android.systemui.controls.ControlsMetricsLogger
 import com.android.systemui.controls.controller.ControlsController
 import com.android.systemui.util.concurrency.DelayableExecutor
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
index fa36eee..1461135 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
@@ -38,7 +38,7 @@
 import android.view.accessibility.AccessibilityEvent
 import android.view.accessibility.AccessibilityNodeInfo
 import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
 import com.android.systemui.controls.ui.ControlViewHolder.Companion.MAX_LEVEL
 import com.android.systemui.controls.ui.ControlViewHolder.Companion.MIN_LEVEL
 import java.util.IllegalFormatException
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 89c45d7..17cf808 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.qs.QSFragmentStartableModule;
 import com.android.systemui.qs.footer.dagger.FooterActionsModule;
 import com.android.systemui.recents.Recents;
+import com.android.systemui.retail.dagger.RetailModeModule;
 import com.android.systemui.screenrecord.ScreenRecordModule;
 import com.android.systemui.screenshot.dagger.ScreenshotModule;
 import com.android.systemui.security.data.repository.SecurityRepositoryModule;
@@ -179,6 +180,7 @@
             PrivacyModule.class,
             QRCodeScannerModule.class,
             QSFragmentStartableModule.class,
+            RetailModeModule.class,
             ScreenshotModule.class,
             SensorModule.class,
             SecurityRepositoryModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
index df46e07..c5e7e0d 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
@@ -25,8 +25,8 @@
 import androidx.core.animation.doOnEnd
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
+import com.android.app.animation.Interpolators
 import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
 import com.android.systemui.complication.ComplicationHostViewController
 import com.android.systemui.complication.ComplicationLayoutParams
 import com.android.systemui.complication.ComplicationLayoutParams.POSITION_BOTTOM
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
index 15a32d2..c22019e 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
@@ -33,9 +33,9 @@
 
 import androidx.annotation.NonNull;
 
+import com.android.app.animation.Interpolators;
 import com.android.dream.lowlight.LowLightTransitionCoordinator;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.complication.ComplicationHostViewController;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dreams.dagger.DreamOverlayComponent;
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 87a85f7..873755f 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -702,6 +702,5 @@
 
     // TODO(b/278761837): Tracking Bug
     @JvmField
-    val USE_NEW_ACTIVITY_STARTER = unreleasedFlag(2801, name = "use_new_activity_starter",
-            teamfood = true)
+    val USE_NEW_ACTIVITY_STARTER = releasedFlag(2801, name = "use_new_activity_starter")
 }
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index f64ed60..2807107 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -97,6 +97,7 @@
 import androidx.lifecycle.LifecycleOwner;
 import androidx.lifecycle.LifecycleRegistry;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.colorextraction.ColorExtractor;
@@ -116,7 +117,6 @@
 import com.android.systemui.animation.DialogCuj;
 import com.android.systemui.animation.DialogLaunchAnimator;
 import com.android.systemui.animation.Expandable;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.dagger.qualifiers.Background;
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt
index 328beed..6bc763c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/view/KeyboardBacklightDialog.kt
@@ -17,6 +17,7 @@
 
 package com.android.systemui.keyboard.backlight.ui.view
 
+import android.annotation.AttrRes
 import android.annotation.ColorInt
 import android.app.Dialog
 import android.content.Context
@@ -31,6 +32,7 @@
 import android.widget.LinearLayout
 import android.widget.LinearLayout.LayoutParams
 import android.widget.LinearLayout.LayoutParams.WRAP_CONTENT
+import com.android.settingslib.Utils
 import com.android.systemui.R
 import com.android.systemui.util.children
 
@@ -38,7 +40,7 @@
     context: Context,
     initialCurrentLevel: Int,
     initialMaxLevel: Int,
-) : Dialog(context) {
+) : Dialog(context, R.style.Theme_SystemUI_Dialog) {
 
     private data class RootProperties(
         val cornerRadius: Float,
@@ -69,9 +71,14 @@
     private lateinit var rootProperties: RootProperties
     private lateinit var iconProperties: BacklightIconProperties
     private lateinit var stepProperties: StepViewProperties
-    @ColorInt var filledRectangleColor: Int = 0
-    @ColorInt var emptyRectangleColor: Int = 0
-    @ColorInt var backgroundColor: Int = 0
+    @ColorInt
+    var filledRectangleColor = getColorFromStyle(com.android.internal.R.attr.materialColorPrimary)
+    @ColorInt
+    var emptyRectangleColor =
+        getColorFromStyle(com.android.internal.R.attr.materialColorOutlineVariant)
+    @ColorInt
+    var backgroundColor = getColorFromStyle(com.android.internal.R.attr.materialColorSurfaceBright)
+    @ColorInt var iconColor = getColorFromStyle(com.android.internal.R.attr.materialColorOnPrimary)
 
     init {
         currentLevel = initialCurrentLevel
@@ -90,9 +97,6 @@
 
     private fun updateResources() {
         context.resources.apply {
-            filledRectangleColor = getColor(R.color.backlight_indicator_step_filled, context.theme)
-            emptyRectangleColor = getColor(R.color.backlight_indicator_step_empty, context.theme)
-            backgroundColor = getColor(R.color.backlight_indicator_background, context.theme)
             rootProperties =
                 RootProperties(
                     cornerRadius =
@@ -126,6 +130,11 @@
         }
     }
 
+    @ColorInt
+    fun getColorFromStyle(@AttrRes colorId: Int): Int {
+        return Utils.getColorAttrDefaultColor(context, colorId)
+    }
+
     fun updateState(current: Int, max: Int, forceRefresh: Boolean = false) {
         if (maxLevel != max || forceRefresh) {
             maxLevel = max
@@ -215,6 +224,7 @@
     private fun createBacklightIconView(): ImageView {
         return ImageView(context).apply {
             setImageResource(R.drawable.ic_keyboard_backlight)
+            setColorFilter(iconColor)
             layoutParams =
                 FrameLayout.LayoutParams(iconProperties.width, iconProperties.height).apply {
                     gravity = Gravity.CENTER
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index 2925d8d..9844ca0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -36,7 +36,7 @@
 import com.android.internal.R
 import com.android.keyguard.KeyguardClockSwitchController
 import com.android.keyguard.KeyguardViewController
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 1a126d7..2854de0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -98,6 +98,7 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.jank.InteractionJankMonitor.Configuration;
 import com.android.internal.policy.IKeyguardDismissCallback;
@@ -121,7 +122,6 @@
 import com.android.systemui.EventLogTags;
 import com.android.systemui.R;
 import com.android.systemui.animation.ActivityLaunchAnimator;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.animation.LaunchAnimator;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.classifier.FalsingCollector;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardFaceAuthModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardFaceAuthModule.kt
index ef8b401..ee0eb2d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardFaceAuthModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardFaceAuthModule.kt
@@ -46,8 +46,6 @@
         impl: SystemUIKeyguardFaceAuthInteractor
     ): KeyguardFaceAuthInteractor
 
-    @Binds fun trustRepository(impl: TrustRepositoryImpl): TrustRepository
-
     companion object {
         @Provides
         @SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
index f27f899..e7b9af6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
@@ -45,4 +45,6 @@
 
     @Binds
     fun keyguardBouncerRepository(impl: KeyguardBouncerRepositoryImpl): KeyguardBouncerRepository
+
+    @Binds fun trustRepository(impl: TrustRepositoryImpl): TrustRepository
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/TrustRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/TrustRepository.kt
index d90f328..74c5520 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/TrustRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/TrustRepository.kt
@@ -28,7 +28,9 @@
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.map
@@ -40,6 +42,9 @@
 interface TrustRepository {
     /** Flow representing whether the current user is trusted. */
     val isCurrentUserTrusted: Flow<Boolean>
+
+    /** Flow representing whether active unlock is available for the current user. */
+    val isCurrentUserActiveUnlockAvailable: StateFlow<Boolean>
 }
 
 @SysUISingleton
@@ -89,11 +94,13 @@
             }
             .shareIn(applicationScope, started = SharingStarted.Eagerly, replay = 1)
 
-    override val isCurrentUserTrusted: Flow<Boolean>
-        get() =
-            combine(trust, userRepository.selectedUserInfo, ::Pair)
-                .map { latestTrustModelForUser[it.second.id]?.isTrusted ?: false }
-                .distinctUntilChanged()
-                .onEach { logger.isCurrentUserTrusted(it) }
-                .onStart { emit(false) }
+    override val isCurrentUserTrusted: Flow<Boolean> =
+        combine(trust, userRepository.selectedUserInfo, ::Pair)
+            .map { latestTrustModelForUser[it.second.id]?.isTrusted ?: false }
+            .distinctUntilChanged()
+            .onEach { logger.isCurrentUserTrusted(it) }
+            .onStart { emit(false) }
+
+    // TODO: Implement based on TrustManager callback b/267322286
+    override val isCurrentUserActiveUnlockAvailable: StateFlow<Boolean> = MutableStateFlow(true)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
index e6568f2..cde67f9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
@@ -17,7 +17,7 @@
 package com.android.systemui.keyguard.domain.interactor
 
 import android.animation.ValueAnimator
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
index c2d139c..7e9cbc1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
@@ -17,7 +17,7 @@
 package com.android.systemui.keyguard.domain.interactor
 
 import android.animation.ValueAnimator
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
index 86f65dde..aca4019 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
@@ -17,7 +17,7 @@
 package com.android.systemui.keyguard.domain.interactor
 
 import android.animation.ValueAnimator
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
index 3beac0b..fc7bfb4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
@@ -17,7 +17,7 @@
 package com.android.systemui.keyguard.domain.interactor
 
 import android.animation.ValueAnimator
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
index b5bcd45..39c630b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
@@ -17,7 +17,7 @@
 package com.android.systemui.keyguard.domain.interactor
 
 import android.animation.ValueAnimator
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index 87f3164..0505d37 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -17,7 +17,7 @@
 package com.android.systemui.keyguard.domain.interactor
 
 import android.animation.ValueAnimator
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
index c0d5abc..47846d1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
@@ -17,7 +17,7 @@
 package com.android.systemui.keyguard.domain.interactor
 
 import android.animation.ValueAnimator
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
index a681c43..bc55bd4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
@@ -17,10 +17,10 @@
 package com.android.systemui.keyguard.domain.interactor
 
 import android.animation.ValueAnimator
+import com.android.app.animation.Interpolators
 import com.android.keyguard.KeyguardSecurityModel
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode.Password
 import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.systemui.animation.Interpolators
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt
index 970d004..110bcd7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt
@@ -32,14 +32,16 @@
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.DismissCallbackRegistry
 import com.android.systemui.keyguard.data.BouncerView
 import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
+import com.android.systemui.keyguard.data.repository.TrustRepository
 import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants
 import com.android.systemui.keyguard.shared.model.BouncerShowMessageModel
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.shared.system.SysUiStatsLog
-import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.combine
@@ -56,28 +58,21 @@
 class PrimaryBouncerInteractor
 @Inject
 constructor(
-    private val repository: KeyguardBouncerRepository,
-    private val primaryBouncerView: BouncerView,
-    @Main private val mainHandler: Handler,
-    private val keyguardStateController: KeyguardStateController,
-    private val keyguardSecurityModel: KeyguardSecurityModel,
-    private val primaryBouncerCallbackInteractor: PrimaryBouncerCallbackInteractor,
-    private val falsingCollector: FalsingCollector,
-    private val dismissCallbackRegistry: DismissCallbackRegistry,
-    private val context: Context,
-    private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
-    keyguardBypassController: KeyguardBypassController,
+        private val repository: KeyguardBouncerRepository,
+        private val primaryBouncerView: BouncerView,
+        @Main private val mainHandler: Handler,
+        private val keyguardStateController: KeyguardStateController,
+        private val keyguardSecurityModel: KeyguardSecurityModel,
+        private val primaryBouncerCallbackInteractor: PrimaryBouncerCallbackInteractor,
+        private val falsingCollector: FalsingCollector,
+        private val dismissCallbackRegistry: DismissCallbackRegistry,
+        private val context: Context,
+        private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+        private val trustRepository: TrustRepository,
+        private val featureFlags: FeatureFlags,
 ) {
-    /** Whether we want to wait for face auth. */
-    private val primaryBouncerFaceDelay =
-        keyguardStateController.isFaceAuthEnabled &&
-            !keyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
-                KeyguardUpdateMonitor.getCurrentUser()
-            ) &&
-            !needsFullscreenBouncer() &&
-            keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(BiometricSourceType.FACE) &&
-            !keyguardBypassController.bypassEnabled
-
+    private val passiveAuthBouncerDelay = context.resources.getInteger(
+            R.integer.primary_bouncer_passive_auth_delay).toLong()
     /** Runnable to show the primary bouncer. */
     val showRunnable = Runnable {
         repository.setPrimaryShow(true)
@@ -160,8 +155,9 @@
         }
 
         repository.setPrimaryShowingSoon(true)
-        if (primaryBouncerFaceDelay) {
-            mainHandler.postDelayed(showRunnable, 1200L)
+        if (usePrimaryBouncerPassiveAuthDelay()) {
+            Log.d(TAG, "delay bouncer, passive auth may succeed")
+            mainHandler.postDelayed(showRunnable, passiveAuthBouncerDelay)
         } else {
             DejankUtils.postAfterTraversal(showRunnable)
         }
@@ -377,6 +373,17 @@
         return repository.primaryBouncerShow.value
     }
 
+    /** Whether we want to wait to show the bouncer in case passive auth succeeds. */
+    private fun usePrimaryBouncerPassiveAuthDelay(): Boolean {
+        val canRunFaceAuth = keyguardStateController.isFaceAuthEnabled &&
+                keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(BiometricSourceType.FACE)
+        val canRunActiveUnlock = trustRepository.isCurrentUserActiveUnlockAvailable.value &&
+                keyguardUpdateMonitor.canTriggerActiveUnlockBasedOnDeviceState()
+        return featureFlags.isEnabled(Flags.DELAY_BOUNCER) &&
+                !needsFullscreenBouncer() &&
+                (canRunFaceAuth || canRunActiveUnlock)
+    }
+
     companion object {
         private const val TAG = "PrimaryBouncerInteractor"
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt
index 38b9d50..9d7477c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt
@@ -16,7 +16,7 @@
 package com.android.systemui.keyguard.ui
 
 import android.view.animation.Interpolator
-import com.android.systemui.animation.Interpolators.LINEAR
+import com.android.app.animation.Interpolators.LINEAR
 import com.android.systemui.keyguard.shared.model.TransitionState.CANCELED
 import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED
 import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
index d96609c..c8d37a1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
@@ -32,11 +32,11 @@
 import androidx.core.view.updateLayoutParams
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
+import com.android.app.animation.Interpolators
 import com.android.settingslib.Utils
 import com.android.systemui.R
 import com.android.systemui.animation.ActivityLaunchAnimator
 import com.android.systemui.animation.Expandable
-import com.android.systemui.animation.Interpolators
 import com.android.systemui.animation.view.LaunchableLinearLayout
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.common.ui.binder.IconViewBinder
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 951f0bd..ad11360 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
@@ -17,6 +17,7 @@
 
 package com.android.systemui.keyguard.ui.preview
 
+import android.annotation.ColorInt
 import android.content.BroadcastReceiver
 import android.content.Context
 import android.content.Intent
@@ -85,6 +86,7 @@
 
     private var clockView: View? = null
     private var smartSpaceView: View? = null
+    private var colorOverride: Int? = null
 
     private val disposables = mutableSetOf<DisposableHandle>()
     private var isDestroyed = false
@@ -171,6 +173,14 @@
         }
     }
 
+    /** Sets the clock's color to the overridden seed color. */
+    fun onColorOverridden(@ColorInt color: Int?) {
+        runBlocking(mainDispatcher) {
+            colorOverride = color
+            clockController.clock?.run { events.onSeedColorChanged(color) }
+        }
+    }
+
     /**
      * This sets up and shows a non-interactive smart space
      *
@@ -288,8 +298,10 @@
         val receiver =
             object : BroadcastReceiver() {
                 override fun onReceive(context: Context?, intent: Intent?) {
-                    clockController.clock?.smallClock?.events?.onTimeTick()
-                    clockController.clock?.largeClock?.events?.onTimeTick()
+                    clockController.clock?.run {
+                        smallClock.events.onTimeTick()
+                        largeClock.events.onTimeTick()
+                    }
                 }
             }
         broadcastDispatcher.registerReceiver(
@@ -305,18 +317,18 @@
     }
 
     private fun onClockChanged(parentView: ViewGroup) {
-        clockController.clock = clockRegistry.createCurrentClock()
+        val clock = clockRegistry.createCurrentClock()
+        clockController.clock = clock
 
+        colorOverride?.let { clock.events.onSeedColorChanged(it) }
         if (!shouldHideClock) {
-            val largeClock = clockController.clock?.largeClock
-
-            largeClock
-                ?.events
-                ?.onTargetRegionChanged(KeyguardClockSwitch.getLargeClockRegion(parentView))
+            clock.largeClock.events.onTargetRegionChanged(
+                KeyguardClockSwitch.getLargeClockRegion(parentView)
+            )
 
             clockView?.let { parentView.removeView(it) }
             clockView =
-                largeClock?.view?.apply {
+                clock.largeClock.view.apply {
                     if (shouldHighlightSelectedAffordance) {
                         alpha = DIM_ALPHA
                     }
@@ -329,7 +341,7 @@
 
         // Hide smart space if the clock has weather display; otherwise show it
         val hasCustomWeatherDataDisplay =
-            clockController.clock?.largeClock?.config?.hasCustomWeatherDataDisplay == true
+            clock.largeClock.config.hasCustomWeatherDataDisplay == true
         hideSmartspace(hasCustomWeatherDataDisplay)
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt
index 3869b23..79712f9c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardRemotePreviewManager.kt
@@ -115,16 +115,21 @@
 
             when (message.what) {
                 KeyguardPreviewConstants.MESSAGE_ID_SLOT_SELECTED -> {
-                    message.data
-                        .getString(
-                            KeyguardPreviewConstants.KEY_SLOT_ID,
-                        )
-                        ?.let { slotId -> renderer.onSlotSelected(slotId = slotId) }
+                    message.data.getString(KeyguardPreviewConstants.KEY_SLOT_ID)?.let { slotId ->
+                        renderer.onSlotSelected(slotId = slotId)
+                    }
                 }
                 KeyguardPreviewConstants.MESSAGE_ID_HIDE_SMART_SPACE -> {
-                    message.data
-                        .getBoolean(KeyguardPreviewConstants.KEY_HIDE_SMART_SPACE)
-                        .let { hide -> renderer.hideSmartspace(hide) }
+                    renderer.hideSmartspace(
+                        message.data.getBoolean(KeyguardPreviewConstants.KEY_HIDE_SMART_SPACE)
+                    )
+                }
+                KeyguardPreviewConstants.MESSAGE_ID_COLOR_OVERRIDE -> {
+                    renderer.onColorOverridden(
+                        message.data
+                            .getString(KeyguardPreviewConstants.KEY_COLOR_OVERRIDE)
+                            ?.toIntOrNull()
+                    )
                 }
                 else -> requestDestruction(this)
             }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
index 8d6545a4..2c9a9b3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
@@ -16,8 +16,8 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
-import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
-import com.android.systemui.animation.Interpolators.EMPHASIZED_DECELERATE
+import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyguard.domain.interactor.FromDreamingTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModel.kt
index f16827d..c135786 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModel.kt
@@ -16,7 +16,7 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
-import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyguard.domain.interactor.FromGoneTransitionInteractor.Companion.TO_DREAMING_DURATION
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt
index bc9dc4f..c6187dd 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt
@@ -16,7 +16,7 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
-import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor.Companion.TO_DREAMING_DURATION
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModel.kt
index a60665a..d3ea89c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModel.kt
@@ -16,7 +16,7 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
-import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor.Companion.TO_OCCLUDED_DURATION
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt
index ddce516..6845c55 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt
@@ -16,7 +16,7 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
-import com.android.systemui.animation.Interpolators.EMPHASIZED_DECELERATE
+import com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyguard.domain.interactor.FromOccludedTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
index df93d23..68810f9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt
@@ -16,7 +16,7 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
-import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor.Companion.TO_GONE_DURATION
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
index aec7b5f..c41f82b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
@@ -111,7 +111,7 @@
         if (featureFlags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING_ENTERPRISE_POLICIES)) {
             component.emptyStateProvider
         } else {
-            super.createBlockerEmptyStateProvider()
+            object : EmptyStateProvider {}
         }
 
     override fun createListController(userHandle: UserHandle): ResolverListController =
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
index 28adfbb..c9c2ea2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
@@ -79,6 +79,9 @@
     // Indicates if user must review already-granted consent that the MediaProjection app is
     // attempting to re-use.
     private boolean mReviewGrantedConsentRequired = false;
+    // Indicates if the user has consented to record, but is continuing in another activity to
+    // select a particular task to capture.
+    private boolean mUserSelectingTask = false;
 
     @Inject
     public MediaProjectionPermissionActivity(FeatureFlags featureFlags,
@@ -296,6 +299,7 @@
                 // Start activity from the current foreground user to avoid creating a separate
                 // SystemUI process without access to recent tasks because it won't have
                 // WM Shell running inside.
+                mUserSelectingTask = true;
                 startActivityAsUser(intent, UserHandle.of(ActivityManager.getCurrentUser()));
             }
         } catch (RemoteException e) {
@@ -316,7 +320,10 @@
     @Override
     public void finish() {
         // Default to cancelling recording when user needs to review consent.
-        finish(RECORD_CANCEL, /* projection= */ null);
+        // Don't send cancel if the user has moved on to the next activity.
+        if (!mUserSelectingTask) {
+            finish(RECORD_CANCEL, /* projection= */ null);
+        }
     }
 
     private void finish(@ReviewGrantedConsentResult int consentResult,
@@ -328,7 +335,7 @@
 
     private void onDialogDismissedOrCancelled(DialogInterface dialogInterface) {
         if (!isFinishing()) {
-            finish(RECORD_CANCEL, /* projection= */ null);
+            finish();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarObserver.kt b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarObserver.kt
index 37d956b..e38abc2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarObserver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarObserver.kt
@@ -21,9 +21,9 @@
 import android.text.format.DateUtils
 import androidx.annotation.UiThread
 import androidx.lifecycle.Observer
+import com.android.app.animation.Interpolators
 import com.android.internal.annotations.VisibleForTesting
 import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
 import com.android.systemui.media.controls.ui.SquigglyProgress
 
 /**
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/IlluminationDrawable.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/IlluminationDrawable.kt
index 3669493..b46ebb2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/IlluminationDrawable.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/IlluminationDrawable.kt
@@ -34,10 +34,10 @@
 import android.util.MathUtils
 import android.view.View
 import androidx.annotation.Keep
+import com.android.app.animation.Interpolators
 import com.android.internal.graphics.ColorUtils
 import com.android.internal.graphics.ColorUtils.blendARGB
 import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
 import org.xmlpull.v1.XmlPullParser
 
 private const val BACKGROUND_ANIM_DURATION = 370L
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/LightSourceDrawable.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/LightSourceDrawable.kt
index dd5c2bf..937a618 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/LightSourceDrawable.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/LightSourceDrawable.kt
@@ -35,9 +35,9 @@
 import android.util.AttributeSet
 import android.util.MathUtils.lerp
 import androidx.annotation.Keep
+import com.android.app.animation.Interpolators
 import com.android.internal.graphics.ColorUtils
 import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
 import org.xmlpull.v1.XmlPullParser
 
 private const val RIPPLE_ANIM_DURATION = 800L
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
index 40027a1..f9d3094 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
@@ -72,6 +72,7 @@
 import androidx.annotation.UiThread;
 import androidx.constraintlayout.widget.ConstraintSet;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.graphics.ColorUtils;
 import com.android.internal.jank.InteractionJankMonitor;
@@ -82,7 +83,6 @@
 import com.android.systemui.R;
 import com.android.systemui.animation.ActivityLaunchAnimator;
 import com.android.systemui.animation.GhostedViewLaunchAnimatorController;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.bluetooth.BroadcastDialogController;
 import com.android.systemui.broadcast.BroadcastSender;
 import com.android.systemui.dagger.qualifiers.Background;
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
index 49e1665..fe8ebaf 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
@@ -33,9 +33,9 @@
 import android.view.ViewGroup
 import android.view.ViewGroupOverlay
 import androidx.annotation.VisibleForTesting
+import com.android.app.animation.Interpolators
 import com.android.keyguard.KeyguardViewController
 import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.dreams.DreamOverlayStateController
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/SquigglyProgress.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/SquigglyProgress.kt
index e9b2cf2..583c626 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/SquigglyProgress.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/SquigglyProgress.kt
@@ -31,8 +31,8 @@
 import android.util.MathUtils.lerpInv
 import android.util.MathUtils.lerpInvSat
 import androidx.annotation.VisibleForTesting
+import com.android.app.animation.Interpolators
 import com.android.internal.graphics.ColorUtils
-import com.android.systemui.animation.Interpolators
 import kotlin.math.abs
 import kotlin.math.cos
 
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
index 78082c3..77ff036 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
@@ -36,7 +36,7 @@
 import android.view.View.ACCESSIBILITY_LIVE_REGION_NONE
 import com.android.internal.widget.CachingIconView
 import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
 import com.android.systemui.common.shared.model.ContentDescription
 import com.android.systemui.common.ui.binder.TintedIconViewBinder
 import com.android.systemui.dagger.SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorController.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorController.kt
index 219629b..1d8fe72 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorController.kt
@@ -19,7 +19,6 @@
 import android.content.ComponentName
 import android.os.UserHandle
 import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.flags.Flags
 import com.android.systemui.mediaprojection.appselector.data.RecentTask
 import com.android.systemui.mediaprojection.appselector.data.RecentTaskListProvider
 import javax.inject.Inject
@@ -59,13 +58,7 @@
      * Removes all recent tasks that are different from the profile of the host app to avoid any
      * cross-profile sharing
      */
-    private fun List<RecentTask>.filterDevicePolicyRestrictedTasks(): List<RecentTask> =
-        if (flags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING_ENTERPRISE_POLICIES)) {
-            // TODO(b/263950746): filter tasks based on the enterprise policies
-            this
-        } else {
-            filter { UserHandle.of(it.userId) == hostUserHandle }
-        }
+    private fun List<RecentTask>.filterDevicePolicyRestrictedTasks(): List<RecentTask> = this
 
     private fun List<RecentTask>.filterAppSelector(): List<RecentTask> = filter {
         // Only take tasks that is not the app selector
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 94f01b8..146b5f5 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -58,11 +58,11 @@
 
 import androidx.annotation.Nullable;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settingslib.Utils;
 import com.android.systemui.Gefingerpoken;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.navigationbar.buttons.ButtonDispatcher;
 import com.android.systemui.navigationbar.buttons.ContextualButton;
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonDispatcher.java
index 0218016..10084bd 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonDispatcher.java
@@ -16,7 +16,7 @@
 
 package com.android.systemui.navigationbar.buttons;
 
-import static com.android.systemui.animation.Interpolators.LINEAR;
+import static com.android.app.animation.Interpolators.LINEAR;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -24,9 +24,6 @@
 import android.view.View;
 import android.view.View.AccessibilityDelegate;
 
-import com.android.systemui.Dependency;
-import com.android.systemui.assist.AssistManager;
-
 import java.util.ArrayList;
 
 /**
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
index 590efbb..ff22398 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
@@ -48,10 +48,10 @@
 import androidx.dynamicanimation.animation.SpringAnimation;
 import androidx.dynamicanimation.animation.SpringForce;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.util.LatencyTracker;
 import com.android.settingslib.Utils;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.plugins.NavigationEdgeBackPlugin;
 import com.android.systemui.settings.DisplayTracker;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index a7aac5a..463c79c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -26,7 +26,7 @@
 
 import androidx.annotation.Nullable;
 
-import com.android.systemui.animation.Interpolators;
+import com.android.app.animation.Interpolators;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.plugins.qs.QSTile;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
index 0d29a1a..85f557b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
@@ -27,6 +27,7 @@
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.qs.dagger.QSScope;
+import com.android.systemui.retail.domain.interactor.RetailModeInteractor;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.util.ViewController;
 
@@ -45,18 +46,22 @@
     private final View mEditButton;
     private final FalsingManager mFalsingManager;
     private final ActivityStarter mActivityStarter;
+    private final RetailModeInteractor mRetailModeInteractor;
 
     @Inject
     QSFooterViewController(QSFooterView view,
             UserTracker userTracker,
             FalsingManager falsingManager,
             ActivityStarter activityStarter,
-            QSPanelController qsPanelController) {
+            QSPanelController qsPanelController,
+            RetailModeInteractor retailModeInteractor
+    ) {
         super(view);
         mUserTracker = userTracker;
         mQsPanelController = qsPanelController;
         mFalsingManager = falsingManager;
         mActivityStarter = activityStarter;
+        mRetailModeInteractor = retailModeInteractor;
 
         mBuildText = mView.findViewById(R.id.build);
         mPageIndicator = mView.findViewById(R.id.footer_page_indicator);
@@ -96,6 +101,8 @@
     @Override
     public void setVisibility(int visibility) {
         mView.setVisibility(visibility);
+        mEditButton
+                .setVisibility(mRetailModeInteractor.isInRetailMode() ? View.GONE : View.VISIBLE);
         mEditButton.setClickable(visibility == View.VISIBLE);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index fd3f701..b8c2fad 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -44,10 +44,10 @@
 import androidx.lifecycle.LifecycleOwner;
 import androidx.lifecycle.LifecycleRegistry;
 
+import com.android.app.animation.Interpolators;
 import com.android.keyguard.BouncerPanelExpansionCalculator;
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.animation.ShadeInterpolation;
 import com.android.systemui.compose.ComposeFacade;
 import com.android.systemui.dump.DumpManager;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/TileSpecRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/TileSpecRepository.kt
index 595b29a9..3b2362f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/TileSpecRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/data/repository/TileSpecRepository.kt
@@ -20,6 +20,7 @@
 import android.content.res.Resources
 import android.database.ContentObserver
 import android.provider.Settings
+import com.android.systemui.R
 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
@@ -27,12 +28,16 @@
 import com.android.systemui.qs.QSHost
 import com.android.systemui.qs.pipeline.shared.TileSpec
 import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger
+import com.android.systemui.retail.data.repository.RetailModeRepository
 import com.android.systemui.util.settings.SecureSettings
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onEach
@@ -84,6 +89,9 @@
  * [Settings.Secure.QS_TILES].
  *
  * All operations against [Settings] will be performed in a background thread.
+ *
+ * If the device is in retail mode, the tiles are fixed to the value of
+ * [R.string.quick_settings_tiles_retail_mode].
  */
 @SysUISingleton
 class TileSpecSettingsRepository
@@ -92,9 +100,31 @@
     private val secureSettings: SecureSettings,
     @Main private val resources: Resources,
     private val logger: QSPipelineLogger,
+    private val retailModeRepository: RetailModeRepository,
     @Background private val backgroundDispatcher: CoroutineDispatcher,
 ) : TileSpecRepository {
+
+    private val retailModeTiles by lazy {
+        resources
+            .getString(R.string.quick_settings_tiles_retail_mode)
+            .split(DELIMITER)
+            .map(TileSpec::create)
+            .filter { it !is TileSpec.Invalid }
+    }
+
+    @OptIn(ExperimentalCoroutinesApi::class)
     override fun tilesSpecs(userId: Int): Flow<List<TileSpec>> {
+        return retailModeRepository.retailMode.flatMapLatest { inRetailMode ->
+            if (inRetailMode) {
+                logger.logUsingRetailTiles()
+                flowOf(retailModeTiles)
+            } else {
+                settingsTiles(userId)
+            }
+        }
+    }
+
+    private fun settingsTiles(userId: Int): Flow<List<TileSpec>> {
         return conflatedCallbackFlow {
                 val observer =
                     object : ContentObserver(null) {
@@ -157,6 +187,10 @@
     }
 
     private suspend fun storeTiles(@UserIdInt forUser: Int, tiles: List<TileSpec>) {
+        if (retailModeRepository.inRetailMode) {
+            // No storing tiles when in retail mode
+            return
+        }
         val toStore =
             tiles
                 .filter { it !is TileSpec.Invalid }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt
index b564334..ff7d206 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/logging/QSPipelineLogger.kt
@@ -120,6 +120,10 @@
         )
     }
 
+    fun logUsingRetailTiles() {
+        tileListLogBuffer.log(TILE_LIST_TAG, LogLevel.DEBUG, {}, { "Using retail tiles" })
+    }
+
     /** Reasons for destroying an existing tile. */
     enum class TileDestroyedReason(val readable: String) {
         TILE_REMOVED("Tile removed from  current set"),
diff --git a/packages/SystemUI/src/com/android/systemui/retail/dagger/RetailModeModule.kt b/packages/SystemUI/src/com/android/systemui/retail/dagger/RetailModeModule.kt
new file mode 100644
index 0000000..e863949
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/retail/dagger/RetailModeModule.kt
@@ -0,0 +1,34 @@
+/*
+ * 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.retail.dagger
+
+import com.android.systemui.retail.data.repository.RetailModeRepository
+import com.android.systemui.retail.data.repository.RetailModeSettingsRepository
+import com.android.systemui.retail.domain.interactor.RetailModeInteractor
+import com.android.systemui.retail.domain.interactor.RetailModeInteractorImpl
+import dagger.Binds
+import dagger.Module
+
+@Module
+abstract class RetailModeModule {
+
+    @Binds
+    abstract fun bindsRetailModeRepository(impl: RetailModeSettingsRepository): RetailModeRepository
+
+    @Binds
+    abstract fun bindsRetailModeInteractor(impl: RetailModeInteractorImpl): RetailModeInteractor
+}
diff --git a/packages/SystemUI/src/com/android/systemui/retail/data/repository/RetailModeRepository.kt b/packages/SystemUI/src/com/android/systemui/retail/data/repository/RetailModeRepository.kt
new file mode 100644
index 0000000..3c0aa38
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/retail/data/repository/RetailModeRepository.kt
@@ -0,0 +1,81 @@
+/*
+ * 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.retail.data.repository
+
+import android.database.ContentObserver
+import android.provider.Settings
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.util.settings.GlobalSettings
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.stateIn
+
+/** Repository to track if the device is in Retail mode */
+interface RetailModeRepository {
+    /** Flow of whether the device is currently in retail mode. */
+    val retailMode: StateFlow<Boolean>
+
+    /** Last value of whether the device is in retail mode. */
+    val inRetailMode: Boolean
+        get() = retailMode.value
+}
+
+/**
+ * Tracks [Settings.Global.DEVICE_DEMO_MODE].
+ *
+ * @see UserManager.isDeviceInDemoMode
+ */
+@SysUISingleton
+class RetailModeSettingsRepository
+@Inject
+constructor(
+    globalSettings: GlobalSettings,
+    @Background backgroundDispatcher: CoroutineDispatcher,
+    @Application scope: CoroutineScope,
+) : RetailModeRepository {
+    override val retailMode =
+        conflatedCallbackFlow {
+                val observer =
+                    object : ContentObserver(null) {
+                        override fun onChange(selfChange: Boolean) {
+                            trySend(Unit)
+                        }
+                    }
+
+                globalSettings.registerContentObserver(RETAIL_MODE_SETTING, observer)
+
+                awaitClose { globalSettings.unregisterContentObserver(observer) }
+            }
+            .onStart { emit(Unit) }
+            .map { globalSettings.getInt(RETAIL_MODE_SETTING, 0) != 0 }
+            .flowOn(backgroundDispatcher)
+            .stateIn(scope, SharingStarted.Eagerly, false)
+
+    companion object {
+        private const val RETAIL_MODE_SETTING = Settings.Global.DEVICE_DEMO_MODE
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt b/packages/SystemUI/src/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt
new file mode 100644
index 0000000..eea452c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt
@@ -0,0 +1,37 @@
+/*
+ * 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.retail.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.retail.data.repository.RetailModeRepository
+import javax.inject.Inject
+
+/** Interactor to determine if the device is currently in retail mode */
+interface RetailModeInteractor {
+    /** Whether the device is currently in retail mode */
+    val isInRetailMode: Boolean
+}
+
+@SysUISingleton
+class RetailModeInteractorImpl
+@Inject
+constructor(
+    private val repository: RetailModeRepository,
+) : RetailModeInteractor {
+    override val isInRetailMode: Boolean
+        get() = repository.inRetailMode
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 137a99ef..926ede9 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -22,10 +22,10 @@
 import static android.view.View.INVISIBLE;
 import static android.view.View.VISIBLE;
 
+import static com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE;
+import static com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE;
 import static com.android.keyguard.KeyguardClockSwitch.LARGE;
 import static com.android.keyguard.KeyguardClockSwitch.SMALL;
-import static com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE;
-import static com.android.systemui.animation.Interpolators.EMPHASIZED_DECELERATE;
 import static com.android.systemui.classifier.Classifier.BOUNCER_UNLOCK;
 import static com.android.systemui.classifier.Classifier.GENERIC;
 import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
@@ -88,6 +88,7 @@
 import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.MetricsLogger;
@@ -111,7 +112,6 @@
 import com.android.systemui.Gefingerpoken;
 import com.android.systemui.R;
 import com.android.systemui.animation.ActivityLaunchAnimator;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.animation.LaunchAnimator;
 import com.android.systemui.biometrics.AuthController;
 import com.android.systemui.classifier.Classifier;
@@ -1513,6 +1513,8 @@
                 mKeyguardStatusViewController.getClockBottom(mStatusBarHeaderHeightKeyguard),
                 mKeyguardStatusViewController.isClockTopAligned());
         mClockPositionAlgorithm.run(mClockPositionResult);
+        mKeyguardStatusViewController.setLockscreenClockY(
+                mClockPositionAlgorithm.getExpandedPreferredClockY());
         mKeyguardBottomAreaInteractor.setClockPosition(
                 mClockPositionResult.clockX, mClockPositionResult.clockY);
         boolean animate = mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending();
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
index fb7c5c2..31b361f 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
@@ -18,7 +18,6 @@
 
 import android.view.View
 import android.view.ViewGroup
-import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
 import android.view.WindowInsets
 import androidx.annotation.VisibleForTesting
 import androidx.constraintlayout.widget.ConstraintSet
@@ -62,6 +61,7 @@
     private var isQSCustomizing = false
     private var isQSCustomizerAnimating = false
 
+    private var shadeHeaderHeight = 0
     private var largeScreenShadeHeaderHeight = 0
     private var largeScreenShadeHeaderActive = false
     private var notificationsBottomMargin = 0
@@ -146,6 +146,8 @@
                 R.dimen.notification_panel_margin_bottom)
         largeScreenShadeHeaderHeight =
                 resources.getDimensionPixelSize(R.dimen.large_screen_shade_header_height)
+        shadeHeaderHeight =
+                resources.getDimensionPixelSize(R.dimen.qs_header_height)
         panelMarginHorizontal = resources.getDimensionPixelSize(
                 R.dimen.notification_panel_margin_horizontal)
         topMargin = if (largeScreenShadeHeaderActive) {
@@ -245,7 +247,7 @@
         if (largeScreenShadeHeaderActive) {
             constraintSet.constrainHeight(R.id.split_shade_status_bar, largeScreenShadeHeaderHeight)
         } else {
-            constraintSet.constrainHeight(R.id.split_shade_status_bar, WRAP_CONTENT)
+            constraintSet.constrainHeight(R.id.split_shade_status_bar, shadeHeaderHeight)
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
index a1fa8fb..abdd1a9 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java
@@ -50,6 +50,7 @@
 import android.view.accessibility.AccessibilityManager;
 import android.widget.FrameLayout;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.MetricsLogger;
@@ -59,7 +60,6 @@
 import com.android.keyguard.FaceAuthApiRequestReason;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.classifier.Classifier;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.flags.FeatureFlags;
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
index 86ae4ec..f080d3d 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
@@ -34,10 +34,10 @@
 import android.widget.TextView
 import androidx.annotation.VisibleForTesting
 import androidx.constraintlayout.motion.widget.MotionLayout
+import com.android.app.animation.Interpolators
 import com.android.settingslib.Utils
 import com.android.systemui.Dumpable
 import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
 import com.android.systemui.animation.ShadeInterpolation
 import com.android.systemui.battery.BatteryMeterView
 import com.android.systemui.battery.BatteryMeterViewController
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
index 63179da..c1ebf12 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
@@ -18,8 +18,8 @@
 
 import android.view.View;
 
+import com.android.app.animation.Interpolators;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
 
 /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
index 54b341f..1a32d70 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
@@ -38,8 +38,8 @@
 import android.view.animation.Interpolator;
 import android.widget.ImageView;
 
+import com.android.app.animation.Interpolators;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.wm.shell.animation.FlingAnimationUtils;
 
 /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
index 9421524..823bb35 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
@@ -16,7 +16,7 @@
 import android.util.MathUtils.lerp
 import android.view.View
 import android.view.animation.PathInterpolator
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
 import com.android.systemui.statusbar.LightRevealEffect.Companion.getPercentPastThreshold
 import com.android.systemui.util.getColorWithAlpha
 import com.android.systemui.util.leak.RotationUtils
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index 7f016f3..b61f243 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -18,7 +18,7 @@
 import com.android.systemui.ExpandHelper
 import com.android.systemui.Gefingerpoken
 import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
 import com.android.systemui.biometrics.UdfpsKeyguardViewController
 import com.android.systemui.classifier.Classifier
 import com.android.systemui.classifier.FalsingCollector
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 72ae16e..fb88a96 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -44,9 +44,9 @@
 import android.view.View;
 import android.widget.ImageView;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.Dumpable;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dump.DumpManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index a3bd247..0e20df6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -33,7 +33,7 @@
 import androidx.dynamicanimation.animation.SpringAnimation
 import androidx.dynamicanimation.animation.SpringForce
 import com.android.systemui.Dumpable
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
 import com.android.systemui.animation.ShadeInterpolation
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dump.DumpManager
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 49c7950..9d7f3be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -35,10 +35,10 @@
 
 import androidx.annotation.NonNull;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.policy.SystemBarUtils;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.animation.ShadeInterpolation;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
index 821a172..fc6eaa8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
@@ -31,7 +31,7 @@
 import com.android.systemui.Dumpable
 import com.android.systemui.Gefingerpoken
 import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
 import com.android.systemui.classifier.Classifier.NOTIFICATION_DRAG_DOWN
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.dagger.SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScroller.kt b/packages/SystemUI/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScroller.kt
index 575f354..f1e51e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScroller.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScroller.kt
@@ -4,7 +4,7 @@
 import android.content.res.Configuration
 import android.util.MathUtils
 import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
 import com.android.systemui.statusbar.policy.ConfigurationController
 import dagger.assisted.Assisted
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScroller.kt b/packages/SystemUI/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScroller.kt
index 572c0e0..3d574ca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScroller.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScroller.kt
@@ -8,7 +8,7 @@
 import android.view.animation.PathInterpolator
 import com.android.internal.annotations.VisibleForTesting
 import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.plugins.qs.QS
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 7755003..91c08a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -52,10 +52,10 @@
 
 import androidx.core.graphics.ColorUtils;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.util.ContrastColorUtil;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.statusbar.notification.NotificationIconDozeHelper;
 import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.util.drawable.DrawableSize;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index 79d01b4a..d6a14604 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -42,6 +42,7 @@
 
 import androidx.annotation.NonNull;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.jank.InteractionJankMonitor;
@@ -49,7 +50,6 @@
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.DejankUtils;
 import com.android.systemui.Dumpable;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
index 2fa27ee..67ab060 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
@@ -25,8 +25,8 @@
 import android.view.ViewGroup;
 import android.view.animation.Interpolator;
 
+import com.android.app.animation.Interpolators;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.statusbar.notification.TransformState;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
index bfc4e9c..eddb683 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
@@ -26,7 +26,7 @@
 import android.widget.FrameLayout
 import com.android.internal.annotations.GuardedBy
 import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.plugins.statusbar.StatusBarStateController
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
index 0446165..b09b9f4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
@@ -21,8 +21,8 @@
 import android.view.View;
 import android.widget.ImageView;
 
+import com.android.app.animation.Interpolators;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.statusbar.CrossFadeHelper;
 import com.android.systemui.statusbar.TransformableView;
 import com.android.systemui.statusbar.notification.row.HybridNotificationView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/LaunchAnimationParameters.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/LaunchAnimationParameters.kt
index c22dbf6..785e65d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/LaunchAnimationParameters.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/LaunchAnimationParameters.kt
@@ -3,7 +3,7 @@
 import android.util.MathUtils
 import com.android.internal.annotations.VisibleForTesting
 import com.android.systemui.animation.ActivityLaunchAnimator
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
 import com.android.systemui.animation.LaunchAnimator
 import kotlin.math.min
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java
index c22cd1b..5a14200 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java
@@ -23,13 +23,13 @@
 import android.view.ViewGroup;
 import android.widget.TextView;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.widget.IMessagingLayout;
 import com.android.internal.widget.MessagingGroup;
 import com.android.internal.widget.MessagingImageMessage;
 import com.android.internal.widget.MessagingLinearLayout;
 import com.android.internal.widget.MessagingMessage;
 import com.android.internal.widget.MessagingPropertyAnimator;
-import com.android.systemui.animation.Interpolators;
 
 import java.util.ArrayList;
 import java.util.HashMap;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java
index 3fc7b13..a045698 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java
@@ -24,8 +24,8 @@
 import android.view.View;
 import android.widget.ImageView;
 
+import com.android.app.animation.Interpolators;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
 
 import java.util.function.Consumer;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index fe0b28d..9ba2199 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -21,8 +21,8 @@
 import androidx.annotation.VisibleForTesting
 import androidx.core.animation.ObjectAnimator
 import com.android.systemui.Dumpable
-import com.android.systemui.animation.Interpolators
-import com.android.systemui.animation.InterpolatorsAndroidX
+import com.android.app.animation.Interpolators
+import com.android.app.animation.InterpolatorsAndroidX
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.plugins.statusbar.StatusBarStateController
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java
index 5d07cac..57d20246 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/PropertyAnimator.java
@@ -24,7 +24,7 @@
 import android.view.View;
 import android.view.animation.Interpolator;
 
-import com.android.systemui.animation.Interpolators;
+import com.android.app.animation.Interpolators;
 import com.android.systemui.statusbar.notification.stack.AnimationFilter;
 import com.android.systemui.statusbar.notification.stack.AnimationProperties;
 import com.android.systemui.statusbar.notification.stack.ViewState;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
index 9f9fba4..90eb630 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
@@ -23,11 +23,11 @@
 import android.widget.ProgressBar;
 import android.widget.TextView;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.widget.MessagingImageMessage;
 import com.android.internal.widget.MessagingPropertyAnimator;
 import com.android.internal.widget.ViewClippingUtil;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.statusbar.CrossFadeHelper;
 import com.android.systemui.statusbar.TransformableView;
 import com.android.systemui.statusbar.ViewTransformationHelper;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ViewGroupFadeHelper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ViewGroupFadeHelper.kt
index dc16274..16f1a45 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ViewGroupFadeHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ViewGroupFadeHelper.kt
@@ -22,7 +22,7 @@
 import android.view.View
 import android.view.ViewGroup
 import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
 
 /**
  * Class to help with fading of view groups without fading one subview
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index 285dd97..8af488e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -31,12 +31,12 @@
 import android.view.animation.Interpolator;
 import android.view.animation.PathInterpolator;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.jank.InteractionJankMonitor.Configuration;
 import com.android.settingslib.Utils;
 import com.android.systemui.Gefingerpoken;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.notification.FakeShadowView;
 import com.android.systemui.statusbar.notification.NotificationUtils;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 1dc58b5..ba8a5f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -64,6 +64,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -72,7 +73,6 @@
 import com.android.internal.widget.CachingIconView;
 import com.android.internal.widget.CallLayout;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java
index b56bae1..7a2bee9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java
@@ -45,10 +45,10 @@
 
 import androidx.annotation.VisibleForTesting;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.logging.InstanceId;
 import com.android.internal.logging.InstanceIdSequence;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.shade.ShadeController;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.notification.logging.NotificationPanelLogger;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index 3e01dd3..f0e15c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -32,9 +32,9 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.app.animation.Interpolators;
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.notification.Roundable;
 import com.android.systemui.statusbar.notification.RoundableState;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
index f21db0b..9bc0333 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
@@ -25,7 +25,7 @@
 import static android.app.NotificationManager.Policy.CONVERSATION_SENDERS_ANYONE;
 import static android.app.NotificationManager.Policy.CONVERSATION_SENDERS_IMPORTANT;
 
-import static com.android.systemui.animation.Interpolators.FAST_OUT_SLOW_IN;
+import static com.android.app.animation.Interpolators.FAST_OUT_SLOW_IN;
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
index 596bdc0..047db20 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
@@ -33,9 +33,9 @@
 
 import androidx.annotation.Nullable;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
 
 /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index 8a50f2f..99a7755 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
@@ -20,7 +20,7 @@
 import static android.app.NotificationManager.IMPORTANCE_LOW;
 import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
 
-import static com.android.systemui.animation.Interpolators.FAST_OUT_SLOW_IN;
+import static com.android.app.animation.Interpolators.FAST_OUT_SLOW_IN;
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
index bafc474..5a129fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
@@ -39,9 +39,9 @@
 import android.widget.FrameLayout;
 import android.widget.FrameLayout.LayoutParams;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.statusbar.AlphaOptimizedImageView;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
index 5f4c926..d5d7f75 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
@@ -45,11 +45,11 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
index 5aaf63f..b24cec1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/StackScrollerDecorView.java
@@ -23,8 +23,8 @@
 import android.view.View;
 import android.view.animation.Interpolator;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.animation.Interpolators;
 
 import java.util.function.Consumer;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
index 2c59c2e..ef5e86f06 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
@@ -34,10 +34,10 @@
 
 import androidx.annotation.Nullable;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.widget.CachingIconView;
 import com.android.internal.widget.NotificationExpandButton;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.statusbar.TransformableView;
 import com.android.systemui.statusbar.ViewTransformationHelper;
 import com.android.systemui.statusbar.notification.CustomInterpolatorTransformation;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java
index 7f3381c..d73bbeb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java
@@ -22,8 +22,8 @@
 import android.animation.ValueAnimator;
 import android.view.View;
 
+import com.android.app.animation.Interpolators;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
index 0b435fe..9a33a94 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
@@ -26,7 +26,7 @@
 import android.view.View;
 import android.view.animation.Interpolator;
 
-import com.android.systemui.animation.Interpolators;
+import com.android.app.animation.Interpolators;
 import com.android.systemui.statusbar.notification.ShadeViewRefactor;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index edff877..cf051fb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -75,6 +75,7 @@
 import android.widget.OverScroller;
 import android.widget.ScrollView;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.graphics.ColorUtils;
 import com.android.internal.jank.InteractionJankMonitor;
@@ -86,7 +87,6 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.ExpandHelper;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
 import com.android.systemui.plugins.ActivityStarter;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
index ee72943..f07dd00 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
@@ -22,9 +22,9 @@
 import android.util.Property;
 import android.view.View;
 
+import com.android.app.animation.Interpolators;
 import com.android.keyguard.KeyguardSliceView;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.shared.clocks.AnimatableClockView;
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.StatusBarIconView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java
index d07da38..f4605be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java
@@ -26,9 +26,9 @@
 import android.view.View;
 import android.view.animation.Interpolator;
 
+import com.android.app.animation.Interpolators;
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.statusbar.notification.AnimatableProperty;
 import com.android.systemui.statusbar.notification.NotificationFadeAware.FadeOptimizedNotification;
 import com.android.systemui.statusbar.notification.PropertyAnimator;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
index 9dce332..4590712 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
@@ -33,9 +33,9 @@
 import android.util.Log;
 import android.view.View;
 
+import com.android.app.animation.Interpolators;
 import com.android.settingslib.Utils;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 90a6d0f..561bd91 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -23,10 +23,10 @@
 import android.content.res.Resources;
 import android.util.MathUtils;
 
+import com.android.app.animation.Interpolators;
 import com.android.keyguard.BouncerPanelExpansionCalculator;
 import com.android.keyguard.KeyguardStatusView;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.shade.ShadeViewController;
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcherListView;
 
@@ -239,7 +239,11 @@
         }
     }
 
-    private int getExpandedPreferredClockY() {
+    /**
+     * give the static topMargin, used for lockscreen clocks to get the initial translationY
+     * to do counter translation
+     */
+    public int getExpandedPreferredClockY() {
         if (mIsSplitShade) {
             return mSplitShadeTargetTopMargin;
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
index 9d30cb4..61c1cc8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
@@ -30,9 +30,9 @@
 
 import androidx.annotation.StyleRes;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.keyguard.KeyguardIndication;
 
 /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 13566ef..720eeba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -43,9 +43,9 @@
 
 import androidx.annotation.VisibleForTesting;
 
+import com.android.app.animation.Interpolators;
 import com.android.settingslib.Utils;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.battery.BatteryMeterView;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index 12ed71b..4d716c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -37,12 +37,12 @@
 import androidx.core.animation.AnimatorListenerAdapter;
 import androidx.core.animation.ValueAnimator;
 
+import com.android.app.animation.InterpolatorsAndroidX;
 import com.android.keyguard.CarrierTextController;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.keyguard.logging.KeyguardLogger;
 import com.android.systemui.R;
-import com.android.systemui.animation.InterpolatorsAndroidX;
 import com.android.systemui.battery.BatteryMeterViewController;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.log.LogLevel;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
index 6bf5443..7bc4fc3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
@@ -24,21 +24,21 @@
 import android.util.MathUtils;
 import android.util.TimeUtils;
 
+import com.android.app.animation.Interpolators;
 import com.android.systemui.Dumpable;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.CommandQueue.Callbacks;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
-import java.io.PrintWriter;
-import java.lang.ref.WeakReference;
-
 import dagger.assisted.Assisted;
 import dagger.assisted.AssistedFactory;
 import dagger.assisted.AssistedInject;
 
+import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+
 /**
  * Class to control all aspects about light bar changes.
  */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index cc4f901..46a2457 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -31,9 +31,9 @@
 import android.util.SparseArray;
 import android.view.ViewTreeObserver.OnPreDrawListener;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.graphics.ColorUtils;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.statusbar.KeyguardAffordanceView;
 
 import java.lang.annotation.Retention;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 55dc188..560ea8a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -15,11 +15,11 @@
 import androidx.annotation.VisibleForTesting;
 import androidx.collection.ArrayMap;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.util.ContrastColorUtil;
 import com.android.settingslib.Utils;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.demomode.DemoMode;
 import com.android.systemui.demomode.DemoModeController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 006a029d..bef422c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -36,10 +36,10 @@
 import androidx.annotation.VisibleForTesting;
 import androidx.collection.ArrayMap;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.settingslib.Utils;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.notification.stack.AnimationFilter;
 import com.android.systemui.statusbar.notification.stack.AnimationProperties;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
index 5e5317d7..07a6d0a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
@@ -29,7 +29,7 @@
 import android.view.animation.AnimationUtils;
 import android.widget.Button;
 
-import com.android.systemui.animation.Interpolators;
+import com.android.app.animation.Interpolators;
 import com.android.systemui.statusbar.AlphaOptimizedImageView;
 
 public class SettingsButton extends AlphaOptimizedImageView {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
index 8fa803e..cdf6652 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
@@ -15,7 +15,7 @@
 import com.android.internal.jank.InteractionJankMonitor.CUJ_SCREEN_OFF
 import com.android.internal.jank.InteractionJankMonitor.CUJ_SCREEN_OFF_SHOW_AOD
 import com.android.systemui.DejankUtils
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyguard.KeyguardViewMediator
 import com.android.systemui.keyguard.WakefulnessLifecycle
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 620d282..5af8932 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
@@ -40,10 +40,10 @@
 import androidx.annotation.VisibleForTesting;
 import androidx.core.animation.Animator;
 
+import com.android.app.animation.Interpolators;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserDetailItemView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserDetailItemView.java
index 4dd63be..e1ec94f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserDetailItemView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserDetailItemView.java
@@ -24,9 +24,9 @@
 
 import androidx.core.graphics.ColorUtils;
 
+import com.android.app.animation.Interpolators;
 import com.android.keyguard.KeyguardConstants;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.qs.tiles.UserDetailItemView;
 
 /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
index 928e011..66b5256 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
@@ -31,6 +31,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 
+import com.android.app.animation.Interpolators;
 import com.android.keyguard.KeyguardConstants;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
@@ -38,7 +39,6 @@
 import com.android.keyguard.dagger.KeyguardUserSwitcherScope;
 import com.android.settingslib.drawable.CircleFramedDrawable;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java
index 850a4b4..363b06a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java
@@ -21,11 +21,11 @@
 import android.util.Log;
 import android.view.View;
 
+import com.android.app.animation.Interpolators;
 import com.android.keyguard.AlphaOptimizedLinearLayout;
 import com.android.keyguard.KeyguardConstants;
 import com.android.settingslib.animation.AppearAnimationUtils;
 import com.android.settingslib.animation.DisappearAnimationUtils;
-import com.android.systemui.animation.Interpolators;
 
 /**
  * The container for the user switcher on Keyguard.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 403a7e8..e311bad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -73,6 +73,7 @@
 import androidx.core.animation.ObjectAnimator;
 import androidx.core.animation.ValueAnimator;
 
+import com.android.app.animation.InterpolatorsAndroidX;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.graphics.ColorUtils;
 import com.android.internal.logging.UiEvent;
@@ -80,7 +81,6 @@
 import com.android.internal.util.ContrastColorUtil;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
-import com.android.systemui.animation.InterpolatorsAndroidX;
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarAnimator.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarAnimator.kt
index 1612388..46954b5 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarAnimator.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarAnimator.kt
@@ -18,7 +18,7 @@
 
 import android.view.View
 import android.view.ViewGroup
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
 import com.android.systemui.animation.ViewHierarchyAnimator
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.util.children
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt
index e819f94..4fbbc89 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt
@@ -34,10 +34,10 @@
 import androidx.annotation.DimenRes
 import androidx.annotation.IdRes
 import androidx.annotation.VisibleForTesting
+import com.android.app.animation.Interpolators
 import com.android.internal.widget.CachingIconView
 import com.android.systemui.Gefingerpoken
 import com.android.systemui.R
-import com.android.systemui.animation.Interpolators
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.common.shared.model.ContentDescription.Companion.loadContentDescription
 import com.android.systemui.common.shared.model.Text.Companion.loadText
diff --git a/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt b/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt
index f0fa779..58f2246 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt
+++ b/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt
@@ -51,6 +51,7 @@
                 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()),
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 43d15bc..4b73d61 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -659,6 +659,10 @@
                     == mColorScheme.getNeutral1().getS500()
                     && res.getColor(android.R.color.system_neutral2_500, theme)
                     == mColorScheme.getNeutral2().getS500()
+                    && res.getColor(android.R.color.system_outline_variant_dark, theme)
+                    == MaterialDynamicColors.outlineVariant().getArgb(mDynamicSchemeDark)
+                    && res.getColor(android.R.color.system_outline_variant_light, theme)
+                    == MaterialDynamicColors.outlineVariant().getArgb(mDynamicSchemeLight)
                     && res.getColor(android.R.color.system_primary_container_dark, theme)
                     == MaterialDynamicColors.primaryContainer().getArgb(mDynamicSchemeDark)
                     && res.getColor(android.R.color.system_primary_container_light, theme)
diff --git a/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace.proto b/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace.proto
index eb23b9d..d940a6b 100644
--- a/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace.proto
+++ b/packages/SystemUI/src/com/android/systemui/tracing/sysui_trace.proto
@@ -16,8 +16,6 @@
 
 syntax = "proto2";
 
-import "frameworks/base/libs/WindowManager/Shell/proto/wm_shell_trace.proto";
-
 package com.android.systemui.tracing;
 
 option java_multiple_files = true;
@@ -25,7 +23,6 @@
 message SystemUiTraceProto {
 
     optional EdgeBackGestureHandlerProto edge_back_gesture_handler = 1;
-    optional com.android.wm.shell.WmShellTraceProto wm_shell = 2;
 }
 
 message EdgeBackGestureHandlerProto {
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayoutController.kt b/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayoutController.kt
index 5d80292..db4ab7e 100644
--- a/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayoutController.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayoutController.kt
@@ -19,7 +19,7 @@
 import android.animation.ValueAnimator
 import android.graphics.PointF
 import android.util.MathUtils
-import com.android.systemui.animation.Interpolators
+import com.android.app.animation.Interpolators
 
 /**
  * The fraction after which we start fading in when going from a gone widget to a visible one
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 77210b7..91078dc 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -109,6 +109,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
@@ -119,7 +120,6 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.media.dialog.MediaOutputDialogFactory;
 import com.android.systemui.plugins.ActivityStarter;
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index e60f9b6..5144d19 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -362,9 +362,6 @@
 
     @Override
     public void writeToProto(SystemUiTraceProto proto) {
-        if (proto.wmShell == null) {
-            proto.wmShell = new WmShellTraceProto();
-        }
         // Dump to WMShell proto here
         // TODO: Figure out how we want to synchronize while dumping to proto
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/InterpolatorsAndroidXTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/InterpolatorsAndroidXTest.kt
deleted file mode 100644
index 2c680be..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/InterpolatorsAndroidXTest.kt
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.systemui.animation
-
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import java.lang.reflect.Modifier
-import junit.framework.Assert.assertEquals
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@SmallTest
-@RunWith(JUnit4::class)
-class InterpolatorsAndroidXTest : SysuiTestCase() {
-
-    @Test
-    fun testInterpolatorsAndInterpolatorsAndroidXPublicMethodsAreEqual() {
-        assertEquals(
-            Interpolators::class.java.getPublicMethods(),
-            InterpolatorsAndroidX::class.java.getPublicMethods()
-        )
-    }
-
-    @Test
-    fun testInterpolatorsAndInterpolatorsAndroidXPublicFieldsAreEqual() {
-        assertEquals(
-            Interpolators::class.java.getPublicFields(),
-            InterpolatorsAndroidX::class.java.getPublicFields()
-        )
-    }
-
-    private fun <T> Class<T>.getPublicMethods() =
-        declaredMethods
-            .filter { Modifier.isPublic(it.modifiers) }
-            .map { it.toString().replace(name, "") }
-            .toSet()
-
-    private fun <T> Class<T>.getPublicFields() =
-        fields.filter { Modifier.isPublic(it.modifiers) }.map { it.name }.toSet()
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
index 6ab54a3..da9ceb4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
@@ -19,6 +19,7 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import com.android.app.animation.Interpolators
 
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
index 6e37ee7..a361bbc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
@@ -68,7 +68,6 @@
 import org.mockito.Mockito.`when` as whenever
 import org.mockito.junit.MockitoJUnit
 
-@Ignore("b/279650412")
 @RunWith(AndroidJUnit4::class)
 @RunWithLooper(setAsMainLooper = true)
 @SmallTest
@@ -281,6 +280,7 @@
         assertThat(authContainer!!.parent).isNull()
     }
 
+    @Ignore("b/279650412")
     @Test
     fun testActionUseDeviceCredential_sendsOnDeviceCredentialPressed() {
         val container = initializeFingerprintContainer(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index da71188..5536d83 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -1388,7 +1388,7 @@
     }
 
     @Test
-    public void onTouch_withNewTouchDetection_doNotPilferWhenPullingUpBouncer()
+    public void onTouch_withNewTouchDetection_doNotProcessTouchWhenPullingUpBouncer()
             throws RemoteException {
         final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L,
                 0L);
@@ -1427,8 +1427,10 @@
         mBiometricExecutor.runAllReady();
         moveEvent.recycle();
 
-        // THEN the touch is NOT pilfered
-        verify(mInputManager, never()).pilferPointers(any());
+        // THEN the touch is NOT processed
+        verify(mFingerprintManager, never()).onPointerDown(anyLong(), anyInt(), anyInt(),
+                anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong(), anyLong(),
+                anyBoolean());
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt
index 8bf32cf..8f6017c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt
@@ -21,22 +21,23 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.keyguard.KeyguardSecurityModel
+import com.android.systemui.RoboPilotTest
 import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.flags.FakeFeatureFlags
 import com.android.systemui.keyguard.DismissCallbackRegistry
 import com.android.systemui.keyguard.data.BouncerView
 import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
 import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
 import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
 import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepositoryImpl
+import com.android.systemui.keyguard.data.repository.TrustRepository
 import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor
 import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor
 import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor
 import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants
 import com.android.systemui.log.table.TableLogBuffer
 import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.RoboPilotTest
 import com.android.systemui.statusbar.StatusBarState
-import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.time.FakeSystemClock
 import com.android.systemui.util.time.SystemClock
@@ -94,7 +95,8 @@
                 mock(DismissCallbackRegistry::class.java),
                 context,
                 mKeyguardUpdateMonitor,
-                mock(KeyguardBypassController::class.java),
+                mock(TrustRepository::class.java),
+                FakeFeatureFlags(),
             )
         mAlternateBouncerInteractor =
             AlternateBouncerInteractor(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
index d0bfaa9..5afc405 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
@@ -23,8 +23,8 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.SmallTest
+import com.android.app.animation.Interpolators
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.animation.Interpolators
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
 import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
index 5da1a84..e261982 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt
@@ -35,12 +35,12 @@
 import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
 import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.TrustRepository
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.TransitionState
 import com.android.systemui.keyguard.shared.model.TransitionStep
 import com.android.systemui.log.FaceAuthenticationLogger
 import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
@@ -100,7 +100,8 @@
                     mock(DismissCallbackRegistry::class.java),
                     context,
                     keyguardUpdateMonitor,
-                    mock(KeyguardBypassController::class.java),
+                    mock(TrustRepository::class.java),
+                    FakeFeatureFlags(),
                 ),
                 AlternateBouncerInteractor(
                     mock(StatusBarStateController::class.java),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt
index 24a47b0..eed1e739 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorTest.kt
@@ -16,7 +16,7 @@
 
 package com.android.systemui.keyguard.domain.interactor
 
-import android.os.Looper
+import android.hardware.biometrics.BiometricSourceType
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
 import android.testing.TestableResources
@@ -28,15 +28,17 @@
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.DismissCallbackRegistry
 import com.android.systemui.keyguard.data.BouncerView
 import com.android.systemui.keyguard.data.BouncerViewDelegate
+import com.android.systemui.keyguard.data.repository.FakeTrustRepository
 import com.android.systemui.keyguard.data.repository.KeyguardBouncerRepository
 import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN
 import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE
 import com.android.systemui.keyguard.shared.model.BouncerShowMessageModel
 import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.whenever
@@ -67,16 +69,23 @@
     @Mock private lateinit var mPrimaryBouncerCallbackInteractor: PrimaryBouncerCallbackInteractor
     @Mock private lateinit var falsingCollector: FalsingCollector
     @Mock private lateinit var dismissCallbackRegistry: DismissCallbackRegistry
-    @Mock private lateinit var keyguardBypassController: KeyguardBypassController
     @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
-    private val mainHandler = FakeHandler(Looper.getMainLooper())
+    private lateinit var mainHandler: FakeHandler
     private lateinit var underTest: PrimaryBouncerInteractor
     private lateinit var resources: TestableResources
+    private lateinit var trustRepository: FakeTrustRepository
+    private lateinit var featureFlags: FakeFeatureFlags
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
+        whenever(keyguardSecurityModel.getSecurityMode(anyInt()))
+            .thenReturn(KeyguardSecurityModel.SecurityMode.PIN)
+
         DejankUtils.setImmediate(true)
+        mainHandler = FakeHandler(android.os.Looper.getMainLooper())
+        trustRepository = FakeTrustRepository()
+        featureFlags = FakeFeatureFlags().apply { set(Flags.DELAY_BOUNCER, false) }
         underTest =
             PrimaryBouncerInteractor(
                 repository,
@@ -89,7 +98,8 @@
                 dismissCallbackRegistry,
                 context,
                 keyguardUpdateMonitor,
-                keyguardBypassController,
+                trustRepository,
+                featureFlags,
             )
         whenever(repository.primaryBouncerStartingDisappearAnimation.value).thenReturn(null)
         whenever(repository.primaryBouncerShow.value).thenReturn(false)
@@ -383,6 +393,55 @@
         verify(repository).setSideFpsShowing(false)
     }
 
+    @Test
+    fun delayBouncerWhenFaceAuthPossible() {
+        mainHandler.setMode(FakeHandler.Mode.QUEUEING)
+
+        // GIVEN bouncer should be delayed due to face auth
+        featureFlags.apply { set(Flags.DELAY_BOUNCER, true) }
+        whenever(keyguardStateController.isFaceAuthEnabled).thenReturn(true)
+        whenever(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(BiometricSourceType.FACE))
+            .thenReturn(true)
+
+        // WHEN bouncer show is requested
+        underTest.show(true)
+
+        // THEN primary show & primary showing soon aren't updated immediately
+        verify(repository, never()).setPrimaryShow(true)
+        verify(repository, never()).setPrimaryShowingSoon(false)
+
+        // WHEN all queued messages are dispatched
+        mainHandler.dispatchQueuedMessages()
+
+        // THEN primary show & primary showing soon are updated
+        verify(repository).setPrimaryShow(true)
+        verify(repository).setPrimaryShowingSoon(false)
+    }
+
+    @Test
+    fun delayBouncerWhenActiveUnlockPossible() {
+        mainHandler.setMode(FakeHandler.Mode.QUEUEING)
+
+        // GIVEN bouncer should be delayed due to active unlock
+        featureFlags.apply { set(Flags.DELAY_BOUNCER, true) }
+        trustRepository.setCurrentUserActiveUnlockAvailable(true)
+        whenever(keyguardUpdateMonitor.canTriggerActiveUnlockBasedOnDeviceState()).thenReturn(true)
+
+        // WHEN bouncer show is requested
+        underTest.show(true)
+
+        // THEN primary show & primary showing soon were scheduled to update
+        verify(repository, never()).setPrimaryShow(true)
+        verify(repository, never()).setPrimaryShowingSoon(false)
+
+        // WHEN all queued messages are dispatched
+        mainHandler.dispatchQueuedMessages()
+
+        // THEN primary show & primary showing soon are updated
+        verify(repository).setPrimaryShow(true)
+        verify(repository).setPrimaryShowingSoon(false)
+    }
+
     private fun updateSideFpsVisibilityParameters(
         isVisible: Boolean,
         sfpsEnabled: Boolean,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt
index e35e971..5056b43 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractorWithCoroutinesTest.kt
@@ -25,9 +25,11 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.flags.FakeFeatureFlags
 import com.android.systemui.keyguard.DismissCallbackRegistry
 import com.android.systemui.keyguard.data.BouncerView
 import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
+import com.android.systemui.keyguard.data.repository.TrustRepository
 import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.utils.os.FakeHandler
@@ -37,6 +39,7 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mock
+import org.mockito.Mockito
 import org.mockito.MockitoAnnotations
 
 @SmallTest
@@ -71,7 +74,8 @@
                 dismissCallbackRegistry,
                 context,
                 keyguardUpdateMonitor,
-                keyguardBypassController,
+                Mockito.mock(TrustRepository::class.java),
+                FakeFeatureFlags(),
             )
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowTest.kt
index a5b78b74..3efe382 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowTest.kt
@@ -17,8 +17,8 @@
 package com.android.systemui.keyguard.ui
 
 import androidx.test.filters.SmallTest
+import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.KeyguardState
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModelTest.kt
index 0e9c99e..e9f1ac1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBouncerViewModelTest.kt
@@ -24,9 +24,11 @@
 import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.flags.FakeFeatureFlags
 import com.android.systemui.keyguard.DismissCallbackRegistry
 import com.android.systemui.keyguard.data.BouncerView
 import com.android.systemui.keyguard.data.repository.FakeKeyguardBouncerRepository
+import com.android.systemui.keyguard.data.repository.TrustRepository
 import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerCallbackInteractor
 import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor
 import com.android.systemui.keyguard.shared.model.BouncerShowMessageModel
@@ -42,6 +44,7 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mock
+import org.mockito.Mockito
 import org.mockito.MockitoAnnotations
 
 @SmallTest
@@ -77,7 +80,8 @@
                 dismissCallbackRegistry,
                 context,
                 keyguardUpdateMonitor,
-                keyguardBypassController,
+                Mockito.mock(TrustRepository::class.java),
+                FakeFeatureFlags(),
             )
         underTest = KeyguardBouncerViewModel(bouncerView, bouncerInteractor)
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt
index 4977775..f1bbd84 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt
@@ -132,7 +132,7 @@
     }
 
     @Test
-    fun initRecentTasksWithAppSelectorTasks_enterprisePoliciesDisabled_bindsOnlyTasksWithHostProfile() {
+    fun initRecentTasksWithAppSelectorTasks_enterprisePoliciesDisabled_bindsAllTasks() {
         givenEnterprisePoliciesFeatureFlag(enabled = false)
 
         val tasks =
@@ -147,11 +147,15 @@
 
         controller.init()
 
+        // TODO (b/263950746): Cross-profile filtering is removed for now. This should be brought
+        // back with the future fix
         verify(view)
             .bind(
                 listOf(
                     createRecentTask(taskId = 1, userId = hostUserHandle.identifier),
+                    createRecentTask(taskId = 2, userId = otherUserHandle.identifier),
                     createRecentTask(taskId = 3, userId = hostUserHandle.identifier),
+                    createRecentTask(taskId = 4, userId = otherUserHandle.identifier),
                     createRecentTask(taskId = 5, userId = hostUserHandle.identifier),
                 )
             )
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
index 26aa37d..d9db60d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
@@ -37,6 +37,8 @@
 import com.android.systemui.R;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.retail.data.repository.FakeRetailModeRepository;
+import com.android.systemui.retail.domain.interactor.RetailModeInteractorImpl;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.utils.leaks.LeakCheckedTest;
 
@@ -67,6 +69,8 @@
     @Mock
     private ActivityStarter mActivityStarter;
 
+    private FakeRetailModeRepository mRetailModeRepository;
+
     private QSFooterViewController mController;
     private View mEditButton;
 
@@ -74,6 +78,9 @@
     public void setup() throws Exception {
         MockitoAnnotations.initMocks(this);
 
+        mRetailModeRepository = new FakeRetailModeRepository();
+        mRetailModeRepository.setRetailMode(false);
+
         mEditButton = new View(mContext);
 
         injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
@@ -89,7 +96,8 @@
         when(mView.findViewById(android.R.id.edit)).thenReturn(mEditButton);
 
         mController = new QSFooterViewController(mView, mUserTracker, mFalsingManager,
-                mActivityStarter, mQSPanelController);
+                mActivityStarter, mQSPanelController,
+                new RetailModeInteractorImpl(mRetailModeRepository));
 
         mController.init();
     }
@@ -132,4 +140,20 @@
         captor.getValue().run();
         verify(mQSPanelController).showEdit(mEditButton);
     }
+
+    @Test
+    public void testEditButton_notRetailMode_visible() {
+        mRetailModeRepository.setRetailMode(false);
+
+        mController.setVisibility(View.VISIBLE);
+        assertThat(mEditButton.getVisibility()).isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void testEditButton_retailMode_notVisible() {
+        mRetailModeRepository.setRetailMode(true);
+
+        mController.setVisibility(View.VISIBLE);
+        assertThat(mEditButton.getVisibility()).isEqualTo(View.GONE);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt
index 50a8d26..fda63ed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt
@@ -25,6 +25,7 @@
 import com.android.systemui.qs.QSHost
 import com.android.systemui.qs.pipeline.shared.TileSpec
 import com.android.systemui.qs.pipeline.shared.logging.QSPipelineLogger
+import com.android.systemui.retail.data.repository.FakeRetailModeRepository
 import com.android.systemui.util.settings.FakeSettings
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -44,6 +45,7 @@
 class TileSpecSettingsRepositoryTest : SysuiTestCase() {
 
     private lateinit var secureSettings: FakeSettings
+    private lateinit var retailModeRepository: FakeRetailModeRepository
 
     @Mock private lateinit var logger: QSPipelineLogger
 
@@ -57,9 +59,12 @@
         MockitoAnnotations.initMocks(this)
 
         secureSettings = FakeSettings()
+        retailModeRepository = FakeRetailModeRepository()
+        retailModeRepository.setRetailMode(false)
 
         with(context.orCreateTestableResources) {
             addOverride(R.string.quick_settings_tiles_default, DEFAULT_TILES)
+            addOverride(R.string.quick_settings_tiles_retail_mode, RETAIL_TILES)
         }
 
         underTest =
@@ -67,6 +72,7 @@
                 secureSettings,
                 context.resources,
                 logger,
+                retailModeRepository,
                 testDispatcher,
             )
     }
@@ -346,6 +352,26 @@
             assertThat(tiles).isEqualTo("b".toTileSpecs())
         }
 
+    @Test
+    fun retailMode_usesRetailTiles() =
+        testScope.runTest {
+            retailModeRepository.setRetailMode(true)
+
+            val tiles by collectLastValue(underTest.tilesSpecs(0))
+
+            assertThat(tiles).isEqualTo(RETAIL_TILES.toTileSpecs())
+        }
+
+    @Test
+    fun retailMode_cannotModifyTiles() =
+        testScope.runTest {
+            retailModeRepository.setRetailMode(true)
+
+            underTest.setTiles(0, DEFAULT_TILES.toTileSpecs())
+
+            assertThat(loadTilesForUser(0)).isNull()
+        }
+
     private fun getDefaultTileSpecs(): List<TileSpec> {
         return QSHost.getDefaultSpecs(context.resources).map(TileSpec::create)
     }
@@ -360,6 +386,7 @@
 
     companion object {
         private const val DEFAULT_TILES = "a,b,c"
+        private const val RETAIL_TILES = "d"
         private const val SETTING = Settings.Secure.QS_TILES
 
         private fun String.toTileSpecs(): List<TileSpec> {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt
new file mode 100644
index 0000000..d7682b2
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt
@@ -0,0 +1,84 @@
+/*
+ * 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.retail.data.repository
+
+import android.provider.Settings
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.util.settings.FakeSettings
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class RetailModeSettingsRepositoryTest : SysuiTestCase() {
+
+    private val globalSettings = FakeSettings()
+
+    private val testDispatcher = StandardTestDispatcher()
+    private val testScope = TestScope(testDispatcher)
+
+    private val underTest =
+        RetailModeSettingsRepository(
+            globalSettings,
+            backgroundDispatcher = testDispatcher,
+            scope = testScope.backgroundScope,
+        )
+
+    @Test
+    fun retailMode_defaultFalse() =
+        testScope.runTest {
+            val value by collectLastValue(underTest.retailMode)
+
+            assertThat(value).isFalse()
+            assertThat(underTest.inRetailMode).isFalse()
+        }
+
+    @Test
+    fun retailMode_false() =
+        testScope.runTest {
+            val value by collectLastValue(underTest.retailMode)
+
+            globalSettings.putInt(SETTING, 0)
+
+            assertThat(value).isFalse()
+            assertThat(underTest.inRetailMode).isFalse()
+        }
+
+    @Test
+    fun retailMode_true() =
+        testScope.runTest {
+            val value by collectLastValue(underTest.retailMode)
+
+            globalSettings.putInt(SETTING, 1)
+
+            assertThat(value).isTrue()
+            assertThat(underTest.inRetailMode).isTrue()
+        }
+
+    companion object {
+        private const val SETTING = Settings.Global.DEVICE_DEMO_MODE
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/retail/domain/interactor/RetailModeInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/retail/domain/interactor/RetailModeInteractorImplTest.kt
new file mode 100644
index 0000000..8f13169
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/retail/domain/interactor/RetailModeInteractorImplTest.kt
@@ -0,0 +1,48 @@
+/*
+ * 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.retail.domain.interactor
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.retail.data.repository.FakeRetailModeRepository
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class RetailModeInteractorImplTest : SysuiTestCase() {
+
+    private val retailModeRepository = FakeRetailModeRepository()
+
+    private val underTest = RetailModeInteractorImpl(retailModeRepository)
+
+    @Test
+    fun retailMode_false() {
+        retailModeRepository.setRetailMode(false)
+
+        assertThat(underTest.isInRetailMode).isFalse()
+    }
+
+    @Test
+    fun retailMode_true() {
+        retailModeRepository.setRetailMode(true)
+
+        assertThat(underTest.isInRetailMode).isTrue()
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java
index 31a33d4..cbd9dba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/appclips/AppClipsTrampolineActivityTest.java
@@ -30,6 +30,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assume.assumeFalse;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
@@ -127,6 +128,9 @@
 
     @Before
     public void setUp() {
+        assumeFalse("Skip test: does not apply to watches",
+            mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH));
+
         MockitoAnnotations.initMocks(this);
         mMainHandler = mContext.getMainThreadHandler();
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerTest.kt
new file mode 100644
index 0000000..d4751c8
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerTest.kt
@@ -0,0 +1,109 @@
+/*
+ * 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.shade
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.testing.TestableResources
+import androidx.constraintlayout.widget.ConstraintSet
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.fragments.FragmentService
+import com.android.systemui.navigationbar.NavigationModeController
+import com.android.systemui.recents.OverviewProxyService
+import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+@SmallTest
+class NotificationsQSContainerControllerTest : SysuiTestCase() {
+
+    @Mock lateinit var view: NotificationsQuickSettingsContainer
+    @Mock lateinit var navigationModeController: NavigationModeController
+    @Mock lateinit var overviewProxyService: OverviewProxyService
+    @Mock lateinit var shadeHeaderController: ShadeHeaderController
+    @Mock lateinit var shadeExpansionStateManager: ShadeExpansionStateManager
+    @Mock lateinit var fragmentService: FragmentService
+
+    lateinit var underTest: NotificationsQSContainerController
+
+    private lateinit var fakeResources: TestableResources
+
+    private val delayableExecutor: DelayableExecutor = FakeExecutor(FakeSystemClock())
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+        fakeResources = TestableResources(context.resources)
+
+        whenever(view.resources).thenReturn(fakeResources.resources)
+
+        underTest =
+            NotificationsQSContainerController(
+                view,
+                navigationModeController,
+                overviewProxyService,
+                shadeHeaderController,
+                shadeExpansionStateManager,
+                fragmentService,
+                delayableExecutor,
+            )
+    }
+
+    @Test
+    fun testSmallScreen_updateResources_splitShadeHeightIsSet() {
+        with(fakeResources) {
+            addOverride(R.bool.config_use_large_screen_shade_header, false)
+            addOverride(R.dimen.qs_header_height, 1)
+            addOverride(R.dimen.large_screen_shade_header_height, 2)
+        }
+
+        underTest.updateResources()
+
+        val captor = ArgumentCaptor.forClass(ConstraintSet::class.java)
+        verify(view).applyConstraints(capture(captor))
+        assertThat(captor.value.getHeight(R.id.split_shade_status_bar)).isEqualTo(1)
+    }
+
+    @Test
+    fun testLargeScreen_updateResources_splitShadeHeightIsSet() {
+        with(fakeResources) {
+            addOverride(R.bool.config_use_large_screen_shade_header, true)
+            addOverride(R.dimen.qs_header_height, 1)
+            addOverride(R.dimen.large_screen_shade_header_height, 2)
+        }
+
+        underTest.updateResources()
+
+        val captor = ArgumentCaptor.forClass(ConstraintSet::class.java)
+        verify(view).applyConstraints(capture(captor))
+        assertThat(captor.value.getHeight(R.id.split_shade_status_bar)).isEqualTo(2)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
index 9fe75ab..20da8a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ShadeHeaderControllerTest.kt
@@ -33,9 +33,9 @@
 import androidx.constraintlayout.motion.widget.MotionLayout
 import androidx.constraintlayout.widget.ConstraintSet
 import androidx.test.filters.SmallTest
+import com.android.app.animation.Interpolators
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.animation.Interpolators
 import com.android.systemui.animation.ShadeInterpolation
 import com.android.systemui.battery.BatteryMeterView
 import com.android.systemui.battery.BatteryMeterViewController
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java
index a1168f8..f0abf2f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/PropertyAnimatorTest.java
@@ -32,9 +32,9 @@
 import android.view.View;
 import android.view.animation.Interpolator;
 
+import com.android.app.animation.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.statusbar.notification.stack.AnimationFilter;
 import com.android.systemui.statusbar.notification.stack.AnimationProperties;
 import com.android.systemui.statusbar.notification.stack.ViewState;
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/animation/FakeLaunchAnimator.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/animation/FakeLaunchAnimator.kt
index 5b431e7..0983041 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/animation/FakeLaunchAnimator.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/animation/FakeLaunchAnimator.kt
@@ -14,6 +14,8 @@
 
 package com.android.systemui.animation
 
+import com.android.app.animation.Interpolators
+
 /** A [LaunchAnimator] to be used in tests. */
 fun fakeLaunchAnimator(): LaunchAnimator {
     return LaunchAnimator(TEST_TIMINGS, TEST_INTERPOLATORS)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeTrustRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeTrustRepository.kt
index 6690de8..f0dbc60 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeTrustRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeTrustRepository.kt
@@ -19,13 +19,23 @@
 
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
 
 class FakeTrustRepository : TrustRepository {
     private val _isCurrentUserTrusted = MutableStateFlow(false)
     override val isCurrentUserTrusted: Flow<Boolean>
         get() = _isCurrentUserTrusted
 
+    private val _isCurrentUserActiveUnlockAvailable = MutableStateFlow(false)
+    override val isCurrentUserActiveUnlockAvailable: StateFlow<Boolean> =
+        _isCurrentUserActiveUnlockAvailable.asStateFlow()
+
     fun setCurrentUserTrusted(trust: Boolean) {
         _isCurrentUserTrusted.value = trust
     }
+
+    fun setCurrentUserActiveUnlockAvailable(available: Boolean) {
+        _isCurrentUserActiveUnlockAvailable.value = available
+    }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/retail/data/repository/FakeRetailModeRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/retail/data/repository/FakeRetailModeRepository.kt
new file mode 100644
index 0000000..75b29ca
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/retail/data/repository/FakeRetailModeRepository.kt
@@ -0,0 +1,36 @@
+/*
+ * 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.retail.data.repository
+
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+class FakeRetailModeRepository : RetailModeRepository {
+
+    private val _retailMode = MutableStateFlow(false)
+    override val retailMode: StateFlow<Boolean> = _retailMode.asStateFlow()
+
+    private var _retailModeValue = false
+    override val inRetailMode: Boolean
+        get() = _retailModeValue
+
+    fun setRetailMode(value: Boolean) {
+        _retailMode.value = value
+        _retailModeValue = value
+    }
+}
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFieldClassificationService.java b/services/autofill/java/com/android/server/autofill/RemoteFieldClassificationService.java
index feae56e..b8bac61 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFieldClassificationService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFieldClassificationService.java
@@ -157,6 +157,8 @@
                                         if (sDebug) {
                                             Log.d(TAG, "onSuccess Response: " + response);
                                         }
+                                        fieldClassificationServiceCallbacks
+                                                .onClassificationRequestSuccess(response);
                                     }
 
                                     @Override
@@ -165,6 +167,8 @@
                                         if (sDebug) {
                                             Log.d(TAG, "onFailure");
                                         }
+                                        fieldClassificationServiceCallbacks
+                                                .onClassificationRequestFailure(0, null);
                                     }
 
                                     @Override
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 3736262..9e46d73 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -204,6 +204,10 @@
         RemoteFieldClassificationService.FieldClassificationServiceCallbacks {
     private static final String TAG = "AutofillSession";
 
+    // This should never be true in production. This is only for local debugging.
+    // Otherwise it will spam logcat.
+    private static final boolean DBG = false;
+
     private static final String ACTION_DELAYED_FILL =
             "android.service.autofill.action.DELAYED_FILL";
     private static final String EXTRA_REQUEST_ID = "android.service.autofill.extra.REQUEST_ID";
@@ -1240,6 +1244,8 @@
 
     @GuardedBy("mLock")
     private void requestAssistStructureForPccLocked(int flags) {
+        if (!mClassificationState.shouldTriggerRequest()) return;
+        mClassificationState.updatePendingRequest();
         // Get request id
         int requestId;
         // TODO(b/158623971): Update this to prevent possible overflow
@@ -1571,12 +1577,18 @@
         // TODO(b/266379948): Ideally wait for PCC request to finish for a while more
         // (say 100ms) before proceeding further on.
 
+        if (DBG) {
+            Slog.d(TAG, "DBG: Initial response: " + response);
+        }
         synchronized (mLock) {
             response = getEffectiveFillResponse(response);
             if (isEmptyResponse(response)) {
                 // Treat it as a null response.
                 processNullResponseLocked(requestId, requestFlags);
             }
+            if (DBG) {
+                Slog.d(TAG, "DBG: Processed response: " + response);
+            }
             processResponseLocked(response, null, requestFlags);
         }
     }
@@ -1601,12 +1613,25 @@
         DatasetComputationContainer autofillProviderContainer = new DatasetComputationContainer();
         computeDatasetsForProviderAndUpdateContainer(response, autofillProviderContainer);
 
+        if (DBG) {
+            Slog.d(TAG, "DBG: computeDatasetsForProviderAndUpdateContainer: "
+                    + autofillProviderContainer);
+        }
         if (!mService.getMaster().isPccClassificationEnabled())  {
+            if (sVerbose) {
+                Slog.v(TAG, "PCC classification is disabled");
+            }
             return createShallowCopy(response, autofillProviderContainer);
         }
         synchronized (mLock) {
             if (mClassificationState.mState != ClassificationState.STATE_RESPONSE
                     || mClassificationState.mLastFieldClassificationResponse == null) {
+                if (sVerbose) {
+                    Slog.v(TAG, "PCC classification no last response:"
+                            + (mClassificationState.mLastFieldClassificationResponse == null)
+                            +   " ,ineligible state="
+                            + (mClassificationState.mState != ClassificationState.STATE_RESPONSE));
+                }
                 return createShallowCopy(response, autofillProviderContainer);
             }
             if (!mClassificationState.processResponse()) return response;
@@ -1614,11 +1639,22 @@
         boolean preferAutofillProvider = mService.getMaster().preferProviderOverPcc();
         boolean shouldUseFallback = mService.getMaster().shouldUsePccFallback();
         if (preferAutofillProvider && !shouldUseFallback) {
+            if (sVerbose) {
+                Slog.v(TAG, "preferAutofillProvider but no fallback");
+            }
             return createShallowCopy(response, autofillProviderContainer);
         }
 
+        if (DBG) {
+            synchronized (mLock) {
+                Slog.d(TAG, "DBG: ClassificationState: " + mClassificationState);
+            }
+        }
         DatasetComputationContainer detectionPccContainer = new DatasetComputationContainer();
         computeDatasetsForPccAndUpdateContainer(response, detectionPccContainer);
+        if (DBG) {
+            Slog.d(TAG, "DBG: computeDatasetsForPccAndUpdateContainer: " + detectionPccContainer);
+        }
 
         DatasetComputationContainer resultContainer;
         if (preferAutofillProvider) {
@@ -1692,6 +1728,20 @@
         // FillResponse.
         Set<Dataset> mDatasets = new LinkedHashSet<>();
         ArrayMap<AutofillId, Set<Dataset>> mAutofillIdToDatasetMap = new ArrayMap<>();
+
+        public String toString() {
+            final StringBuilder builder = new StringBuilder("DatasetComputationContainer[");
+            if (mAutofillIds != null) {
+                builder.append(", autofillIds=").append(mAutofillIds);
+            }
+            if (mDatasets != null) {
+                builder.append(", mDatasets=").append(mDatasets);
+            }
+            if (mAutofillIdToDatasetMap != null) {
+                builder.append(", mAutofillIdToDatasetMap=").append(mAutofillIdToDatasetMap);
+            }
+            return builder.append(']').toString();
+        }
     }
 
     // Adds fallback datasets to the first container.
@@ -1843,7 +1893,6 @@
                 Dataset dataset = datasets.get(i);
                 if (dataset.getAutofillDatatypes() == null
                         || dataset.getAutofillDatatypes().isEmpty()) continue;
-                if (dataset.getFieldIds() != null && dataset.getFieldIds().size() > 0) continue;
 
                 ArrayList<AutofillId> fieldIds = new ArrayList<>();
                 ArrayList<AutofillValue> fieldValues = new ArrayList<>();
@@ -1852,9 +1901,10 @@
                 ArrayList<InlinePresentation> fieldInlinePresentations = new ArrayList<>();
                 ArrayList<InlinePresentation> fieldInlineTooltipPresentations = new ArrayList<>();
                 ArrayList<Dataset.DatasetFieldFilter> fieldFilters = new ArrayList<>();
+                Set<AutofillId> datasetAutofillIds = new ArraySet<>();
 
                 for (int j = 0; j < dataset.getAutofillDatatypes().size(); j++) {
-                    if (dataset.getAutofillDatatypes().get(0) == null) continue;
+                    if (dataset.getAutofillDatatypes().get(j) == null) continue;
                     String hint = dataset.getAutofillDatatypes().get(j);
 
                     if (hintsToAutofillIdMap.containsKey(hint)) {
@@ -1863,6 +1913,7 @@
 
                         for (AutofillId autofillId : tempIds) {
                             eligibleAutofillIds.add(autofillId);
+                            datasetAutofillIds.add(autofillId);
                             // For each of the field, copy over values.
                             fieldIds.add(autofillId);
                             fieldValues.add(dataset.getFieldValues().get(j));
@@ -1876,37 +1927,6 @@
                                     dataset.getFieldInlineTooltipPresentation(j));
                             fieldFilters.add(dataset.getFilter(j));
                         }
-
-                        Dataset newDataset =
-                                new Dataset(
-                                        fieldIds,
-                                        fieldValues,
-                                        fieldPresentations,
-                                        fieldDialogPresentations,
-                                        fieldInlinePresentations,
-                                        fieldInlineTooltipPresentations,
-                                        fieldFilters,
-                                        new ArrayList<>(),
-                                        dataset.getFieldContent(),
-                                        null,
-                                        null,
-                                        null,
-                                        null,
-                                        dataset.getId(),
-                                        dataset.getAuthentication());
-                        eligibleDatasets.add(newDataset);
-
-                        // Associate this dataset with all the ids that are represented with it.
-                        Set<Dataset> newDatasets;
-                        for (AutofillId autofillId : tempIds) {
-                            if (map.containsKey(autofillId)) {
-                                newDatasets = map.get(autofillId);
-                            } else {
-                                newDatasets = new ArraySet<>();
-                            }
-                            newDatasets.add(newDataset);
-                            map.put(autofillId, newDatasets);
-                        }
                     }
                     // TODO(b/266379948):  handle the case:
                     // groupHintsToAutofillIdMap.containsKey(hint))
@@ -1914,6 +1934,34 @@
                     // TODO(b/266379948):  also handle the case where there could be more types in
                     // the dataset, provided by the provider, however, they aren't applicable.
                 }
+                Dataset newDataset =
+                        new Dataset(
+                                fieldIds,
+                                fieldValues,
+                                fieldPresentations,
+                                fieldDialogPresentations,
+                                fieldInlinePresentations,
+                                fieldInlineTooltipPresentations,
+                                fieldFilters,
+                                new ArrayList<>(),
+                                dataset.getFieldContent(),
+                                null,
+                                null,
+                                null,
+                                null,
+                                dataset.getId(),
+                                dataset.getAuthentication());
+                eligibleDatasets.add(newDataset);
+                Set<Dataset> newDatasets;
+                for (AutofillId autofillId : datasetAutofillIds) {
+                    if (map.containsKey(autofillId)) {
+                        newDatasets = map.get(autofillId);
+                    } else {
+                        newDatasets = new ArraySet<>();
+                    }
+                    newDatasets.add(newDataset);
+                    map.put(autofillId, newDatasets);
+                }
             }
             container.mAutofillIds = eligibleAutofillIds;
             container.mDatasets = eligibleDatasets;
@@ -5319,6 +5367,26 @@
             mState = STATE_PENDING_REQUEST;
             mPendingFieldClassificationRequest = null;
         }
+
+        @GuardedBy("mLock")
+        private boolean shouldTriggerRequest() {
+            return mState == STATE_INITIAL || mState == STATE_INVALIDATED;
+        }
+
+        @GuardedBy("mLock")
+        @Override
+        public String toString() {
+            return "ClassificationState: ["
+                    + "state=" + stateToString()
+                    + ", mPendingFieldClassificationRequest=" + mPendingFieldClassificationRequest
+                    + ", mLastFieldClassificationResponse=" + mLastFieldClassificationResponse
+                    + ", mClassificationHintsMap=" + mClassificationHintsMap
+                    + ", mClassificationGroupHintsMap=" + mClassificationGroupHintsMap
+                    + ", mHintsToAutofillIdMap=" + mHintsToAutofillIdMap
+                    + ", mGroupHintsToAutofillIdMap=" + mGroupHintsToAutofillIdMap
+                    + "]";
+        }
+
     }
 
     @Override
@@ -5843,7 +5911,7 @@
         return serviceInfo == null ? Process.INVALID_UID : serviceInfo.applicationInfo.uid;
     }
 
-    // DetectionServiceCallbacks
+    // FieldClassificationServiceCallbacks
     public void onClassificationRequestSuccess(@Nullable FieldClassificationResponse response) {
         mClassificationState.updateResponseReceived(response);
     }
diff --git a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncConnectionService.java b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncConnectionService.java
index 6f99d86..e436e93 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncConnectionService.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncConnectionService.java
@@ -128,9 +128,9 @@
 
     private static final class CallMetadataSyncConnectionIdentifier {
         private final int mAssociationId;
-        private final long mCallId;
+        private final String mCallId;
 
-        CallMetadataSyncConnectionIdentifier(int associationId, long callId) {
+        CallMetadataSyncConnectionIdentifier(int associationId, String callId) {
             mAssociationId = associationId;
             mCallId = callId;
         }
@@ -139,7 +139,7 @@
             return mAssociationId;
         }
 
-        public long getCallId() {
+        public String getCallId() {
             return mCallId;
         }
 
@@ -161,9 +161,7 @@
 
     private abstract static class CallMetadataSyncConnectionCallback {
 
-        abstract void sendCallAction(int associationId, long callId, int action);
-
-        abstract void sendStateChange(int associationId, long callId, int newState);
+        abstract void sendCallAction(int associationId, String callId, int action);
     }
 
     private static class CallMetadataSyncConnection extends Connection {
@@ -184,7 +182,7 @@
             mCallback = callback;
         }
 
-        public long getCallId() {
+        public String getCallId() {
             return mCall.getId();
         }
 
@@ -205,22 +203,22 @@
             }
 
             final Bundle extras = new Bundle();
-            extras.putLong(CrossDeviceCall.EXTRA_CALL_ID, mCall.getId());
+            extras.putString(CrossDeviceCall.EXTRA_CALL_ID, mCall.getId());
             putExtras(extras);
 
             int capabilities = getConnectionCapabilities();
-            if (mCall.hasControl(android.companion.Telecom.Call.PUT_ON_HOLD)) {
+            if (mCall.hasControl(android.companion.Telecom.PUT_ON_HOLD)) {
                 capabilities |= CAPABILITY_HOLD;
             } else {
                 capabilities &= ~CAPABILITY_HOLD;
             }
-            if (mCall.hasControl(android.companion.Telecom.Call.MUTE)) {
+            if (mCall.hasControl(android.companion.Telecom.MUTE)) {
                 capabilities |= CAPABILITY_MUTE;
             } else {
                 capabilities &= ~CAPABILITY_MUTE;
             }
             mAudioManager.setMicrophoneMute(
-                    mCall.hasControl(android.companion.Telecom.Call.UNMUTE));
+                    mCall.hasControl(android.companion.Telecom.UNMUTE));
             if (capabilities != getConnectionCapabilities()) {
                 setConnectionCapabilities(capabilities);
             }
@@ -248,8 +246,8 @@
 
             int capabilities = getConnectionCapabilities();
             final boolean hasHoldControl = mCall.hasControl(
-                    android.companion.Telecom.Call.PUT_ON_HOLD)
-                    || mCall.hasControl(android.companion.Telecom.Call.TAKE_OFF_HOLD);
+                    android.companion.Telecom.PUT_ON_HOLD)
+                    || mCall.hasControl(android.companion.Telecom.TAKE_OFF_HOLD);
             if (hasHoldControl != ((getConnectionCapabilities() & CAPABILITY_HOLD)
                     == CAPABILITY_HOLD)) {
                 if (hasHoldControl) {
@@ -258,7 +256,7 @@
                     capabilities &= ~CAPABILITY_HOLD;
                 }
             }
-            final boolean hasMuteControl = mCall.hasControl(android.companion.Telecom.Call.MUTE);
+            final boolean hasMuteControl = mCall.hasControl(android.companion.Telecom.MUTE);
             if (hasMuteControl != ((getConnectionCapabilities() & CAPABILITY_MUTE)
                     == CAPABILITY_MUTE)) {
                 if (hasMuteControl) {
@@ -268,7 +266,7 @@
                 }
             }
             mAudioManager.setMicrophoneMute(
-                    mCall.hasControl(android.companion.Telecom.Call.UNMUTE));
+                    mCall.hasControl(android.companion.Telecom.UNMUTE));
             if (capabilities != getConnectionCapabilities()) {
                 setConnectionCapabilities(capabilities);
             }
@@ -276,12 +274,12 @@
 
         @Override
         public void onAnswer(int videoState) {
-            sendCallAction(android.companion.Telecom.Call.ACCEPT);
+            sendCallAction(android.companion.Telecom.ACCEPT);
         }
 
         @Override
         public void onReject() {
-            sendCallAction(android.companion.Telecom.Call.REJECT);
+            sendCallAction(android.companion.Telecom.REJECT);
         }
 
         @Override
@@ -296,33 +294,28 @@
 
         @Override
         public void onSilence() {
-            sendCallAction(android.companion.Telecom.Call.SILENCE);
+            sendCallAction(android.companion.Telecom.SILENCE);
         }
 
         @Override
         public void onHold() {
-            sendCallAction(android.companion.Telecom.Call.PUT_ON_HOLD);
+            sendCallAction(android.companion.Telecom.PUT_ON_HOLD);
         }
 
         @Override
         public void onUnhold() {
-            sendCallAction(android.companion.Telecom.Call.TAKE_OFF_HOLD);
+            sendCallAction(android.companion.Telecom.TAKE_OFF_HOLD);
         }
 
         @Override
         public void onMuteStateChanged(boolean isMuted) {
-            sendCallAction(isMuted ? android.companion.Telecom.Call.MUTE
-                    : android.companion.Telecom.Call.UNMUTE);
+            sendCallAction(isMuted ? android.companion.Telecom.MUTE
+                    : android.companion.Telecom.UNMUTE);
         }
 
         @Override
         public void onDisconnect() {
-            sendCallAction(android.companion.Telecom.Call.END);
-        }
-
-        @Override
-        public void onStateChanged(int state) {
-            mCallback.sendStateChange(mAssociationId, mCall.getId(), state);
+            sendCallAction(android.companion.Telecom.END);
         }
 
         private void sendCallAction(int action) {
diff --git a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncData.java b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncData.java
index 1e4bb9a..5b0c745 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncData.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncData.java
@@ -33,14 +33,14 @@
 /** A read-only snapshot of an {@link ContextSyncMessage}. */
 class CallMetadataSyncData {
 
-    final Map<Long, CallMetadataSyncData.Call> mCalls = new HashMap<>();
+    final Map<String, CallMetadataSyncData.Call> mCalls = new HashMap<>();
     final List<CallMetadataSyncData.Call> mRequests = new ArrayList<>();
 
     public void addCall(CallMetadataSyncData.Call call) {
         mCalls.put(call.getId(), call);
     }
 
-    public boolean hasCall(long id) {
+    public boolean hasCall(String id) {
         return mCalls.containsKey(id);
     }
 
@@ -57,7 +57,7 @@
     }
 
     public static class Call implements Parcelable {
-        private long mId;
+        private String mId;
         private String mCallerId;
         private byte[] mAppIcon;
         private String mAppName;
@@ -67,7 +67,7 @@
 
         public static Call fromParcel(Parcel parcel) {
             final Call call = new Call();
-            call.setId(parcel.readLong());
+            call.setId(parcel.readString());
             call.setCallerId(parcel.readString());
             call.setAppIcon(parcel.readBlob());
             call.setAppName(parcel.readString());
@@ -82,7 +82,7 @@
 
         @Override
         public void writeToParcel(Parcel parcel, int parcelableFlags) {
-            parcel.writeLong(mId);
+            parcel.writeString(mId);
             parcel.writeString(mCallerId);
             parcel.writeBlob(mAppIcon);
             parcel.writeString(mAppName);
@@ -94,7 +94,7 @@
             }
         }
 
-        void setId(long id) {
+        void setId(String id) {
             mId = id;
         }
 
@@ -122,7 +122,7 @@
             mControls.add(control);
         }
 
-        long getId() {
+        String getId() {
             return mId;
         }
 
@@ -157,7 +157,7 @@
         @Override
         public boolean equals(Object other) {
             if (other instanceof CallMetadataSyncData.Call) {
-                return ((Call) other).getId() == getId();
+                return mId != null && mId.equals(((Call) other).getId());
             }
             return false;
         }
diff --git a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncInCallService.java b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncInCallService.java
index 443a732..0c23730 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncInCallService.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncInCallService.java
@@ -41,7 +41,6 @@
 public class CallMetadataSyncInCallService extends InCallService {
 
     private static final String TAG = "CallMetadataIcs";
-    private static final long NOT_VALID = -1L;
 
     private CompanionDeviceManagerServiceInternal mCdmsi;
 
@@ -71,7 +70,7 @@
                             callMetadataSyncData.getRequests().iterator();
                     while (iterator.hasNext()) {
                         final CallMetadataSyncData.Call call = iterator.next();
-                        if (call.getId() != 0) {
+                        if (call.getId() != null) {
                             // The call is already assigned an id; treat as control invocations.
                             for (int control : call.getControls()) {
                                 processCallControlAction(call.getId(), control);
@@ -81,41 +80,41 @@
                     }
                 }
 
-                private void processCallControlAction(long crossDeviceCallId,
+                private void processCallControlAction(String crossDeviceCallId,
                         int callControlAction) {
                     final CrossDeviceCall crossDeviceCall = getCallForId(crossDeviceCallId,
                             mCurrentCalls.values());
                     switch (callControlAction) {
-                        case android.companion.Telecom.Call.ACCEPT:
+                        case android.companion.Telecom.ACCEPT:
                             if (crossDeviceCall != null) {
                                 crossDeviceCall.doAccept();
                             }
                             break;
-                        case android.companion.Telecom.Call.REJECT:
+                        case android.companion.Telecom.REJECT:
                             if (crossDeviceCall != null) {
                                 crossDeviceCall.doReject();
                             }
                             break;
-                        case android.companion.Telecom.Call.SILENCE:
+                        case android.companion.Telecom.SILENCE:
                             doSilence();
                             break;
-                        case android.companion.Telecom.Call.MUTE:
+                        case android.companion.Telecom.MUTE:
                             doMute();
                             break;
-                        case android.companion.Telecom.Call.UNMUTE:
+                        case android.companion.Telecom.UNMUTE:
                             doUnmute();
                             break;
-                        case android.companion.Telecom.Call.END:
+                        case android.companion.Telecom.END:
                             if (crossDeviceCall != null) {
                                 crossDeviceCall.doEnd();
                             }
                             break;
-                        case android.companion.Telecom.Call.PUT_ON_HOLD:
+                        case android.companion.Telecom.PUT_ON_HOLD:
                             if (crossDeviceCall != null) {
                                 crossDeviceCall.doPutOnHold();
                             }
                             break;
-                        case android.companion.Telecom.Call.TAKE_OFF_HOLD:
+                        case android.companion.Telecom.TAKE_OFF_HOLD:
                             if (crossDeviceCall != null) {
                                 crossDeviceCall.doTakeOffHold();
                             }
@@ -171,12 +170,12 @@
 
     @Nullable
     @VisibleForTesting
-    CrossDeviceCall getCallForId(long crossDeviceCallId, Collection<CrossDeviceCall> calls) {
-        if (crossDeviceCallId == NOT_VALID) {
+    CrossDeviceCall getCallForId(String crossDeviceCallId, Collection<CrossDeviceCall> calls) {
+        if (crossDeviceCallId == null) {
             return null;
         }
         for (CrossDeviceCall crossDeviceCall : calls) {
-            if (crossDeviceCall.getId() == crossDeviceCallId) {
+            if (crossDeviceCallId.equals(crossDeviceCall.getId())) {
                 return crossDeviceCall;
             }
         }
diff --git a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceCall.java b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceCall.java
index ac981d4..168068e 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceCall.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceCall.java
@@ -23,7 +23,6 @@
 import android.graphics.Canvas;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
-import android.os.Bundle;
 import android.telecom.Call;
 import android.telecom.CallAudioState;
 import android.telecom.VideoProfile;
@@ -34,7 +33,7 @@
 import java.io.ByteArrayOutputStream;
 import java.util.HashSet;
 import java.util.Set;
-import java.util.concurrent.atomic.AtomicLong;
+import java.util.UUID;
 
 /** Data holder for a telecom call and additional metadata. */
 public class CrossDeviceCall {
@@ -45,9 +44,7 @@
             "com.android.companion.datatransfer.contextsync.extra.CALL_ID";
     private static final int APP_ICON_BITMAP_DIMENSION = 256;
 
-    private static final AtomicLong sNextId = new AtomicLong(1);
-
-    private final long mId;
+    private final String mId;
     private Call mCall;
     @VisibleForTesting boolean mIsEnterprise;
     @VisibleForTesting boolean mIsOtt;
@@ -64,14 +61,14 @@
             CallAudioState callAudioState) {
         this(packageManager, call.getDetails(), callAudioState);
         mCall = call;
-        final Bundle extras = new Bundle();
-        extras.putLong(EXTRA_CALL_ID, mId);
-        call.putExtras(extras);
+        call.putExtra(EXTRA_CALL_ID, mId);
     }
 
     CrossDeviceCall(PackageManager packageManager, Call.Details callDetails,
             CallAudioState callAudioState) {
-        mId = sNextId.getAndIncrement();
+        final String predefinedId = callDetails.getIntentExtras() != null
+                ? callDetails.getIntentExtras().getString(EXTRA_CALL_ID) : null;
+        mId = predefinedId != null ? predefinedId : UUID.randomUUID().toString();
         mCallingAppPackageName =
                 callDetails.getAccountHandle().getComponentName().getPackageName();
         mIsOtt = (callDetails.getCallCapabilities() & Call.Details.PROPERTY_SELF_MANAGED)
@@ -145,7 +142,7 @@
         if (mStatus == android.companion.Telecom.Call.RINGING) {
             mStatus = android.companion.Telecom.Call.RINGING_SILENCED;
         }
-        mControls.remove(android.companion.Telecom.Call.SILENCE);
+        mControls.remove(android.companion.Telecom.SILENCE);
     }
 
     @VisibleForTesting
@@ -156,26 +153,26 @@
         mControls.clear();
         if (mStatus == android.companion.Telecom.Call.RINGING
                 || mStatus == android.companion.Telecom.Call.RINGING_SILENCED) {
-            mControls.add(android.companion.Telecom.Call.ACCEPT);
-            mControls.add(android.companion.Telecom.Call.REJECT);
+            mControls.add(android.companion.Telecom.ACCEPT);
+            mControls.add(android.companion.Telecom.REJECT);
             if (mStatus == android.companion.Telecom.Call.RINGING) {
-                mControls.add(android.companion.Telecom.Call.SILENCE);
+                mControls.add(android.companion.Telecom.SILENCE);
             }
         }
         if (mStatus == android.companion.Telecom.Call.ONGOING
                 || mStatus == android.companion.Telecom.Call.ON_HOLD) {
-            mControls.add(android.companion.Telecom.Call.END);
+            mControls.add(android.companion.Telecom.END);
             if (callDetails.can(Call.Details.CAPABILITY_HOLD)) {
                 mControls.add(
                         mStatus == android.companion.Telecom.Call.ON_HOLD
-                                ? android.companion.Telecom.Call.TAKE_OFF_HOLD
-                                : android.companion.Telecom.Call.PUT_ON_HOLD);
+                                ? android.companion.Telecom.TAKE_OFF_HOLD
+                                : android.companion.Telecom.PUT_ON_HOLD);
             }
         }
         if (mStatus == android.companion.Telecom.Call.ONGOING && callDetails.can(
                 Call.Details.CAPABILITY_MUTE)) {
-            mControls.add(mIsMuted ? android.companion.Telecom.Call.UNMUTE
-                    : android.companion.Telecom.Call.MUTE);
+            mControls.add(mIsMuted ? android.companion.Telecom.UNMUTE
+                    : android.companion.Telecom.MUTE);
         }
     }
 
@@ -212,7 +209,7 @@
         }
     }
 
-    public long getId() {
+    public String getId() {
         return mId;
     }
 
diff --git a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncController.java b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncController.java
index adc5faf..e5ab963 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncController.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncController.java
@@ -270,7 +270,7 @@
         while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
             switch (pis.getFieldNumber()) {
                 case (int) Telecom.Call.ID:
-                    call.setId(pis.readLong(Telecom.Call.ID));
+                    call.setId(pis.readString(Telecom.Call.ID));
                     break;
                 case (int) Telecom.Call.ORIGIN:
                     final long originToken = pis.start(Telecom.Call.ORIGIN);
@@ -336,7 +336,7 @@
     }
 
     /** Create a call control message. */
-    public static byte[] createCallControlMessage(long callId, int control) {
+    public static byte[] createCallControlMessage(String callId, int control) {
         final ProtoOutputStream pos = new ProtoOutputStream();
         pos.write(ContextSyncMessage.VERSION, CURRENT_VERSION);
         final long telecomToken = pos.start(ContextSyncMessage.TELECOM);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index a992765..48898a6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -14247,7 +14247,8 @@
                 throw new SecurityException(
                         "Intent " + intent.getAction() + " may not be broadcast from an SDK sandbox"
                         + " uid. Given caller package " + callerPackage + " (pid=" + callingPid
-                        + ", uid=" + callingUid + ")");
+                        + ", realCallingUid=" + realCallingUid + ", callingUid= " + callingUid
+                        + ")");
             }
         }
 
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 06af2ce..334c145 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -583,7 +583,10 @@
                 // user transitions to RUNNING_LOCKED.  However, in "headless system user mode", the
                 // system user is explicitly started before the device has finished booting.  In
                 // that case, we need to wait until onBootComplete() to send the broadcast.
-                if (!(mInjector.isHeadlessSystemUserMode() && uss.mHandle.isSystem())) {
+                // Similarly, this occurs after a user switch, but in HSUM we switch to the main
+                // user before boot is complete, so again this should be delayed until
+                // onBootComplete if boot has not yet completed.
+                if (mAllowUserUnlocking) {
                     // ACTION_LOCKED_BOOT_COMPLETED
                     sendLockedBootCompletedBroadcast(resultTo, userId);
                 }
@@ -2564,9 +2567,9 @@
         // we should *not* transition users out of the BOOTING state using finishUserBoot(), as that
         // doesn't handle issuing the needed onUserStarting() call, and it would just race with an
         // explicit start anyway.  We do, however, need to send the "locked boot complete" broadcast
-        // for the system user, as that got skipped earlier due to the *device* boot not being
-        // complete yet.  We also need to try to unlock all started users, since until now explicit
-        // user starts didn't proceed to unlocking, due to it being too early in the device boot.
+        // as that got skipped earlier due to the *device* boot not being complete yet.
+        // We also need to try to unlock all started users, since until now explicit user starts
+        // didn't proceed to unlocking, due to it being too early in the device boot.
         //
         // USER_SYSTEM must be processed first.  It will be first in the array, as its ID is lowest.
         Preconditions.checkArgument(startedUsers.keyAt(0) == UserHandle.USER_SYSTEM);
@@ -2576,9 +2579,7 @@
             if (!mInjector.isHeadlessSystemUserMode()) {
                 finishUserBoot(uss, resultTo);
             } else {
-                if (userId == UserHandle.USER_SYSTEM) {
-                    sendLockedBootCompletedBroadcast(resultTo, userId);
-                }
+                sendLockedBootCompletedBroadcast(resultTo, userId);
                 maybeUnlockUser(userId);
             }
         }
diff --git a/services/core/java/com/android/server/am/UserSwitchingDialog.java b/services/core/java/com/android/server/am/UserSwitchingDialog.java
index 412fbe79..4e7865c 100644
--- a/services/core/java/com/android/server/am/UserSwitchingDialog.java
+++ b/services/core/java/com/android/server/am/UserSwitchingDialog.java
@@ -33,6 +33,8 @@
 import android.graphics.drawable.Animatable2;
 import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Looper;
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.os.UserHandle;
@@ -53,6 +55,8 @@
 import com.android.internal.util.UserIcons;
 import com.android.server.wm.WindowManagerService;
 
+import java.util.concurrent.atomic.AtomicBoolean;
+
 /**
  * Dialog to show during the user switch. This dialog shows target user's name and their profile
  * picture with a circular spinner animation around it if the animations for this dialog are not
@@ -64,9 +68,14 @@
 
     // User switching doesn't happen that frequently, so it doesn't hurt to have it always on
     protected static final boolean DEBUG = true;
+
     private static final long DIALOG_SHOW_HIDE_ANIMATION_DURATION_MS = 300;
     private final boolean mDisableAnimations;
 
+    // Time to wait for the onAnimationEnd() callbacks before moving on
+    private static final int ANIMATION_TIMEOUT_MS = 1000;
+    private final Handler mHandler = new Handler(Looper.myLooper());
+
     protected final UserInfo mOldUser;
     protected final UserInfo mNewUser;
     private final String mSwitchingFromSystemUserMessage;
@@ -180,7 +189,7 @@
 
     @Override
     public void show() {
-        asyncTraceBegin("", 0);
+        asyncTraceBegin("dialog", 0);
         super.show();
     }
 
@@ -188,7 +197,7 @@
     public void dismiss() {
         super.dismiss();
         stopFreezingScreen();
-        asyncTraceEnd("", 0);
+        asyncTraceEnd("dialog", 0);
     }
 
     public void show(@NonNull Runnable onShown) {
@@ -217,20 +226,18 @@
         if (!mNeedToFreezeScreen) {
             return;
         }
-        if (DEBUG) Slog.d(TAG, "startFreezingScreen");
-        Trace.traceBegin(TRACE_TAG, "startFreezingScreen");
+        traceBegin("startFreezingScreen");
         mWindowManager.startFreezingScreen(0, 0);
-        Trace.traceEnd(TRACE_TAG);
+        traceEnd("startFreezingScreen");
     }
 
     private void stopFreezingScreen() {
         if (!mNeedToFreezeScreen) {
             return;
         }
-        if (DEBUG) Slog.d(TAG, "stopFreezingScreen");
-        Trace.traceBegin(TRACE_TAG, "stopFreezingScreen");
+        traceBegin("stopFreezingScreen");
         mWindowManager.stopFreezingScreen();
-        Trace.traceEnd(TRACE_TAG);
+        traceEnd("stopFreezingScreen");
     }
 
     private void startShowAnimation(Runnable onAnimationEnd) {
@@ -238,13 +245,13 @@
             onAnimationEnd.run();
             return;
         }
-        asyncTraceBegin("-showAnimation", 1);
-        startDialogAnimation(new AlphaAnimation(0, 1), () -> {
-            asyncTraceEnd("-showAnimation", 1);
+        asyncTraceBegin("showAnimation", 1);
+        startDialogAnimation("show", new AlphaAnimation(0, 1), () -> {
+            asyncTraceEnd("showAnimation", 1);
 
-            asyncTraceBegin("-spinnerAnimation", 2);
+            asyncTraceBegin("spinnerAnimation", 2);
             startProgressAnimation(() -> {
-                asyncTraceEnd("-spinnerAnimation", 2);
+                asyncTraceEnd("spinnerAnimation", 2);
 
                 onAnimationEnd.run();
             });
@@ -257,9 +264,9 @@
             onAnimationEnd.run();
             return;
         }
-        asyncTraceBegin("-dismissAnimation", 3);
-        startDialogAnimation(new AlphaAnimation(1, 0), () -> {
-            asyncTraceEnd("-dismissAnimation", 3);
+        asyncTraceBegin("dismissAnimation", 3);
+        startDialogAnimation("dismiss", new AlphaAnimation(1, 0), () -> {
+            asyncTraceEnd("dismissAnimation", 3);
 
             onAnimationEnd.run();
         });
@@ -271,10 +278,11 @@
             onAnimationEnd.run();
             return;
         }
+        final Runnable onAnimationEndWithTimeout = animationWithTimeout("spinner", onAnimationEnd);
         avd.registerAnimationCallback(new Animatable2.AnimationCallback() {
             @Override
             public void onAnimationEnd(Drawable drawable) {
-                onAnimationEnd.run();
+                onAnimationEndWithTimeout.run();
             }
         });
         avd.start();
@@ -291,12 +299,13 @@
         return null;
     }
 
-    private void startDialogAnimation(Animation animation, Runnable onAnimationEnd) {
+    private void startDialogAnimation(String name, Animation animation, Runnable onAnimationEnd) {
         final View view = findViewById(R.id.content);
         if (mDisableAnimations || view == null) {
             onAnimationEnd.run();
             return;
         }
+        final Runnable onAnimationEndWithTimeout = animationWithTimeout(name, onAnimationEnd);
         animation.setDuration(DIALOG_SHOW_HIDE_ANIMATION_DURATION_MS);
         animation.setAnimationListener(new Animation.AnimationListener() {
             @Override
@@ -306,7 +315,7 @@
 
             @Override
             public void onAnimationEnd(Animation animation) {
-                onAnimationEnd.run();
+                onAnimationEndWithTimeout.run();
             }
 
             @Override
@@ -317,11 +326,39 @@
         view.startAnimation(animation);
     }
 
+    private Runnable animationWithTimeout(String name, Runnable onAnimationEnd) {
+        final AtomicBoolean isFirst = new AtomicBoolean(true);
+        final Runnable onAnimationEndOrTimeout = () -> {
+            if (isFirst.getAndSet(false)) {
+                mHandler.removeCallbacksAndMessages(null);
+                onAnimationEnd.run();
+            }
+        };
+        mHandler.postDelayed(() -> {
+            Slog.w(TAG, name + " animation not completed in " + ANIMATION_TIMEOUT_MS + " ms");
+            onAnimationEndOrTimeout.run();
+        }, ANIMATION_TIMEOUT_MS);
+
+        return onAnimationEndOrTimeout;
+    }
+
     private void asyncTraceBegin(String subTag, int subCookie) {
+        if (DEBUG) Slog.d(TAG, "asyncTraceBegin-" + subTag);
         Trace.asyncTraceBegin(TRACE_TAG, TAG + subTag, mTraceCookie + subCookie);
     }
 
     private void asyncTraceEnd(String subTag, int subCookie) {
         Trace.asyncTraceEnd(TRACE_TAG, TAG + subTag, mTraceCookie + subCookie);
+        if (DEBUG) Slog.d(TAG, "asyncTraceEnd-" + subTag);
+    }
+
+    private void traceBegin(String msg) {
+        if (DEBUG) Slog.d(TAG, "traceBegin-" + msg);
+        Trace.traceBegin(TRACE_TAG, msg);
+    }
+
+    private void traceEnd(String msg) {
+        Trace.traceEnd(TRACE_TAG);
+        if (DEBUG) Slog.d(TAG, "traceEnd-" + msg);
     }
 }
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index d369af6..e4a5a3e 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -402,11 +402,15 @@
     public enum FrameRate {
         FPS_DEFAULT(0),
         FPS_30(30),
+        FPS_36(36),
         FPS_40(40),
         FPS_45(45),
+        FPS_48(48),
         FPS_60(60),
+        FPS_72(72),
         FPS_90(90),
         FPS_120(120),
+        FPS_144(144),
         FPS_INVALID(-1);
 
         public final int fps;
@@ -423,16 +427,24 @@
         switch (raw) {
             case "30":
                 return FrameRate.FPS_30.fps;
+            case "36":
+                return FrameRate.FPS_36.fps;
             case "40":
                 return FrameRate.FPS_40.fps;
             case "45":
                 return FrameRate.FPS_45.fps;
+            case "48":
+                return FrameRate.FPS_48.fps;
             case "60":
                 return FrameRate.FPS_60.fps;
+            case "72":
+                return FrameRate.FPS_72.fps;
             case "90":
                 return FrameRate.FPS_90.fps;
             case "120":
                 return FrameRate.FPS_120.fps;
+            case "144":
+                return FrameRate.FPS_144.fps;
             case "disable":
             case "":
                 return FrameRate.FPS_DEFAULT.fps;
diff --git a/services/core/java/com/android/server/audio/SoundDoseHelper.java b/services/core/java/com/android/server/audio/SoundDoseHelper.java
index 9429b4c..4984f12 100644
--- a/services/core/java/com/android/server/audio/SoundDoseHelper.java
+++ b/services/core/java/com/android/server/audio/SoundDoseHelper.java
@@ -303,8 +303,6 @@
                 SAFE_MEDIA_VOLUME_UNINITIALIZED);
         mSafeMediaVolumeDevices.append(AudioSystem.DEVICE_OUT_BLE_BROADCAST,
                 SAFE_MEDIA_VOLUME_UNINITIALIZED);
-        mSafeMediaVolumeDevices.append(AudioSystem.DEVICE_OUT_HEARING_AID,
-                SAFE_MEDIA_VOLUME_UNINITIALIZED);
         mSafeMediaVolumeDevices.append(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,
                 SAFE_MEDIA_VOLUME_UNINITIALIZED);
         // TODO(b/278265907): enable A2DP when we can distinguish A2DP headsets
diff --git a/services/core/java/com/android/server/display/color/CctEvaluator.java b/services/core/java/com/android/server/display/color/CctEvaluator.java
new file mode 100644
index 0000000..878f7e5
--- /dev/null
+++ b/services/core/java/com/android/server/display/color/CctEvaluator.java
@@ -0,0 +1,108 @@
+/*
+ * 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.server.display.color;
+
+import android.animation.TypeEvaluator;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Arrays;
+
+/**
+ * Interpolates between CCT values by a given step.
+ */
+class CctEvaluator implements TypeEvaluator<Integer> {
+
+    private static final String TAG = "CctEvaluator";
+
+    /**
+     * The minimum input value, which will represent index 0 in the mValues array. Each
+     * subsequent input value is offset by this amount.
+     */
+    private final int mIndexOffset;
+    /**
+     * Cached step values at each CCT value (offset by the {@link #mIndexOffset} above). For
+     * example, if the minimum CCT is 2000K (which is set to mIndexOffset), then the 0th index of
+     * this array is equivalent to the step value at 2000K, 1st index corresponds to 2001K, and so
+     * on.
+     */
+    @VisibleForTesting
+    final int[] mStepsAtOffsetCcts;
+    /**
+     * Pre-computed stepped CCTs. These will be accessed frequently; the memory cost of caching them
+     * is well-spent.
+     */
+    @VisibleForTesting
+    final int[] mSteppedCctsAtOffsetCcts;
+
+    CctEvaluator(int min, int max, int[] cctRangeMinimums, int[] steps) {
+        final int delta = max - min + 1;
+        mStepsAtOffsetCcts = new int[delta];
+        mSteppedCctsAtOffsetCcts = new int[delta];
+        mIndexOffset = min;
+
+        final int parallelArraysLength = cctRangeMinimums.length;
+        if (cctRangeMinimums.length != steps.length) {
+            Slog.e(TAG,
+                    "Parallel arrays cctRangeMinimums and steps are different lengths; setting "
+                            + "step of 1");
+            setStepOfOne();
+        } else if (parallelArraysLength == 0) {
+            Slog.e(TAG, "No cctRangeMinimums or steps are set; setting step of 1");
+            setStepOfOne();
+        } else {
+            int parallelArraysIndex = 0;
+            int index = 0;
+            int lastSteppedCct = Integer.MIN_VALUE;
+            while (index < delta) {
+                final int cct = index + mIndexOffset;
+                int nextParallelArraysIndex = parallelArraysIndex + 1;
+                while (nextParallelArraysIndex < parallelArraysLength
+                        && cct >= cctRangeMinimums[nextParallelArraysIndex]) {
+                    parallelArraysIndex = nextParallelArraysIndex;
+                    nextParallelArraysIndex++;
+                }
+                mStepsAtOffsetCcts[index] = steps[parallelArraysIndex];
+                if (lastSteppedCct == Integer.MIN_VALUE
+                        || Math.abs(lastSteppedCct - cct) >= steps[parallelArraysIndex]) {
+                    lastSteppedCct = cct;
+                }
+                mSteppedCctsAtOffsetCcts[index] = lastSteppedCct;
+                index++;
+            }
+        }
+    }
+
+    @Override
+    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
+        final int cct = (int) (startValue + fraction * (endValue - startValue));
+        final int index = cct - mIndexOffset;
+        if (index < 0 || index >= mSteppedCctsAtOffsetCcts.length) {
+            Slog.e(TAG, "steppedCctValueAt: returning same since invalid requested index=" + index);
+            return cct;
+        }
+        return mSteppedCctsAtOffsetCcts[index];
+    }
+
+    private void setStepOfOne() {
+        Arrays.fill(mStepsAtOffsetCcts, 1);
+        for (int i = 0; i < mSteppedCctsAtOffsetCcts.length; i++) {
+            mSteppedCctsAtOffsetCcts[i] = mIndexOffset + i;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/display/color/ColorDisplayService.java b/services/core/java/com/android/server/display/color/ColorDisplayService.java
index 0284d9c..c0ea5fea 100644
--- a/services/core/java/com/android/server/display/color/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java
@@ -180,6 +180,8 @@
      */
     private SparseIntArray mColorModeCompositionColorSpaces = null;
 
+    private final Object mCctTintApplierLock = new Object();
+
     public ColorDisplayService(Context context) {
         super(context);
         mHandler = new TintHandler(DisplayThread.get().getLooper());
@@ -698,6 +700,79 @@
         }
     }
 
+    private void applyTintByCct(ColorTemperatureTintController tintController, boolean immediate) {
+        synchronized (mCctTintApplierLock) {
+            tintController.cancelAnimator();
+
+            final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
+            final int from = tintController.getAppliedCct();
+            final int to = tintController.isActivated() ? tintController.getTargetCct()
+                    : tintController.getDisabledCct();
+
+            if (immediate) {
+                Slog.d(TAG, tintController.getClass().getSimpleName()
+                        + " applied immediately: toCct=" + to + " fromCct=" + from);
+                dtm.setColorMatrix(tintController.getLevel(),
+                        tintController.computeMatrixForCct(to));
+                tintController.setAppliedCct(to);
+            } else {
+                Slog.d(TAG, tintController.getClass().getSimpleName() + " animation started: toCct="
+                        + to + " fromCct=" + from);
+                ValueAnimator valueAnimator = ValueAnimator.ofInt(from, to);
+                tintController.setAnimator(valueAnimator);
+                final CctEvaluator evaluator = tintController.getEvaluator();
+                if (evaluator != null) {
+                    valueAnimator.setEvaluator(evaluator);
+                }
+                valueAnimator.setDuration(tintController.getTransitionDurationMilliseconds());
+                valueAnimator.setInterpolator(AnimationUtils.loadInterpolator(
+                        getContext(), android.R.interpolator.linear));
+                valueAnimator.addUpdateListener((ValueAnimator animator) -> {
+                    synchronized (mCctTintApplierLock) {
+                        final int value = (int) animator.getAnimatedValue();
+                        if (value != tintController.getAppliedCct()) {
+                            dtm.setColorMatrix(tintController.getLevel(),
+                                    tintController.computeMatrixForCct(value));
+                            tintController.setAppliedCct(value);
+                        }
+                    }
+                });
+                valueAnimator.addListener(new AnimatorListenerAdapter() {
+
+                    private boolean mIsCancelled;
+
+                    @Override
+                    public void onAnimationCancel(Animator animator) {
+                        Slog.d(TAG, tintController.getClass().getSimpleName()
+                                + " animation cancelled");
+                        mIsCancelled = true;
+                    }
+
+                    @Override
+                    public void onAnimationEnd(Animator animator) {
+                        synchronized (mCctTintApplierLock) {
+                            Slog.d(TAG, tintController.getClass().getSimpleName()
+                                    + " animation ended: wasCancelled=" + mIsCancelled
+                                    + " toCct=" + to
+                                    + " fromCct=" + from);
+                            if (!mIsCancelled) {
+                                // Ensure final color matrix is set at the end of the animation.
+                                // If the animation is cancelled then don't set the final color
+                                // matrix so the new animator can pick up from where this one left
+                                // off.
+                                dtm.setColorMatrix(tintController.getLevel(),
+                                        tintController.computeMatrixForCct(to));
+                                tintController.setAppliedCct(to);
+                            }
+                            tintController.setAnimator(null);
+                        }
+                    }
+                });
+                valueAnimator.start();
+            }
+        }
+    }
+
     /**
      * Returns the first date time corresponding to the local time that occurs before the provided
      * date time.
@@ -747,7 +822,7 @@
 
         // If disabled, clear the tint. If enabled, do nothing more here and let the next
         // temperature update set the correct tint.
-        if (!activated) {
+        if (oldActivated && !activated) {
             mHandler.sendEmptyMessage(MSG_APPLY_DISPLAY_WHITE_BALANCE);
         }
     }
@@ -1452,7 +1527,7 @@
     public class ColorDisplayServiceInternal {
 
         /** Sets whether DWB should be allowed in the current state. */
-        public void setDisplayWhiteBalanceAllowed(boolean allowed)  {
+        public void setDisplayWhiteBalanceAllowed(boolean allowed) {
             mDisplayWhiteBalanceTintController.setAllowed(allowed);
             updateDisplayWhiteBalanceStatus();
         }
@@ -1464,8 +1539,8 @@
          * @param cct the color temperature in Kelvin.
          */
         public boolean setDisplayWhiteBalanceColorTemperature(int cct) {
-            // Update the transform matrix even if it can't be applied.
-            mDisplayWhiteBalanceTintController.setMatrix(cct);
+            // Update the transform target CCT even if it can't be applied.
+            mDisplayWhiteBalanceTintController.setTargetCct(cct);
 
             if (mDisplayWhiteBalanceTintController.isActivated()) {
                 mHandler.sendEmptyMessage(MSG_APPLY_DISPLAY_WHITE_BALANCE);
@@ -1601,7 +1676,7 @@
                     applyTint(mNightDisplayTintController, false);
                     break;
                 case MSG_APPLY_DISPLAY_WHITE_BALANCE:
-                    applyTint(mDisplayWhiteBalanceTintController, false);
+                    applyTintByCct(mDisplayWhiteBalanceTintController, false);
                     break;
             }
         }
diff --git a/services/core/java/com/android/server/display/color/ColorTemperatureTintController.java b/services/core/java/com/android/server/display/color/ColorTemperatureTintController.java
new file mode 100644
index 0000000..0fbd9d4
--- /dev/null
+++ b/services/core/java/com/android/server/display/color/ColorTemperatureTintController.java
@@ -0,0 +1,38 @@
+/*
+ * 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.server.display.color;
+
+abstract class ColorTemperatureTintController extends TintController {
+
+    abstract int getAppliedCct();
+
+    abstract void setAppliedCct(int cct);
+
+    abstract int getTargetCct();
+
+    abstract void setTargetCct(int cct);
+
+    /**
+     * Returns the CCT value most closely associated with the "disabled" (identity) matrix for
+     * this device, to use as the target when deactivating this transform.
+     */
+    abstract int getDisabledCct();
+
+    abstract float[] computeMatrixForCct(int cct);
+
+    abstract CctEvaluator getEvaluator();
+}
diff --git a/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java b/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java
index 106ac0c..bf0139f 100644
--- a/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java
+++ b/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java
@@ -21,6 +21,7 @@
 import static com.android.server.display.color.DisplayTransformManager.LEVEL_COLOR_MATRIX_DISPLAY_WHITE_BALANCE;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.Size;
 import android.content.Context;
 import android.content.res.Resources;
@@ -36,7 +37,7 @@
 
 import java.io.PrintWriter;
 
-final class DisplayWhiteBalanceTintController extends TintController {
+final class DisplayWhiteBalanceTintController extends ColorTemperatureTintController {
 
     // Three chromaticity coordinates per color: X, Y, and Z
     private static final int NUM_VALUES_PER_PRIMARY = 3;
@@ -52,9 +53,11 @@
     private int mTemperatureDefault;
     @VisibleForTesting
     float[] mDisplayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
+    private int mDisplayNominalWhiteCct;
     @VisibleForTesting
     ColorSpace.Rgb mDisplayColorSpaceRGB;
     private float[] mChromaticAdaptationMatrix;
+    // The temperature currently represented in the matrix.
     @VisibleForTesting
     int mCurrentColorTemperature;
     private float[] mCurrentColorTemperatureXYZ;
@@ -65,6 +68,9 @@
     private Boolean mIsAvailable;
     // This feature becomes disallowed if the device is in an unsupported strong/light state.
     private boolean mIsAllowed = true;
+    private int mTargetCct;
+    private int mAppliedCct;
+    private CctEvaluator mCctEvaluator;
 
     private final DisplayManagerInternal mDisplayManagerInternal;
 
@@ -108,6 +114,9 @@
             displayNominalWhiteXYZ[i] = Float.parseFloat(nominalWhiteValues[i]);
         }
 
+        final int displayNominalWhiteCct = res.getInteger(
+                R.integer.config_displayWhiteBalanceDisplayNominalWhiteCct);
+
         final int colorTemperatureMin = res.getInteger(
                 R.integer.config_displayWhiteBalanceColorTemperatureMin);
         if (colorTemperatureMin <= 0) {
@@ -124,19 +133,28 @@
             return;
         }
 
-        final int colorTemperature = res.getInteger(
+        final int defaultTemperature = res.getInteger(
                 R.integer.config_displayWhiteBalanceColorTemperatureDefault);
 
         mTransitionDuration = res.getInteger(
                 R.integer.config_displayWhiteBalanceTransitionTime);
 
+        int[] cctRangeMinimums = res.getIntArray(
+                R.array.config_displayWhiteBalanceDisplayRangeMinimums);
+        int[] steps = res.getIntArray(R.array.config_displayWhiteBalanceDisplaySteps);
+
         synchronized (mLock) {
             mDisplayColorSpaceRGB = displayColorSpaceRGB;
             mDisplayNominalWhiteXYZ = displayNominalWhiteXYZ;
+            mDisplayNominalWhiteCct = displayNominalWhiteCct;
+            mTargetCct = mDisplayNominalWhiteCct;
+            mAppliedCct = mDisplayNominalWhiteCct;
             mTemperatureMin = colorTemperatureMin;
             mTemperatureMax = colorTemperatureMax;
-            mTemperatureDefault = colorTemperature;
+            mTemperatureDefault = defaultTemperature;
             mSetUp = true;
+            mCctEvaluator = new CctEvaluator(mTemperatureMin, mTemperatureMax,
+                    cctRangeMinimums, steps);
         }
 
         setMatrix(mTemperatureDefault);
@@ -144,8 +162,16 @@
 
     @Override
     public float[] getMatrix() {
-        return mSetUp && isActivated() ? mMatrixDisplayWhiteBalance
-                : ColorDisplayService.MATRIX_IDENTITY;
+        if (!mSetUp || !isActivated()) {
+            return ColorDisplayService.MATRIX_IDENTITY;
+        }
+        computeMatrixForCct(mAppliedCct);
+        return mMatrixDisplayWhiteBalance;
+    }
+
+    @Override
+    public int getTargetCct() {
+        return mTargetCct;
     }
 
     /**
@@ -174,6 +200,12 @@
 
     @Override
     public void setMatrix(int cct) {
+        setTargetCct(cct);
+        computeMatrixForCct(mTargetCct);
+    }
+
+    @Override
+    public void setTargetCct(int cct) {
         if (!mSetUp) {
             Slog.w(ColorDisplayService.TAG,
                     "Can't set display white balance temperature: uninitialized");
@@ -183,50 +215,93 @@
         if (cct < mTemperatureMin) {
             Slog.w(ColorDisplayService.TAG,
                     "Requested display color temperature is below allowed minimum");
-            cct = mTemperatureMin;
+            mTargetCct = mTemperatureMin;
         } else if (cct > mTemperatureMax) {
             Slog.w(ColorDisplayService.TAG,
                     "Requested display color temperature is above allowed maximum");
-            cct = mTemperatureMax;
+            mTargetCct = mTemperatureMax;
+        } else {
+            mTargetCct = cct;
+        }
+    }
+
+    @Override
+    public int getDisabledCct() {
+        return mDisplayNominalWhiteCct;
+    }
+
+    @Override
+    public float[] computeMatrixForCct(int cct) {
+        if (!mSetUp || cct == 0) {
+            Slog.w(ColorDisplayService.TAG, "Couldn't compute matrix for cct=" + cct);
+            return ColorDisplayService.MATRIX_IDENTITY;
         }
 
         synchronized (mLock) {
             mCurrentColorTemperature = cct;
 
-            // Adapt the display's nominal white point to match the requested CCT value
-            mCurrentColorTemperatureXYZ = ColorSpace.cctToXyz(cct);
-
-            mChromaticAdaptationMatrix =
-                    ColorSpace.chromaticAdaptation(ColorSpace.Adaptation.BRADFORD,
-                            mDisplayNominalWhiteXYZ, mCurrentColorTemperatureXYZ);
-
-            // Convert the adaptation matrix to RGB space
-            float[] result = mul3x3(mChromaticAdaptationMatrix,
-                    mDisplayColorSpaceRGB.getTransform());
-            result = mul3x3(mDisplayColorSpaceRGB.getInverseTransform(), result);
-
-            // Normalize the transform matrix to peak white value in RGB space
-            final float adaptedMaxR = result[0] + result[3] + result[6];
-            final float adaptedMaxG = result[1] + result[4] + result[7];
-            final float adaptedMaxB = result[2] + result[5] + result[8];
-            final float denum = Math.max(Math.max(adaptedMaxR, adaptedMaxG), adaptedMaxB);
-
-            Matrix.setIdentityM(mMatrixDisplayWhiteBalance, 0);
-            for (int i = 0; i < result.length; i++) {
-                result[i] /= denum;
-                if (!isColorMatrixCoeffValid(result[i])) {
-                    Slog.e(ColorDisplayService.TAG, "Invalid DWB color matrix");
-                    return;
-                }
+            if (cct == mDisplayNominalWhiteCct && !isActivated()) {
+                // DWB is finished turning off. Clear the matrix.
+                Matrix.setIdentityM(mMatrixDisplayWhiteBalance, 0);
+            } else {
+                computeMatrixForCctLocked(cct);
             }
 
-            java.lang.System.arraycopy(result, 0, mMatrixDisplayWhiteBalance, 0, 3);
-            java.lang.System.arraycopy(result, 3, mMatrixDisplayWhiteBalance, 4, 3);
-            java.lang.System.arraycopy(result, 6, mMatrixDisplayWhiteBalance, 8, 3);
+            Slog.d(ColorDisplayService.TAG, "computeDisplayWhiteBalanceMatrix: cct =" + cct
+                    + " matrix =" + matrixToString(mMatrixDisplayWhiteBalance, 16));
+
+            return mMatrixDisplayWhiteBalance;
+        }
+    }
+
+    private void computeMatrixForCctLocked(int cct) {
+        // Adapt the display's nominal white point to match the requested CCT value
+        mCurrentColorTemperatureXYZ = ColorSpace.cctToXyz(cct);
+
+        mChromaticAdaptationMatrix =
+                ColorSpace.chromaticAdaptation(ColorSpace.Adaptation.BRADFORD,
+                        mDisplayNominalWhiteXYZ, mCurrentColorTemperatureXYZ);
+
+        // Convert the adaptation matrix to RGB space
+        float[] result = mul3x3(mChromaticAdaptationMatrix,
+                mDisplayColorSpaceRGB.getTransform());
+        result = mul3x3(mDisplayColorSpaceRGB.getInverseTransform(), result);
+
+        // Normalize the transform matrix to peak white value in RGB space
+        final float adaptedMaxR = result[0] + result[3] + result[6];
+        final float adaptedMaxG = result[1] + result[4] + result[7];
+        final float adaptedMaxB = result[2] + result[5] + result[8];
+        final float denum = Math.max(Math.max(adaptedMaxR, adaptedMaxG), adaptedMaxB);
+
+        Matrix.setIdentityM(mMatrixDisplayWhiteBalance, 0);
+
+        for (int i = 0; i < result.length; i++) {
+            result[i] /= denum;
+            if (!isColorMatrixCoeffValid(result[i])) {
+                Slog.e(ColorDisplayService.TAG, "Invalid DWB color matrix");
+                return;
+            }
         }
 
-        Slog.d(ColorDisplayService.TAG, "setDisplayWhiteBalanceTemperatureMatrix: cct = " + cct
-                + " matrix = " + matrixToString(mMatrixDisplayWhiteBalance, 16));
+        java.lang.System.arraycopy(result, 0, mMatrixDisplayWhiteBalance, 0, 3);
+        java.lang.System.arraycopy(result, 3, mMatrixDisplayWhiteBalance, 4, 3);
+        java.lang.System.arraycopy(result, 6, mMatrixDisplayWhiteBalance, 8, 3);
+    }
+
+    @Override
+    int getAppliedCct() {
+        return mAppliedCct;
+    }
+
+    @Override
+    void setAppliedCct(int cct) {
+        mAppliedCct = cct;
+    }
+
+    @Override
+    @Nullable
+    CctEvaluator getEvaluator() {
+        return mCctEvaluator;
     }
 
     @Override
@@ -258,7 +333,10 @@
             pw.println("    mTemperatureMin = " + mTemperatureMin);
             pw.println("    mTemperatureMax = " + mTemperatureMax);
             pw.println("    mTemperatureDefault = " + mTemperatureDefault);
+            pw.println("    mDisplayNominalWhiteCct = " + mDisplayNominalWhiteCct);
             pw.println("    mCurrentColorTemperature = " + mCurrentColorTemperature);
+            pw.println("    mTargetCct = " + mTargetCct);
+            pw.println("    mAppliedCct = " + mAppliedCct);
             pw.println("    mCurrentColorTemperatureXYZ = "
                     + matrixToString(mCurrentColorTemperatureXYZ, 3));
             pw.println("    mDisplayColorSpaceRGB RGB-to-XYZ = "
@@ -340,11 +418,7 @@
     }
 
     private boolean isColorMatrixCoeffValid(float coeff) {
-        if (Float.isNaN(coeff) || Float.isInfinite(coeff)) {
-            return false;
-        }
-
-        return true;
+        return !Float.isNaN(coeff) && !Float.isInfinite(coeff);
     }
 
     private boolean isColorMatrixValid(float[] matrix) {
@@ -352,8 +426,8 @@
             return false;
         }
 
-        for (int i = 0; i < matrix.length; i++) {
-            if (!isColorMatrixCoeffValid(matrix[i])) {
+        for (float value : matrix) {
+            if (!isColorMatrixCoeffValid(value)) {
                 return false;
             }
         }
diff --git a/services/core/java/com/android/server/display/color/TintController.java b/services/core/java/com/android/server/display/color/TintController.java
index c53ac06..384333a 100644
--- a/services/core/java/com/android/server/display/color/TintController.java
+++ b/services/core/java/com/android/server/display/color/TintController.java
@@ -16,6 +16,7 @@
 
 package com.android.server.display.color;
 
+import android.animation.ValueAnimator;
 import android.content.Context;
 import android.util.Slog;
 
@@ -28,14 +29,14 @@
      */
     private static final long TRANSITION_DURATION = 3000L;
 
-    private ColorDisplayService.TintValueAnimator mAnimator;
+    private ValueAnimator mAnimator;
     private Boolean mIsActivated;
 
-    public ColorDisplayService.TintValueAnimator getAnimator() {
+    public ValueAnimator getAnimator() {
         return mAnimator;
     }
 
-    public void setAnimator(ColorDisplayService.TintValueAnimator animator) {
+    public void setAnimator(ValueAnimator animator) {
         mAnimator = animator;
     }
 
diff --git a/services/core/java/com/android/server/input/KeyboardLayoutManager.java b/services/core/java/com/android/server/input/KeyboardLayoutManager.java
index d8716b3..6ec4022 100644
--- a/services/core/java/com/android/server/input/KeyboardLayoutManager.java
+++ b/services/core/java/com/android/server/input/KeyboardLayoutManager.java
@@ -562,7 +562,7 @@
                 key.append(",languageTag:").append(inputDevice.getKeyboardLanguageTag());
             }
             if (!TextUtils.isEmpty(inputDevice.getKeyboardLayoutType())) {
-                key.append(",layoutType:").append(inputDevice.getKeyboardLanguageTag());
+                key.append(",layoutType:").append(inputDevice.getKeyboardLayoutType());
             }
         }
         return key.toString();
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 464a256..02b7053 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -16,6 +16,12 @@
 
 package com.android.server.media;
 
+import static android.media.VolumeProvider.VOLUME_CONTROL_ABSOLUTE;
+import static android.media.VolumeProvider.VOLUME_CONTROL_FIXED;
+import static android.media.VolumeProvider.VOLUME_CONTROL_RELATIVE;
+import static android.media.session.MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL;
+import static android.media.session.MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE;
+
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -173,8 +179,8 @@
     // Volume handling fields
     private AudioAttributes mAudioAttrs;
     private AudioManager mAudioManager;
-    private int mVolumeType = PlaybackInfo.PLAYBACK_TYPE_LOCAL;
-    private int mVolumeControlType = VolumeProvider.VOLUME_CONTROL_ABSOLUTE;
+    private int mVolumeType = PLAYBACK_TYPE_LOCAL;
+    private int mVolumeControlType = VOLUME_CONTROL_ABSOLUTE;
     private int mMaxVolume = 0;
     private int mCurrentVolume = 0;
     private int mOptimisticVolume = -1;
@@ -309,13 +315,13 @@
         if (checkPlaybackActiveState(true) || isSystemPriority()) {
             flags &= ~AudioManager.FLAG_PLAY_SOUND;
         }
-        if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL) {
+        if (mVolumeType == PLAYBACK_TYPE_LOCAL) {
             // Adjust the volume with a handler not to be blocked by other system service.
             int stream = getVolumeStream(mAudioAttrs);
             postAdjustLocalVolume(stream, direction, flags, opPackageName, pid, uid,
                     asSystemService, useSuggested, previousFlagPlaySound);
         } else {
-            if (mVolumeControlType == VolumeProvider.VOLUME_CONTROL_FIXED) {
+            if (mVolumeControlType == VOLUME_CONTROL_FIXED) {
                 if (DEBUG) {
                     Log.d(TAG, "Session does not support volume adjustment");
                 }
@@ -354,7 +360,7 @@
 
     private void setVolumeTo(String packageName, String opPackageName, int pid, int uid, int value,
             int flags) {
-        if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL) {
+        if (mVolumeType == PLAYBACK_TYPE_LOCAL) {
             int stream = getVolumeStream(mAudioAttrs);
             final int volumeValue = value;
             mHandler.post(new Runnable() {
@@ -371,7 +377,7 @@
                 }
             });
         } else {
-            if (mVolumeControlType != VolumeProvider.VOLUME_CONTROL_ABSOLUTE) {
+            if (mVolumeControlType != VOLUME_CONTROL_ABSOLUTE) {
                 if (DEBUG) {
                     Log.d(TAG, "Session does not support setting volume");
                 }
@@ -433,7 +439,7 @@
      */
     @Override
     public boolean isPlaybackTypeLocal() {
-        return mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL;
+        return mVolumeType == PLAYBACK_TYPE_LOCAL;
     }
 
     @Override
@@ -495,7 +501,7 @@
 
     @Override
     public boolean canHandleVolumeKey() {
-        return mVolumeControlType != VolumeProvider.VOLUME_CONTROL_FIXED;
+        return mVolumeControlType != VOLUME_CONTROL_FIXED;
     }
 
     @Override
@@ -528,13 +534,48 @@
         pw.println(indent + "controllers: " + mControllerCallbackHolders.size());
         pw.println(indent + "state=" + (mPlaybackState == null ? null : mPlaybackState.toString()));
         pw.println(indent + "audioAttrs=" + mAudioAttrs);
-        pw.println(indent + "volumeType=" + mVolumeType + ", controlType=" + mVolumeControlType
-                + ", max=" + mMaxVolume + ", current=" + mCurrentVolume);
+        pw.append(indent)
+                .append("volumeType=")
+                .append(toVolumeTypeString(mVolumeType))
+                .append(", controlType=")
+                .append(toVolumeControlTypeString(mVolumeControlType))
+                .append(", max=")
+                .append(Integer.toString(mMaxVolume))
+                .append(", current=")
+                .append(Integer.toString(mCurrentVolume))
+                .append(", volumeControlId=")
+                .append(mVolumeControlId)
+                .println();
         pw.println(indent + "metadata: " + mMetadataDescription);
         pw.println(indent + "queueTitle=" + mQueueTitle + ", size="
                 + (mQueue == null ? 0 : mQueue.size()));
     }
 
+    private static String toVolumeControlTypeString(
+            @VolumeProvider.ControlType int volumeControlType) {
+        switch (volumeControlType) {
+            case VOLUME_CONTROL_FIXED:
+                return "FIXED";
+            case VOLUME_CONTROL_RELATIVE:
+                return "RELATIVE";
+            case VOLUME_CONTROL_ABSOLUTE:
+                return "ABSOLUTE";
+            default:
+                return TextUtils.formatSimple("unknown(%d)", volumeControlType);
+        }
+    }
+
+    private static String toVolumeTypeString(@PlaybackInfo.PlaybackType int volumeType) {
+        switch (volumeType) {
+            case PLAYBACK_TYPE_LOCAL:
+                return "LOCAL";
+            case PLAYBACK_TYPE_REMOTE:
+                return "REMOTE";
+            default:
+                return TextUtils.formatSimple("unknown(%d)", volumeType);
+        }
+    }
+
     @Override
     public String toString() {
         return mPackageName + "/" + mTag + " (userId=" + mUserId + ")";
@@ -877,8 +918,8 @@
         int stream = getVolumeStream(attributes);
         int max = mAudioManager.getStreamMaxVolume(stream);
         int current = mAudioManager.getStreamVolume(stream);
-        return new PlaybackInfo(volumeType, VolumeProvider.VOLUME_CONTROL_ABSOLUTE, max,
-                current, attributes, null);
+        return new PlaybackInfo(
+                volumeType, VOLUME_CONTROL_ABSOLUTE, max, current, attributes, null);
     }
 
     private final Runnable mClearOptimisticVolumeRunnable = new Runnable() {
@@ -1124,7 +1165,7 @@
             boolean typeChanged;
             synchronized (mLock) {
                 typeChanged = mVolumeType == PlaybackInfo.PLAYBACK_TYPE_REMOTE;
-                mVolumeType = PlaybackInfo.PLAYBACK_TYPE_LOCAL;
+                mVolumeType = PLAYBACK_TYPE_LOCAL;
                 mVolumeControlId = null;
                 if (attributes != null) {
                     mAudioAttrs = attributes;
@@ -1148,7 +1189,7 @@
                 throws RemoteException {
             boolean typeChanged;
             synchronized (mLock) {
-                typeChanged = mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL;
+                typeChanged = mVolumeType == PLAYBACK_TYPE_LOCAL;
                 mVolumeType = PlaybackInfo.PLAYBACK_TYPE_REMOTE;
                 mVolumeControlType = control;
                 mMaxVolume = max;
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index a267e8a..5932929 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -4360,12 +4360,22 @@
 
         // A new application appeared on /system, and we are seeing it for the first time.
         // Its also not updated as we don't have a copy of it on /data. So, scan it in a
-        // STOPPED state. Ignore if it's an APEX package since stopped state does not affect them.
+        // STOPPED state.
+        // We'll skip this step under the following conditions:
+        //   - It's "android"
+        //   - It's an APEX or overlay package since stopped state does not affect them.
+        //   - It is enumerated with a <initial-package-state> tag having the stopped attribute
+        //     set to false
         final boolean isApexPkg = (scanFlags & SCAN_AS_APEX) != 0;
-        if (mPm.mShouldStopSystemPackagesByDefault && scanSystemPartition
-                && !pkgAlreadyExists && !isApexPkg) {
+        if (mPm.mShouldStopSystemPackagesByDefault
+                && scanSystemPartition
+                && !pkgAlreadyExists
+                && !isApexPkg
+                && !parsedPackage.isOverlayIsStatic()
+        ) {
             String packageName = parsedPackage.getPackageName();
-            if (!mPm.mInitialNonStoppedSystemPackages.contains(packageName)) {
+            if (!mPm.mInitialNonStoppedSystemPackages.contains(packageName)
+                    && !"android".contentEquals(packageName)) {
                 scanFlags |= SCAN_AS_STOPPED_SYSTEM_APP;
             }
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index b5108af..f482046 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -5258,6 +5258,12 @@
         }
 
         @Override
+        public @NonNull List<String> getInitialNonStoppedSystemPackages() {
+            return mInitialNonStoppedSystemPackages != null
+                    ? new ArrayList<>(mInitialNonStoppedSystemPackages) : new ArrayList<>();
+        }
+
+        @Override
         public String[] getUnsuspendablePackagesForUser(String[] packageNames, int userId) {
             Objects.requireNonNull(packageNames, "packageNames cannot be null");
             mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS,
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index f78b611..58183f0 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -782,6 +782,8 @@
                         getInFileDescriptor(), getOutFileDescriptor(), getErrFileDescriptor(),
                         new String[] { "list" }, getShellCallback(), adoptResultReceiver());
                 return 0;
+            case "initial-non-stopped-system-packages":
+                return runListInitialNonStoppedSystemPackages();
         }
         pw.println("Error: unknown list type '" + type + "'");
         return -1;
@@ -794,6 +796,21 @@
         return 0;
     }
 
+    private int runListInitialNonStoppedSystemPackages() throws RemoteException {
+        final PrintWriter pw = getOutPrintWriter();
+        final List<String> list = mInterface.getInitialNonStoppedSystemPackages();
+
+        Collections.sort(list);
+
+        for (String pkgName : list) {
+            pw.print("package:");
+            pw.print(pkgName);
+            pw.println();
+        }
+
+        return 0;
+    }
+
     private int runListFeatures() throws RemoteException {
         final PrintWriter pw = getOutPrintWriter();
         final List<FeatureInfo> list = mInterface.getSystemAvailableFeatures().getList();
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 9ff98be..f8954b7 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -5690,8 +5690,14 @@
             }
 
             if (eventTime > now) {
-                Slog.e(TAG, "Event time " + eventTime + " cannot be newer than " + now);
-                throw new IllegalArgumentException("event time must not be in the future");
+                Slog.wtf(TAG, "Event cannot be newer than the current time ("
+                        + "now=" + now
+                        + ", eventTime=" + eventTime
+                        + ", displayId=" + displayId
+                        + ", event=" + PowerManager.userActivityEventToString(event)
+                        + ", flags=" + flags
+                        + ")");
+                return;
             }
 
             final int uid = Binder.getCallingUid();
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index f86df2a..b816dad 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -6336,6 +6336,8 @@
         public void cleanupDisabledPackageComponents(
                 String packageName, Set<String> disabledClasses, int userId, boolean booted) {
             synchronized (mGlobalLock) {
+                // In case if setWindowManager hasn't been called yet when booting.
+                if (mRootWindowContainer == null) return;
                 // Clean-up disabled activities.
                 if (mRootWindowContainer.finishDisabledPackageActivities(
                         packageName, disabledClasses, true /* doit */, false /* evenPersistent */,
diff --git a/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java b/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
index 2edb082..7852249 100644
--- a/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
+++ b/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
@@ -20,41 +20,73 @@
 
 import static com.android.internal.R.bool.config_unfoldTransitionEnabled;
 import static com.android.server.wm.ActivityTaskManagerService.POWER_MODE_REASON_CHANGE_DISPLAY;
+import static com.android.server.wm.DeviceStateController.DeviceState.FOLDED;
+import static com.android.server.wm.DeviceStateController.DeviceState.HALF_FOLDED;
+import static com.android.server.wm.DeviceStateController.DeviceState.OPEN;
 
 import android.animation.ValueAnimator;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.Context;
 import android.graphics.Rect;
 import android.window.DisplayAreaInfo;
 import android.window.TransitionRequestInfo;
 import android.window.WindowContainerTransaction;
 
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.wm.DeviceStateController.DeviceState;
+
 public class PhysicalDisplaySwitchTransitionLauncher {
 
     private final DisplayContent mDisplayContent;
-    private final WindowManagerService mService;
+    private final ActivityTaskManagerService mAtmService;
+    private final Context mContext;
     private final TransitionController mTransitionController;
 
     /**
-     * If on a foldable device represents whether the device is folded or not
+     * If on a foldable device represents whether we need to show unfold animation when receiving
+     * a physical display switch event
      */
-    private boolean mIsFolded;
+    private boolean mShouldRequestTransitionOnDisplaySwitch = false;
+    /**
+     * Current device state from {@link android.hardware.devicestate.DeviceStateManager}
+     */
+    private DeviceState mDeviceState = DeviceState.UNKNOWN;
     private Transition mTransition;
 
     public PhysicalDisplaySwitchTransitionLauncher(DisplayContent displayContent,
             TransitionController transitionController) {
+        this(displayContent, displayContent.mWmService.mAtmService,
+                displayContent.mWmService.mContext, transitionController);
+    }
+
+    @VisibleForTesting
+    public PhysicalDisplaySwitchTransitionLauncher(DisplayContent displayContent,
+            ActivityTaskManagerService service, Context context,
+            TransitionController transitionController) {
         mDisplayContent = displayContent;
-        mService = displayContent.mWmService;
+        mAtmService = service;
+        mContext = context;
         mTransitionController = transitionController;
     }
 
     /**
      *   Called by the DeviceStateManager callback when the state changes.
      */
-    void foldStateChanged(DeviceStateController.DeviceState newDeviceState) {
-        // Ignore transitions to/from half-folded.
-        if (newDeviceState == DeviceStateController.DeviceState.HALF_FOLDED) return;
-        mIsFolded = newDeviceState == DeviceStateController.DeviceState.FOLDED;
+    void foldStateChanged(DeviceState newDeviceState) {
+        boolean isUnfolding = mDeviceState == FOLDED
+                && (newDeviceState == HALF_FOLDED || newDeviceState == OPEN);
+
+        if (isUnfolding) {
+            // Request transition only if we are unfolding the device
+            mShouldRequestTransitionOnDisplaySwitch = true;
+        } else if (newDeviceState != HALF_FOLDED && newDeviceState != OPEN) {
+            // Cancel the transition request in case if we are folding or switching to back
+            // to the rear display before the displays got switched
+            mShouldRequestTransitionOnDisplaySwitch = false;
+        }
+
+        mDeviceState = newDeviceState;
     }
 
     /**
@@ -62,12 +94,12 @@
      */
     public void requestDisplaySwitchTransitionIfNeeded(int displayId, int oldDisplayWidth,
             int oldDisplayHeight, int newDisplayWidth, int newDisplayHeight) {
+        if (!mShouldRequestTransitionOnDisplaySwitch) return;
         if (!mTransitionController.isShellTransitionsEnabled()) return;
         if (!mDisplayContent.getLastHasContent()) return;
 
-        boolean shouldRequestUnfoldTransition = !mIsFolded
-                && mService.mContext.getResources().getBoolean(config_unfoldTransitionEnabled)
-                && ValueAnimator.areAnimatorsEnabled();
+        boolean shouldRequestUnfoldTransition = mContext.getResources()
+                .getBoolean(config_unfoldTransitionEnabled) && ValueAnimator.areAnimatorsEnabled();
 
         if (!shouldRequestUnfoldTransition) {
             return;
@@ -91,6 +123,8 @@
             mDisplayContent.mAtmService.startLaunchPowerMode(POWER_MODE_REASON_CHANGE_DISPLAY);
             mTransition = t;
         }
+
+        mShouldRequestTransitionOnDisplaySwitch = false;
     }
 
     /**
@@ -118,7 +152,7 @@
         if (mTransition == null) return;
 
         if (transaction != null) {
-            mService.mAtmService.mWindowOrganizerController.applyTransaction(transaction);
+            mAtmService.mWindowOrganizerController.applyTransaction(transaction);
         }
 
         markTransitionAsReady();
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index a1e497e..50bf38b 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -2267,7 +2267,7 @@
                         // Display won't be rotated for multi window Task, so the fixed rotation
                         // won't be applied. This can happen when the windowing mode is changed
                         // before the previous fixed rotation is applied.
-                        && !task.inMultiWindowMode()) {
+                        && (!task.inMultiWindowMode() || !topRunningActivity.inMultiWindowMode())) {
                     // If Activity is in fixed rotation, its will be applied with the next rotation,
                     // when the Task is still in the previous rotation.
                     final int taskRotation = task.getWindowConfiguration().getDisplayRotation();
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index f9b6fc1..40c6c46 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3915,8 +3915,9 @@
         synchronized (mGlobalLock) {
             final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent == null) {
-                throw new IllegalStateException("No touch mode is defined for displayId {"
-                        + displayId + "}");
+                throw new IllegalStateException("Failed to retrieve the touch mode state for"
+                        + "display {" + displayId + "}: display is not registered in "
+                        + "WindowRootContainer");
             }
             return displayContent.isInTouchMode();
         }
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 369c974..f0d718a 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -342,15 +342,15 @@
     void notifySensorAccuracy(int32_t deviceId, InputDeviceSensorType sensorType,
                               InputDeviceSensorAccuracy accuracy) override;
     void notifyVibratorState(int32_t deviceId, bool isOn) override;
-    bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) override;
-    void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) override;
-    void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) override;
-    void interceptMotionBeforeQueueing(const int32_t displayId, nsecs_t when,
+    bool filterInputEvent(const InputEvent& inputEvent, uint32_t policyFlags) override;
+    InputDispatcherConfiguration getDispatcherConfiguration() override;
+    void interceptKeyBeforeQueueing(const KeyEvent& keyEvent, uint32_t& policyFlags) override;
+    void interceptMotionBeforeQueueing(int32_t displayId, nsecs_t when,
                                        uint32_t& policyFlags) override;
-    nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>& token, const KeyEvent* keyEvent,
+    nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>& token, const KeyEvent& keyEvent,
                                           uint32_t policyFlags) override;
-    bool dispatchUnhandledKey(const sp<IBinder>& token, const KeyEvent* keyEvent,
-                              uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) override;
+    std::optional<KeyEvent> dispatchUnhandledKey(const sp<IBinder>& token, const KeyEvent& keyEvent,
+                                                 uint32_t policyFlags) override;
     void pokeUserActivity(nsecs_t eventTime, int32_t eventType, int32_t displayId) override;
     void onPointerDownOutsideFocus(const sp<IBinder>& touchedToken) override;
     void setPointerCapture(const PointerCaptureRequest& request) override;
@@ -450,7 +450,7 @@
 
     mServiceObj = env->NewGlobalRef(serviceObj);
 
-    InputManager* im = new InputManager(this, this);
+    InputManager* im = new InputManager(this, *this);
     mInputManager = im;
     defaultServiceManager()->addService(String16("inputflinger"), im);
 }
@@ -1007,21 +1007,22 @@
     checkAndClearExceptionFromCallback(env, "notifyVibratorState");
 }
 
-void NativeInputManager::getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) {
+InputDispatcherConfiguration NativeInputManager::getDispatcherConfiguration() {
     ATRACE_CALL();
+    InputDispatcherConfiguration config;
     JNIEnv* env = jniEnv();
 
-    jint keyRepeatTimeout = env->CallIntMethod(mServiceObj,
-            gServiceClassInfo.getKeyRepeatTimeout);
+    jint keyRepeatTimeout = env->CallIntMethod(mServiceObj, gServiceClassInfo.getKeyRepeatTimeout);
     if (!checkAndClearExceptionFromCallback(env, "getKeyRepeatTimeout")) {
-        outConfig->keyRepeatTimeout = milliseconds_to_nanoseconds(keyRepeatTimeout);
+        config.keyRepeatTimeout = milliseconds_to_nanoseconds(keyRepeatTimeout);
     }
 
-    jint keyRepeatDelay = env->CallIntMethod(mServiceObj,
-            gServiceClassInfo.getKeyRepeatDelay);
+    jint keyRepeatDelay = env->CallIntMethod(mServiceObj, gServiceClassInfo.getKeyRepeatDelay);
     if (!checkAndClearExceptionFromCallback(env, "getKeyRepeatDelay")) {
-        outConfig->keyRepeatDelay = milliseconds_to_nanoseconds(keyRepeatDelay);
+        config.keyRepeatDelay = milliseconds_to_nanoseconds(keyRepeatDelay);
     }
+
+    return config;
 }
 
 void NativeInputManager::displayRemoved(JNIEnv* env, int32_t displayId) {
@@ -1294,110 +1295,112 @@
     checkAndClearExceptionFromCallback(env, "notifyStylusGestureStarted");
 }
 
-bool NativeInputManager::filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) {
+bool NativeInputManager::filterInputEvent(const InputEvent& inputEvent, uint32_t policyFlags) {
     ATRACE_CALL();
-    jobject inputEventObj;
-
     JNIEnv* env = jniEnv();
-    switch (inputEvent->getType()) {
+
+    ScopedLocalRef<jobject> inputEventObj(env);
+    switch (inputEvent.getType()) {
         case InputEventType::KEY:
-            inputEventObj =
-                    android_view_KeyEvent_fromNative(env, static_cast<const KeyEvent*>(inputEvent));
+            inputEventObj.reset(
+                    android_view_KeyEvent_fromNative(env,
+                                                     static_cast<const KeyEvent&>(inputEvent)));
             break;
         case InputEventType::MOTION:
-            inputEventObj = android_view_MotionEvent_obtainAsCopy(env,
-                                                                  static_cast<const MotionEvent&>(
-                                                                          *inputEvent));
+            inputEventObj.reset(
+                    android_view_MotionEvent_obtainAsCopy(env,
+                                                          static_cast<const MotionEvent&>(
+                                                                  inputEvent)));
             break;
         default:
             return true; // dispatch the event normally
     }
 
-    if (!inputEventObj) {
+    if (!inputEventObj.get()) {
         ALOGE("Failed to obtain input event object for filterInputEvent.");
         return true; // dispatch the event normally
     }
 
     // The callee is responsible for recycling the event.
-    jboolean pass = env->CallBooleanMethod(mServiceObj, gServiceClassInfo.filterInputEvent,
-            inputEventObj, policyFlags);
+    const jboolean continueEventDispatch =
+            env->CallBooleanMethod(mServiceObj, gServiceClassInfo.filterInputEvent,
+                                   inputEventObj.get(), policyFlags);
     if (checkAndClearExceptionFromCallback(env, "filterInputEvent")) {
-        pass = true;
+        return true; // dispatch the event normally
     }
-    env->DeleteLocalRef(inputEventObj);
-    return pass;
+    return continueEventDispatch;
 }
 
-void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent,
-        uint32_t& policyFlags) {
+void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent& keyEvent,
+                                                    uint32_t& policyFlags) {
     ATRACE_CALL();
     // Policy:
     // - Ignore untrusted events and pass them along.
     // - Ask the window manager what to do with normal events and trusted injected events.
     // - For normal events wake and brighten the screen if currently off or dim.
-    bool interactive = mInteractive.load();
+    const bool interactive = mInteractive.load();
     if (interactive) {
         policyFlags |= POLICY_FLAG_INTERACTIVE;
     }
-    if ((policyFlags & POLICY_FLAG_TRUSTED)) {
-        nsecs_t when = keyEvent->getEventTime();
-        JNIEnv* env = jniEnv();
-        jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
-        jint wmActions;
-        if (keyEventObj) {
-            wmActions = env->CallIntMethod(mServiceObj,
-                    gServiceClassInfo.interceptKeyBeforeQueueing,
-                    keyEventObj, policyFlags);
-            if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
-                wmActions = 0;
-            }
-            android_view_KeyEvent_recycle(env, keyEventObj);
-            env->DeleteLocalRef(keyEventObj);
-        } else {
-            ALOGE("Failed to obtain key event object for interceptKeyBeforeQueueing.");
-            wmActions = 0;
-        }
 
-        handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
-    } else {
+    if ((policyFlags & POLICY_FLAG_TRUSTED) == 0) {
         if (interactive) {
             policyFlags |= POLICY_FLAG_PASS_TO_USER;
         }
+        return;
     }
+
+    const nsecs_t when = keyEvent.getEventTime();
+    JNIEnv* env = jniEnv();
+    ScopedLocalRef<jobject> keyEventObj(env, android_view_KeyEvent_fromNative(env, keyEvent));
+    if (!keyEventObj.get()) {
+        ALOGE("Failed to obtain key event object for interceptKeyBeforeQueueing.");
+        return;
+    }
+
+    jint wmActions = env->CallIntMethod(mServiceObj, gServiceClassInfo.interceptKeyBeforeQueueing,
+                                        keyEventObj.get(), policyFlags);
+    if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
+        wmActions = 0;
+    }
+    android_view_KeyEvent_recycle(env, keyEventObj.get());
+    handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
 }
 
-void NativeInputManager::interceptMotionBeforeQueueing(const int32_t displayId, nsecs_t when,
-        uint32_t& policyFlags) {
+void NativeInputManager::interceptMotionBeforeQueueing(int32_t displayId, nsecs_t when,
+                                                       uint32_t& policyFlags) {
     ATRACE_CALL();
     // Policy:
     // - Ignore untrusted events and pass them along.
     // - No special filtering for injected events required at this time.
     // - Filter normal events based on screen state.
     // - For normal events brighten (but do not wake) the screen if currently dim.
-    bool interactive = mInteractive.load();
+    const bool interactive = mInteractive.load();
     if (interactive) {
         policyFlags |= POLICY_FLAG_INTERACTIVE;
     }
-    if ((policyFlags & POLICY_FLAG_TRUSTED) && !(policyFlags & POLICY_FLAG_INJECTED)) {
-        if (policyFlags & POLICY_FLAG_INTERACTIVE) {
-            policyFlags |= POLICY_FLAG_PASS_TO_USER;
-        } else {
-            JNIEnv* env = jniEnv();
-            jint wmActions = env->CallIntMethod(mServiceObj,
-                        gServiceClassInfo.interceptMotionBeforeQueueingNonInteractive,
-                        displayId, when, policyFlags);
-            if (checkAndClearExceptionFromCallback(env,
-                    "interceptMotionBeforeQueueingNonInteractive")) {
-                wmActions = 0;
-            }
 
-            handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
-        }
-    } else {
+    if ((policyFlags & POLICY_FLAG_TRUSTED) == 0 || (policyFlags & POLICY_FLAG_INJECTED)) {
         if (interactive) {
             policyFlags |= POLICY_FLAG_PASS_TO_USER;
         }
+        return;
     }
+
+    if (policyFlags & POLICY_FLAG_INTERACTIVE) {
+        policyFlags |= POLICY_FLAG_PASS_TO_USER;
+        return;
+    }
+
+    JNIEnv* env = jniEnv();
+    const jint wmActions =
+            env->CallIntMethod(mServiceObj,
+                               gServiceClassInfo.interceptMotionBeforeQueueingNonInteractive,
+                               displayId, when, policyFlags);
+    if (checkAndClearExceptionFromCallback(env, "interceptMotionBeforeQueueingNonInteractive")) {
+        return;
+    }
+    handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
 }
 
 void NativeInputManager::handleInterceptActions(jint wmActions, nsecs_t when,
@@ -1411,81 +1414,76 @@
     }
 }
 
-nsecs_t NativeInputManager::interceptKeyBeforeDispatching(
-        const sp<IBinder>& token,
-        const KeyEvent* keyEvent, uint32_t policyFlags) {
+nsecs_t NativeInputManager::interceptKeyBeforeDispatching(const sp<IBinder>& token,
+                                                          const KeyEvent& keyEvent,
+                                                          uint32_t policyFlags) {
     ATRACE_CALL();
     // Policy:
     // - Ignore untrusted events and pass them along.
     // - Filter normal events and trusted injected events through the window manager policy to
     //   handle the HOME key and the like.
-    nsecs_t result = 0;
-    if (policyFlags & POLICY_FLAG_TRUSTED) {
-        JNIEnv* env = jniEnv();
-        ScopedLocalFrame localFrame(env);
-
-        // Token may be null
-        jobject tokenObj = javaObjectForIBinder(env, token);
-
-        jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
-        if (keyEventObj) {
-            jlong delayMillis = env->CallLongMethod(mServiceObj,
-                    gServiceClassInfo.interceptKeyBeforeDispatching,
-                    tokenObj, keyEventObj, policyFlags);
-            bool error = checkAndClearExceptionFromCallback(env, "interceptKeyBeforeDispatching");
-            android_view_KeyEvent_recycle(env, keyEventObj);
-            env->DeleteLocalRef(keyEventObj);
-            if (!error) {
-                if (delayMillis < 0) {
-                    result = -1;
-                } else if (delayMillis > 0) {
-                    result = milliseconds_to_nanoseconds(delayMillis);
-                }
-            }
-        } else {
-            ALOGE("Failed to obtain key event object for interceptKeyBeforeDispatching.");
-        }
+    if ((policyFlags & POLICY_FLAG_TRUSTED) == 0) {
+        return 0;
     }
-    return result;
+
+    JNIEnv* env = jniEnv();
+    ScopedLocalFrame localFrame(env);
+
+    // Token may be null
+    ScopedLocalRef<jobject> tokenObj(env, javaObjectForIBinder(env, token));
+    ScopedLocalRef<jobject> keyEventObj(env, android_view_KeyEvent_fromNative(env, keyEvent));
+    if (!keyEventObj.get()) {
+        ALOGE("Failed to obtain key event object for interceptKeyBeforeDispatching.");
+        return 0;
+    }
+
+    const jlong delayMillis =
+            env->CallLongMethod(mServiceObj, gServiceClassInfo.interceptKeyBeforeDispatching,
+                                tokenObj.get(), keyEventObj.get(), policyFlags);
+    android_view_KeyEvent_recycle(env, keyEventObj.get());
+    if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeDispatching")) {
+        return 0;
+    }
+    return delayMillis < 0 ? -1 : milliseconds_to_nanoseconds(delayMillis);
 }
 
-bool NativeInputManager::dispatchUnhandledKey(const sp<IBinder>& token,
-        const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) {
+std::optional<KeyEvent> NativeInputManager::dispatchUnhandledKey(const sp<IBinder>& token,
+                                                                 const KeyEvent& keyEvent,
+                                                                 uint32_t policyFlags) {
     ATRACE_CALL();
     // Policy:
     // - Ignore untrusted events and do not perform default handling.
-    bool result = false;
-    if (policyFlags & POLICY_FLAG_TRUSTED) {
-        JNIEnv* env = jniEnv();
-        ScopedLocalFrame localFrame(env);
-
-        // Note: tokenObj may be null.
-        jobject tokenObj = javaObjectForIBinder(env, token);
-        jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
-        if (keyEventObj) {
-            jobject fallbackKeyEventObj = env->CallObjectMethod(mServiceObj,
-                    gServiceClassInfo.dispatchUnhandledKey,
-                    tokenObj, keyEventObj, policyFlags);
-            if (checkAndClearExceptionFromCallback(env, "dispatchUnhandledKey")) {
-                fallbackKeyEventObj = nullptr;
-            }
-            android_view_KeyEvent_recycle(env, keyEventObj);
-            env->DeleteLocalRef(keyEventObj);
-
-            if (fallbackKeyEventObj) {
-                // Note: outFallbackKeyEvent may be the same object as keyEvent.
-                if (!android_view_KeyEvent_toNative(env, fallbackKeyEventObj,
-                        outFallbackKeyEvent)) {
-                    result = true;
-                }
-                android_view_KeyEvent_recycle(env, fallbackKeyEventObj);
-                env->DeleteLocalRef(fallbackKeyEventObj);
-            }
-        } else {
-            ALOGE("Failed to obtain key event object for dispatchUnhandledKey.");
-        }
+    if ((policyFlags & POLICY_FLAG_TRUSTED) == 0) {
+        return {};
     }
-    return result;
+
+    JNIEnv* env = jniEnv();
+    ScopedLocalFrame localFrame(env);
+
+    // Note: tokenObj may be null.
+    ScopedLocalRef<jobject> tokenObj(env, javaObjectForIBinder(env, token));
+    ScopedLocalRef<jobject> keyEventObj(env, android_view_KeyEvent_fromNative(env, keyEvent));
+    if (!keyEventObj.get()) {
+        ALOGE("Failed to obtain key event object for dispatchUnhandledKey.");
+        return {};
+    }
+
+    ScopedLocalRef<jobject>
+            fallbackKeyEventObj(env,
+                                env->CallObjectMethod(mServiceObj,
+                                                      gServiceClassInfo.dispatchUnhandledKey,
+                                                      tokenObj.get(), keyEventObj.get(),
+                                                      policyFlags));
+
+    android_view_KeyEvent_recycle(env, keyEventObj.get());
+    if (checkAndClearExceptionFromCallback(env, "dispatchUnhandledKey") ||
+        !fallbackKeyEventObj.get()) {
+        return {};
+    }
+
+    const KeyEvent fallbackEvent = android_view_KeyEvent_toNative(env, fallbackKeyEventObj.get());
+    android_view_KeyEvent_recycle(env, fallbackKeyEventObj.get());
+    return fallbackEvent;
 }
 
 void NativeInputManager::pokeUserActivity(nsecs_t eventTime, int32_t eventType, int32_t displayId) {
@@ -1876,13 +1874,7 @@
     InputEventInjectionSync mode = static_cast<InputEventInjectionSync>(syncMode);
 
     if (env->IsInstanceOf(inputEventObj, gKeyEventClassInfo.clazz)) {
-        KeyEvent keyEvent;
-        status_t status = android_view_KeyEvent_toNative(env, inputEventObj, & keyEvent);
-        if (status) {
-            jniThrowRuntimeException(env, "Could not read contents of KeyEvent object.");
-            return static_cast<jint>(InputEventInjectionResult::FAILED);
-        }
-
+        const KeyEvent keyEvent = android_view_KeyEvent_toNative(env, inputEventObj);
         const InputEventInjectionResult result =
                 im->getInputManager()->getDispatcher().injectInputEvent(&keyEvent, targetUid, mode,
                                                                         std::chrono::milliseconds(
@@ -1913,13 +1905,7 @@
     NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
 
     if (env->IsInstanceOf(inputEventObj, gKeyEventClassInfo.clazz)) {
-        KeyEvent keyEvent;
-        status_t status = android_view_KeyEvent_toNative(env, inputEventObj, &keyEvent);
-        if (status) {
-            jniThrowRuntimeException(env, "Could not read contents of KeyEvent object.");
-            return nullptr;
-        }
-
+        const KeyEvent keyEvent = android_view_KeyEvent_toNative(env, inputEventObj);
         std::unique_ptr<VerifiedInputEvent> verifiedEvent =
                 im->getInputManager()->getDispatcher().verifyInputEvent(keyEvent);
         if (verifiedEvent == nullptr) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java
index 941a3a4..3faf394 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/color/DisplayWhiteBalanceTintControllerTest.java
@@ -72,18 +72,28 @@
 
         mResources = InstrumentationRegistry.getContext().getResources();
         // These Resources are common to all tests.
-        doReturn(mResources.getInteger(R.integer.config_displayWhiteBalanceColorTemperatureMin))
+        doReturn(4000)
             .when(mMockedResources)
             .getInteger(R.integer.config_displayWhiteBalanceColorTemperatureMin);
-        doReturn(mResources.getInteger(R.integer.config_displayWhiteBalanceColorTemperatureMax))
+        doReturn(8000)
             .when(mMockedResources)
             .getInteger(R.integer.config_displayWhiteBalanceColorTemperatureMax);
-        doReturn(mResources.getInteger(R.integer.config_displayWhiteBalanceColorTemperatureDefault))
+        doReturn(6500)
             .when(mMockedResources)
             .getInteger(R.integer.config_displayWhiteBalanceColorTemperatureDefault);
-        doReturn(mResources.getStringArray(R.array.config_displayWhiteBalanceDisplayNominalWhite))
-            .when(mMockedResources)
-            .getStringArray(R.array.config_displayWhiteBalanceDisplayNominalWhite);
+        doReturn(new String[] {"0.950456", "1.000000", "1.089058"})
+                .when(mMockedResources)
+                .getStringArray(R.array.config_displayWhiteBalanceDisplayNominalWhite);
+        doReturn(6500)
+                .when(mMockedResources)
+                .getInteger(R.integer.config_displayWhiteBalanceDisplayNominalWhiteCct);
+        doReturn(new int[] {0})
+                .when(mMockedResources)
+                .getIntArray(R.array.config_displayWhiteBalanceDisplaySteps);
+        doReturn(new int[] {20})
+                .when(mMockedResources)
+                .getIntArray(R.array.config_displayWhiteBalanceDisplayRangeMinimums);
+
         doReturn(mMockedResources).when(mMockedContext).getResources();
 
         mDisplayToken = new Binder();
@@ -195,7 +205,7 @@
      * Matrix should match the precalculated one for given cct and display primaries.
      */
     @Test
-    public void displayWhiteBalance_validateTransformMatrix() {
+    public void displayWhiteBalance_getAndSetMatrix_validateTransformMatrix() {
         DisplayPrimaries displayPrimaries = new DisplayPrimaries();
         displayPrimaries.red = new CieXyz();
         displayPrimaries.red.X = 0.412315f;
@@ -223,10 +233,12 @@
 
         final int cct = 6500;
         mDisplayWhiteBalanceTintController.setMatrix(cct);
+        mDisplayWhiteBalanceTintController.setAppliedCct(
+                mDisplayWhiteBalanceTintController.getTargetCct());
+
         assertWithMessage("Failed to set temperature")
                 .that(mDisplayWhiteBalanceTintController.mCurrentColorTemperature)
                 .isEqualTo(cct);
-
         float[] matrixDwb = mDisplayWhiteBalanceTintController.getMatrix();
         final float[] expectedMatrixDwb = {
             0.971848f,   -0.001421f,  0.000491f, 0.0f,
@@ -238,6 +250,54 @@
             1e-6f /* tolerance */);
     }
 
+    /**
+     * Matrix should match the precalculated one for given cct and display primaries.
+     */
+    @Test
+    public void displayWhiteBalance_targetApplied_validateTransformMatrix() {
+        DisplayPrimaries displayPrimaries = new DisplayPrimaries();
+        displayPrimaries.red = new CieXyz();
+        displayPrimaries.red.X = 0.412315f;
+        displayPrimaries.red.Y = 0.212600f;
+        displayPrimaries.red.Z = 0.019327f;
+        displayPrimaries.green = new CieXyz();
+        displayPrimaries.green.X = 0.357600f;
+        displayPrimaries.green.Y = 0.715200f;
+        displayPrimaries.green.Z = 0.119200f;
+        displayPrimaries.blue = new CieXyz();
+        displayPrimaries.blue.X = 0.180500f;
+        displayPrimaries.blue.Y = 0.072200f;
+        displayPrimaries.blue.Z = 0.950633f;
+        displayPrimaries.white = new CieXyz();
+        displayPrimaries.white.X = 0.950456f;
+        displayPrimaries.white.Y = 1.000000f;
+        displayPrimaries.white.Z = 1.089058f;
+        when(mDisplayManagerInternal.getDisplayNativePrimaries(DEFAULT_DISPLAY))
+                .thenReturn(displayPrimaries);
+
+        setUpTintController();
+        assertWithMessage("Setup with valid SurfaceControl failed")
+                .that(mDisplayWhiteBalanceTintController.mSetUp)
+                .isTrue();
+
+        final int cct = 6500;
+        mDisplayWhiteBalanceTintController.setTargetCct(cct);
+        final float[] matrixDwb = mDisplayWhiteBalanceTintController.computeMatrixForCct(cct);
+        mDisplayWhiteBalanceTintController.setAppliedCct(cct);
+
+        assertWithMessage("Failed to set temperature")
+                .that(mDisplayWhiteBalanceTintController.mCurrentColorTemperature)
+                .isEqualTo(cct);
+        final float[] expectedMatrixDwb = {
+                0.971848f,   -0.001421f,  0.000491f, 0.0f,
+                0.028193f,    0.945798f,  0.003207f, 0.0f,
+                -0.000042f,  -0.000989f,  0.988659f, 0.0f,
+                0.0f,         0.0f,       0.0f,      1.0f
+        };
+        assertArrayEquals("Unexpected DWB matrix", expectedMatrixDwb, matrixDwb,
+                1e-6f /* tolerance */);
+    }
+
     private void setUpTintController() {
         mDisplayWhiteBalanceTintController = new DisplayWhiteBalanceTintController(
                 mDisplayManagerInternal);
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index cbc7dc2..317fd58 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -200,6 +200,7 @@
             mUserController.setAllowUserUnlocking(true);
             setUpUser(TEST_USER_ID, NO_USERINFO_FLAGS);
             setUpUser(TEST_PRE_CREATED_USER_ID, NO_USERINFO_FLAGS, /* preCreated= */ true, null);
+            mInjector.mRelevantUser = null;
         });
     }
 
@@ -233,6 +234,25 @@
     }
 
     @Test
+    public void testStartUser_background_duringBootHsum() {
+        mockIsHeadlessSystemUserMode(true);
+        mUserController.setAllowUserUnlocking(false);
+        mInjector.mRelevantUser = TEST_USER_ID;
+        boolean started = mUserController.startUser(TEST_USER_ID, USER_START_MODE_BACKGROUND);
+        assertWithMessage("startUser(%s, foreground=false)", TEST_USER_ID).that(started).isTrue();
+
+        // ACTION_LOCKED_BOOT_COMPLETED not sent yet
+        startUserAssertions(newArrayList(Intent.ACTION_USER_STARTED, Intent.ACTION_USER_STARTING),
+                START_BACKGROUND_USER_MESSAGE_CODES);
+
+        mUserController.onBootComplete(null);
+
+        startUserAssertions(newArrayList(Intent.ACTION_USER_STARTED, Intent.ACTION_USER_STARTING,
+                        Intent.ACTION_LOCKED_BOOT_COMPLETED),
+                START_BACKGROUND_USER_MESSAGE_CODES);
+    }
+
+    @Test
     public void testStartUser_sendsNoBroadcastsForSystemUserInNonHeadlessMode() {
         setUpUser(SYSTEM_USER_ID, UserInfo.FLAG_SYSTEM, /* preCreated= */ false,
                 UserManager.USER_TYPE_FULL_SYSTEM);
@@ -1079,6 +1099,8 @@
 
         private final Context mCtx;
 
+        private Integer mRelevantUser;
+
         TestInjector(Context ctx) {
             super(null);
             mCtx = ctx;
@@ -1166,7 +1188,9 @@
                 boolean sticky, int callingPid, int callingUid, int realCallingUid,
                 int realCallingPid, int userId) {
             Log.i(TAG, "broadcastIntentLocked " + intent);
-            mSentIntents.add(intent);
+            if (mRelevantUser == null || mRelevantUser == userId || userId == UserHandle.USER_ALL) {
+                mSentIntents.add(intent);
+            }
             return 0;
         }
 
diff --git a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncDataTest.java b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncDataTest.java
index c5a9af7..dcd06c9 100644
--- a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncDataTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncDataTest.java
@@ -30,7 +30,7 @@
     @Test
     public void call_writeToParcel_fromParcel_reconstructsSuccessfully() {
         final CallMetadataSyncData.Call call = new CallMetadataSyncData.Call();
-        final long id = 5;
+        final String id = "5";
         final String callerId = "callerId";
         final byte[] appIcon = "appIcon".getBytes();
         final String appName = "appName";
diff --git a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncInCallServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncInCallServiceTest.java
index a488ab4..afddf3c 100644
--- a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncInCallServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CallMetadataSyncInCallServiceTest.java
@@ -47,24 +47,24 @@
 
     @Test
     public void getCallForId_invalid() {
-        when(mMockCrossDeviceCall.getId()).thenReturn(-1L);
-        final CrossDeviceCall call = mSyncInCallService.getCallForId(-1L,
+        when(mMockCrossDeviceCall.getId()).thenReturn(null);
+        final CrossDeviceCall call = mSyncInCallService.getCallForId(null,
                 List.of(mMockCrossDeviceCall));
         assertWithMessage("Unexpectedly found a match for call id").that(call).isNull();
     }
 
     @Test
     public void getCallForId_noMatch() {
-        when(mMockCrossDeviceCall.getId()).thenReturn(5L);
-        final CrossDeviceCall call = mSyncInCallService.getCallForId(1L,
+        when(mMockCrossDeviceCall.getId()).thenReturn("123abc");
+        final CrossDeviceCall call = mSyncInCallService.getCallForId("abc123",
                 List.of(mMockCrossDeviceCall));
         assertWithMessage("Unexpectedly found a match for call id").that(call).isNull();
     }
 
     @Test
     public void getCallForId_hasMatch() {
-        when(mMockCrossDeviceCall.getId()).thenReturn(5L);
-        final CrossDeviceCall call = mSyncInCallService.getCallForId(5L,
+        when(mMockCrossDeviceCall.getId()).thenReturn("123abc");
+        final CrossDeviceCall call = mSyncInCallService.getCallForId("123abc",
                 List.of(mMockCrossDeviceCall));
         assertWithMessage("Unexpectedly did not find a match for call id").that(call).isNotNull();
     }
diff --git a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceCallTest.java b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceCallTest.java
index 9d42a5b..5a0646c 100644
--- a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceCallTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceCallTest.java
@@ -62,9 +62,9 @@
         assertWithMessage("Wrong status").that(crossDeviceCall.getStatus())
                 .isEqualTo(android.companion.Telecom.Call.RINGING);
         assertWithMessage("Wrong controls").that(crossDeviceCall.getControls())
-                .isEqualTo(Set.of(android.companion.Telecom.Call.ACCEPT,
-                        android.companion.Telecom.Call.REJECT,
-                        android.companion.Telecom.Call.SILENCE));
+                .isEqualTo(Set.of(android.companion.Telecom.ACCEPT,
+                        android.companion.Telecom.REJECT,
+                        android.companion.Telecom.SILENCE));
     }
 
     @Test
@@ -77,9 +77,9 @@
         assertWithMessage("Wrong status").that(crossDeviceCall.getStatus())
                 .isEqualTo(android.companion.Telecom.Call.ONGOING);
         assertWithMessage("Wrong controls").that(crossDeviceCall.getControls())
-                .isEqualTo(Set.of(android.companion.Telecom.Call.END,
-                        android.companion.Telecom.Call.MUTE,
-                        android.companion.Telecom.Call.PUT_ON_HOLD));
+                .isEqualTo(Set.of(android.companion.Telecom.END,
+                        android.companion.Telecom.MUTE,
+                        android.companion.Telecom.PUT_ON_HOLD));
     }
 
     @Test
@@ -92,8 +92,8 @@
         assertWithMessage("Wrong status").that(crossDeviceCall.getStatus())
                 .isEqualTo(android.companion.Telecom.Call.ON_HOLD);
         assertWithMessage("Wrong controls").that(crossDeviceCall.getControls())
-                .isEqualTo(Set.of(android.companion.Telecom.Call.END,
-                        android.companion.Telecom.Call.TAKE_OFF_HOLD));
+                .isEqualTo(Set.of(android.companion.Telecom.END,
+                        android.companion.Telecom.TAKE_OFF_HOLD));
     }
 
     @Test
@@ -106,8 +106,8 @@
         assertWithMessage("Wrong status").that(crossDeviceCall.getStatus())
                 .isEqualTo(android.companion.Telecom.Call.ONGOING);
         assertWithMessage("Wrong controls").that(crossDeviceCall.getControls())
-                .isEqualTo(Set.of(android.companion.Telecom.Call.END,
-                        android.companion.Telecom.Call.MUTE));
+                .isEqualTo(Set.of(android.companion.Telecom.END,
+                        android.companion.Telecom.MUTE));
     }
 
     @Test
@@ -120,8 +120,8 @@
         assertWithMessage("Wrong status").that(crossDeviceCall.getStatus())
                 .isEqualTo(android.companion.Telecom.Call.ONGOING);
         assertWithMessage("Wrong controls").that(crossDeviceCall.getControls())
-                .isEqualTo(Set.of(android.companion.Telecom.Call.END,
-                        android.companion.Telecom.Call.PUT_ON_HOLD));
+                .isEqualTo(Set.of(android.companion.Telecom.END,
+                        android.companion.Telecom.PUT_ON_HOLD));
     }
 
     @Test
@@ -134,17 +134,17 @@
         assertWithMessage("Wrong status for ringing state").that(crossDeviceCall.getStatus())
                 .isEqualTo(android.companion.Telecom.Call.RINGING);
         assertWithMessage("Wrong controls for ringing state").that(crossDeviceCall.getControls())
-                .isEqualTo(Set.of(android.companion.Telecom.Call.ACCEPT,
-                        android.companion.Telecom.Call.REJECT,
-                        android.companion.Telecom.Call.SILENCE));
+                .isEqualTo(Set.of(android.companion.Telecom.ACCEPT,
+                        android.companion.Telecom.REJECT,
+                        android.companion.Telecom.SILENCE));
         crossDeviceCall.updateCallDetails(createCallDetails(Call.STATE_ACTIVE,
                 Call.Details.CAPABILITY_HOLD | Call.Details.CAPABILITY_MUTE));
         assertWithMessage("Wrong status for active state").that(crossDeviceCall.getStatus())
                 .isEqualTo(android.companion.Telecom.Call.ONGOING);
         assertWithMessage("Wrong controls for active state").that(crossDeviceCall.getControls())
-                .isEqualTo(Set.of(android.companion.Telecom.Call.END,
-                        android.companion.Telecom.Call.MUTE,
-                        android.companion.Telecom.Call.PUT_ON_HOLD));
+                .isEqualTo(Set.of(android.companion.Telecom.END,
+                        android.companion.Telecom.MUTE,
+                        android.companion.Telecom.PUT_ON_HOLD));
     }
 
     @Test
@@ -158,8 +158,8 @@
         assertWithMessage("Wrong status").that(crossDeviceCall.getStatus())
                 .isEqualTo(android.companion.Telecom.Call.RINGING_SILENCED);
         assertWithMessage("Wrong controls").that(crossDeviceCall.getControls())
-                .isEqualTo(Set.of(android.companion.Telecom.Call.ACCEPT,
-                        android.companion.Telecom.Call.REJECT));
+                .isEqualTo(Set.of(android.companion.Telecom.ACCEPT,
+                        android.companion.Telecom.REJECT));
     }
 
     @Test
@@ -173,9 +173,9 @@
         assertWithMessage("Wrong status").that(crossDeviceCall.getStatus())
                 .isEqualTo(android.companion.Telecom.Call.ONGOING);
         assertWithMessage("Wrong controls").that(crossDeviceCall.getControls())
-                .isEqualTo(Set.of(android.companion.Telecom.Call.END,
-                        android.companion.Telecom.Call.MUTE,
-                        android.companion.Telecom.Call.PUT_ON_HOLD));
+                .isEqualTo(Set.of(android.companion.Telecom.END,
+                        android.companion.Telecom.MUTE,
+                        android.companion.Telecom.PUT_ON_HOLD));
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncControllerTest.java
index eec026cc..25b0ae4 100644
--- a/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/datatransfer/contextsync/CrossDeviceSyncControllerTest.java
@@ -81,7 +81,7 @@
 
     @Test
     public void processTelecomDataFromSync_createCallUpdateMessage_hasCalls() {
-        when(mMockCrossDeviceCall.getId()).thenReturn(5L);
+        when(mMockCrossDeviceCall.getId()).thenReturn("123abc");
         final String callerId = "Firstname Lastname";
         when(mMockCrossDeviceCall.getReadableCallerId(anyBoolean())).thenReturn(callerId);
         final String appName = "AppName";
@@ -90,9 +90,9 @@
         when(mMockCrossDeviceCall.getCallingAppIcon()).thenReturn(appIcon.getBytes());
         when(mMockCrossDeviceCall.getStatus()).thenReturn(android.companion.Telecom.Call.RINGING);
         final Set<Integer> controls = Set.of(
-                android.companion.Telecom.Call.ACCEPT,
-                android.companion.Telecom.Call.REJECT,
-                android.companion.Telecom.Call.SILENCE);
+                android.companion.Telecom.ACCEPT,
+                android.companion.Telecom.REJECT,
+                android.companion.Telecom.SILENCE);
         when(mMockCrossDeviceCall.getControls()).thenReturn(controls);
         final byte[] data = mCrossDeviceSyncController.createCallUpdateMessage(
                 new HashSet<>(List.of(mMockCrossDeviceCall)),
@@ -103,35 +103,33 @@
                 callMetadataSyncData.getCalls()).hasSize(1);
         final CallMetadataSyncData.Call call =
                 callMetadataSyncData.getCalls().stream().findAny().orElseThrow();
-        assertWithMessage("Wrong id").that(call.getId()).isEqualTo(5L);
+        assertWithMessage("Wrong id").that(call.getId()).isEqualTo("123abc");
         assertWithMessage("Wrong app icon").that(new String(call.getAppIcon())).isEqualTo(appIcon);
         assertWithMessage("Wrong app name").that(call.getAppName()).isEqualTo(appName);
         assertWithMessage("Wrong caller id").that(call.getCallerId()).isEqualTo(callerId);
         assertWithMessage("Wrong status").that(call.getStatus())
                 .isEqualTo(android.companion.Telecom.Call.RINGING);
         assertWithMessage("Wrong controls").that(call.getControls()).isEqualTo(controls);
-        assertWithMessage("Unexpectedly has requests").that(
-                callMetadataSyncData.getRequests()).isEmpty();
     }
 
     @Test
     public void processTelecomDataFromMessage_createCallControlMessage_hasCallControlRequest() {
         final byte[] data = CrossDeviceSyncController.createCallControlMessage(
-                /* callId= */ 5L, /* status= */ android.companion.Telecom.Call.ACCEPT);
+                /* callId= */ "123abc", /* status= */ android.companion.Telecom.ACCEPT);
         final CallMetadataSyncData callMetadataSyncData =
                 mCrossDeviceSyncController.processTelecomDataFromSync(data);
         assertWithMessage("Wrong number of requests").that(
                 callMetadataSyncData.getRequests()).hasSize(1);
         final CallMetadataSyncData.Call call =
                 callMetadataSyncData.getRequests().stream().findAny().orElseThrow();
-        assertWithMessage("Wrong id").that(call.getId()).isEqualTo(5L);
+        assertWithMessage("Wrong id").that(call.getId()).isEqualTo("123abc");
         assertWithMessage("Wrong app icon").that(call.getAppIcon()).isNull();
         assertWithMessage("Wrong app name").that(call.getAppName()).isNull();
         assertWithMessage("Wrong caller id").that(call.getCallerId()).isNull();
         assertWithMessage("Wrong status").that(call.getStatus())
                 .isEqualTo(android.companion.Telecom.Call.UNKNOWN_STATUS);
         assertWithMessage("Wrong controls").that(call.getControls())
-                .isEqualTo(Set.of(android.companion.Telecom.Call.ACCEPT));
+                .isEqualTo(Set.of(android.companion.Telecom.ACCEPT));
         assertWithMessage("Unexpectedly has active calls").that(
                 callMetadataSyncData.getCalls()).isEmpty();
     }
diff --git a/services/tests/servicestests/src/com/android/server/display/color/CctEvaluatorTest.java b/services/tests/servicestests/src/com/android/server/display/color/CctEvaluatorTest.java
new file mode 100644
index 0000000..b96666a
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/color/CctEvaluatorTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.server.display.color;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class CctEvaluatorTest {
+
+    @Test
+    public void noEntriesInParallelArrays_setsEverythingToOne() {
+        final CctEvaluator evaluator = new CctEvaluator(0, 5, new int[]{}, new int[]{});
+        assertThat(evaluator.mStepsAtOffsetCcts).isEqualTo(new int[]{1, 1, 1, 1, 1, 1});
+        assertThat(evaluator.mSteppedCctsAtOffsetCcts).isEqualTo(
+                new int[]{0, 1, 2, 3, 4, 5});
+    }
+
+    @Test
+    public void unevenNumberOfEntriesInParallelArrays_setsEverythingToOne() {
+        final CctEvaluator evaluator = new CctEvaluator(0, 5, new int[]{0}, new int[]{});
+        assertThat(evaluator.mStepsAtOffsetCcts).isEqualTo(new int[]{1, 1, 1, 1, 1, 1});
+        assertThat(evaluator.mSteppedCctsAtOffsetCcts).isEqualTo(
+                new int[]{0, 1, 2, 3, 4, 5});
+    }
+
+    @Test
+    public void singleEntryInParallelArray_computesCorrectly() {
+        final CctEvaluator evaluator = new CctEvaluator(0, 5, new int[]{0}, new int[]{2});
+        assertThat(evaluator.mStepsAtOffsetCcts).isEqualTo(new int[]{2, 2, 2, 2, 2, 2});
+        assertThat(evaluator.mSteppedCctsAtOffsetCcts).isEqualTo(
+                new int[]{0, 0, 2, 2, 4, 4});
+    }
+
+    @Test
+    public void minimumIsBelowFirstRange_computesCorrectly() {
+        final CctEvaluator evaluator = new CctEvaluator(3000, 3005, new int[]{3002},
+                new int[]{20});
+        assertThat(evaluator.mStepsAtOffsetCcts).isEqualTo(new int[]{20, 20, 20, 20, 20, 20});
+        assertThat(evaluator.mSteppedCctsAtOffsetCcts).isEqualTo(
+                new int[]{3000, 3000, 3000, 3000, 3000, 3000});
+    }
+
+    @Test
+    public void minimumIsAboveFirstRange_computesCorrectly() {
+        final CctEvaluator evaluator = new CctEvaluator(3000, 3008, new int[]{3002},
+                new int[]{20});
+        assertThat(evaluator.mStepsAtOffsetCcts).isEqualTo(
+                new int[]{20, 20, 20, 20, 20, 20, 20, 20, 20});
+        assertThat(evaluator.mSteppedCctsAtOffsetCcts).isEqualTo(
+                new int[]{3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000});
+    }
+
+    @Test
+    public void multipleStepsStartsAtThreshold_computesCorrectly() {
+        final CctEvaluator evaluator = new CctEvaluator(5, 20, new int[]{0, 4, 5, 10, 18},
+                new int[]{11, 7, 2, 15, 9});
+        assertThat(evaluator.mStepsAtOffsetCcts).isEqualTo(
+                new int[]{2, 2, 2, 2, 2, 15, 15, 15, 15, 15, 15, 15, 15, 9, 9, 9});
+        assertThat(evaluator.mSteppedCctsAtOffsetCcts).isEqualTo(
+                new int[]{5, 5, 7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 18, 18, 18});
+    }
+
+    @Test
+    public void multipleStepsStartsInBetween_computesCorrectly() {
+        final CctEvaluator evaluator = new CctEvaluator(4, 20, new int[]{0, 5, 10, 18},
+                new int[]{14, 2, 15, 9});
+        assertThat(evaluator.mStepsAtOffsetCcts).isEqualTo(
+                new int[]{14, 2, 2, 2, 2, 2, 15, 15, 15, 15, 15, 15, 15, 15, 9, 9, 9});
+        assertThat(evaluator.mSteppedCctsAtOffsetCcts).isEqualTo(
+                new int[]{4, 4, 6, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 18, 18, 18});
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt b/services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt
index d0d28c3..55c45df 100644
--- a/services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt
+++ b/services/tests/servicestests/src/com/android/server/input/KeyboardLayoutManagerTests.kt
@@ -85,6 +85,9 @@
         const val DEVICE_ID = 1
         const val VENDOR_SPECIFIC_DEVICE_ID = 2
         const val ENGLISH_DVORAK_DEVICE_ID = 3
+        const val ENGLISH_QWERTY_DEVICE_ID = 4
+        const val DEFAULT_VENDOR_ID = 123
+        const val DEFAULT_PRODUCT_ID = 456
         const val USER_ID = 4
         const val IME_ID = "ime_id"
         const val PACKAGE_NAME = "KeyboardLayoutManagerTests"
@@ -122,6 +125,7 @@
     private lateinit var keyboardDevice: InputDevice
     private lateinit var vendorSpecificKeyboardDevice: InputDevice
     private lateinit var englishDvorakKeyboardDevice: InputDevice
+    private lateinit var englishQwertyKeyboardDevice: InputDevice
 
     @Before
     fun setup() {
@@ -150,17 +154,26 @@
         Mockito.`when`(context.getSystemService(Mockito.eq(Context.INPUT_SERVICE)))
             .thenReturn(inputManager)
 
-        keyboardDevice = createKeyboard(DEVICE_ID, 0, 0, "", "")
+        keyboardDevice = createKeyboard(DEVICE_ID, DEFAULT_VENDOR_ID, DEFAULT_PRODUCT_ID, "", "")
         vendorSpecificKeyboardDevice = createKeyboard(VENDOR_SPECIFIC_DEVICE_ID, 1, 1, "", "")
-        englishDvorakKeyboardDevice =
-            createKeyboard(ENGLISH_DVORAK_DEVICE_ID, 0, 0, "en", "dvorak")
+        englishDvorakKeyboardDevice = createKeyboard(ENGLISH_DVORAK_DEVICE_ID, DEFAULT_VENDOR_ID,
+                DEFAULT_PRODUCT_ID, "en", "dvorak")
+        englishQwertyKeyboardDevice = createKeyboard(ENGLISH_QWERTY_DEVICE_ID, DEFAULT_VENDOR_ID,
+                DEFAULT_PRODUCT_ID, "en", "qwerty")
         Mockito.`when`(iInputManager.inputDeviceIds)
-            .thenReturn(intArrayOf(DEVICE_ID, VENDOR_SPECIFIC_DEVICE_ID, ENGLISH_DVORAK_DEVICE_ID))
+            .thenReturn(intArrayOf(
+                DEVICE_ID,
+                VENDOR_SPECIFIC_DEVICE_ID,
+                ENGLISH_DVORAK_DEVICE_ID,
+                ENGLISH_QWERTY_DEVICE_ID
+            ))
         Mockito.`when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardDevice)
         Mockito.`when`(iInputManager.getInputDevice(VENDOR_SPECIFIC_DEVICE_ID))
             .thenReturn(vendorSpecificKeyboardDevice)
         Mockito.`when`(iInputManager.getInputDevice(ENGLISH_DVORAK_DEVICE_ID))
             .thenReturn(englishDvorakKeyboardDevice)
+        Mockito.`when`(iInputManager.getInputDevice(ENGLISH_QWERTY_DEVICE_ID))
+                .thenReturn(englishQwertyKeyboardDevice)
     }
 
     private fun setupBroadcastReceiver() {
@@ -778,14 +791,23 @@
     @Test
     fun testNewUi_getDefaultKeyboardLayoutForInputDevice_withHwLanguageTagAndLayoutType() {
         NewSettingsApiFlag(true).use {
-            // Should return English dvorak even if IME current layout is qwerty, since HW says the
+            val frenchSubtype = createImeSubtypeForLanguageTagAndLayoutType("fr", "azerty")
+            // Should return English dvorak even if IME current layout is French, since HW says the
             // keyboard is a Dvorak keyboard
             assertCorrectLayout(
                 englishDvorakKeyboardDevice,
-                createImeSubtypeForLanguageTagAndLayoutType("en", "qwerty"),
+                frenchSubtype,
                 createLayoutDescriptor("keyboard_layout_english_us_dvorak")
             )
 
+            // Back to back changing HW keyboards with same product and vendor ID but different
+            // language and layout type should configure the layouts correctly.
+            assertCorrectLayout(
+                englishQwertyKeyboardDevice,
+                frenchSubtype,
+                createLayoutDescriptor("keyboard_layout_english_us")
+            )
+
             // Fallback to IME information if the HW provided layout script is incompatible with the
             // provided IME subtype
             assertCorrectLayout(
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index 01e56a0..1cfaf7c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -228,6 +228,15 @@
                 });
     }
 
+    public void testShortcutIdTruncated() {
+        ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(),
+                "s".repeat(Short.MAX_VALUE)).build();
+
+        assertTrue(
+                "id must be truncated to MAX_ID_LENGTH",
+                si.getId().length() <= ShortcutInfo.MAX_ID_LENGTH);
+    }
+
     public void testShortcutInfoParcel() {
         setCaller(CALLING_PACKAGE_1, USER_10);
         ShortcutInfo si = parceled(new ShortcutInfo.Builder(mClientContext)
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index 52bf244..ae3ceb1 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -20,6 +20,7 @@
 import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
 import static android.app.AppOpsManager.MODE_ALLOWED;
 import static android.app.AppOpsManager.MODE_ERRORED;
+import static android.os.PowerManager.USER_ACTIVITY_EVENT_BUTTON;
 import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP;
 import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE;
 import static android.os.PowerManagerInternal.WAKEFULNESS_DOZING;
@@ -41,6 +42,7 @@
 import static org.mockito.ArgumentMatchers.same;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.atMost;
+import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
@@ -112,6 +114,7 @@
 import org.mockito.MockitoAnnotations;
 import org.mockito.stubbing.Answer;
 
+import java.time.Duration;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.Executor;
@@ -2468,4 +2471,18 @@
         verify(mNotifierMock).onWakeLockReleased(anyInt(), eq(tag), eq(packageName), anyInt(),
                 anyInt(), any(), any(), same(callback2));
     }
+
+    @Test
+    public void testUserActivity_futureEventsAreIgnored() {
+        createService();
+        startSystem();
+        // Starting the system triggers a user activity event, so clear that before calling
+        // userActivity() directly.
+        clearInvocations(mNotifierMock);
+        final long eventTime = mClock.now() + Duration.ofHours(10).toMillis();
+        mService.getBinderServiceInstance().userActivity(Display.DEFAULT_DISPLAY, eventTime,
+                USER_ACTIVITY_EVENT_BUTTON, /* flags= */ 0);
+        verify(mNotifierMock, never()).onUserActivity(anyInt(),  anyInt(), anyInt());
+    }
+
 }
diff --git a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java
index 2d0755d..3ac9a27 100644
--- a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java
+++ b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundHw2CompatTest.java
@@ -16,6 +16,8 @@
 
 package com.android.server.soundtrigger_middleware;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
@@ -34,12 +36,12 @@
 import static org.mockito.Mockito.when;
 
 import android.media.soundtrigger.ModelParameterRange;
-import android.media.soundtrigger.PhraseRecognitionEvent;
 import android.media.soundtrigger.Properties;
 import android.media.soundtrigger.RecognitionConfig;
-import android.media.soundtrigger.RecognitionEvent;
 import android.media.soundtrigger.RecognitionStatus;
 import android.media.soundtrigger.Status;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
 import android.os.HwParcel;
 import android.os.IBinder;
 import android.os.IHwBinder;
@@ -617,13 +619,16 @@
             final int handle = 85;
             final int status =
                     android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.ABORT;
-            ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
-                    RecognitionEvent.class);
+            ArgumentCaptor<RecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+                    RecognitionEventSys.class);
 
             hwCallback.recognitionCallback(TestUtil.createRecognitionEvent_2_0(handle, status), 99);
             mCanonical.flushCallbacks();
             verify(canonicalCallback).recognitionCallback(eq(handle), eventCaptor.capture());
-            TestUtil.validateRecognitionEvent(eventCaptor.getValue(), RecognitionStatus.ABORTED,
+            RecognitionEventSys lastEvent = eventCaptor.getValue();
+            assertThat(lastEvent.halEventReceivedMillis).isGreaterThan(0);
+            TestUtil.validateRecognitionEvent(lastEvent.recognitionEvent,
+                    RecognitionStatus.ABORTED,
                     false);
         }
 
@@ -631,14 +636,16 @@
             final int handle = 92;
             final int status =
                     android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.SUCCESS;
-            ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
-                    PhraseRecognitionEvent.class);
+            ArgumentCaptor<PhraseRecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+                    PhraseRecognitionEventSys.class);
 
             hwCallback.phraseRecognitionCallback(
                     TestUtil.createPhraseRecognitionEvent_2_0(handle, status), 99);
             mCanonical.flushCallbacks();
             verify(canonicalCallback).phraseRecognitionCallback(eq(handle), eventCaptor.capture());
-            TestUtil.validatePhraseRecognitionEvent(eventCaptor.getValue(),
+            PhraseRecognitionEventSys lastEvent = eventCaptor.getValue();
+            assertThat(lastEvent.halEventReceivedMillis).isGreaterThan(0);
+            TestUtil.validatePhraseRecognitionEvent(lastEvent.phraseRecognitionEvent,
                     RecognitionStatus.SUCCESS, false);
         }
         verifyNoMoreInteractions(canonicalCallback);
@@ -652,28 +659,34 @@
             final int handle = 85;
             final int status =
                     android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.ABORT;
-            ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
-                    RecognitionEvent.class);
+            ArgumentCaptor<RecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+                    RecognitionEventSys.class);
 
             hwCallback.recognitionCallback_2_1(TestUtil.createRecognitionEvent_2_1(handle, status),
                     99);
             mCanonical.flushCallbacks();
             verify(canonicalCallback).recognitionCallback(eq(handle), eventCaptor.capture());
-            TestUtil.validateRecognitionEvent(eventCaptor.getValue(), RecognitionStatus.ABORTED,
+            RecognitionEventSys lastEvent = eventCaptor.getValue();
+            assertThat(lastEvent.halEventReceivedMillis).isGreaterThan(0);
+            TestUtil.validateRecognitionEvent(lastEvent.recognitionEvent,
+                    RecognitionStatus.ABORTED,
                     false);
         }
 
         {
             final int handle = 87;
             final int status = 3; // FORCED;
-            ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
-                    RecognitionEvent.class);
+            ArgumentCaptor<RecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+                    RecognitionEventSys.class);
 
             hwCallback.recognitionCallback_2_1(TestUtil.createRecognitionEvent_2_1(handle, status),
                     99);
             mCanonical.flushCallbacks();
             verify(canonicalCallback).recognitionCallback(eq(handle), eventCaptor.capture());
-            TestUtil.validateRecognitionEvent(eventCaptor.getValue(), RecognitionStatus.FORCED,
+            RecognitionEventSys lastEvent = eventCaptor.getValue();
+            assertThat(lastEvent.halEventReceivedMillis).isGreaterThan(0);
+            TestUtil.validateRecognitionEvent(lastEvent.recognitionEvent,
+                    RecognitionStatus.FORCED,
                     true);
         }
 
@@ -681,28 +694,32 @@
             final int handle = 92;
             final int status =
                     android.hardware.soundtrigger.V2_0.ISoundTriggerHwCallback.RecognitionStatus.SUCCESS;
-            ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
-                    PhraseRecognitionEvent.class);
+            ArgumentCaptor<PhraseRecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+                    PhraseRecognitionEventSys.class);
 
             hwCallback.phraseRecognitionCallback_2_1(
                     TestUtil.createPhraseRecognitionEvent_2_1(handle, status), 99);
             mCanonical.flushCallbacks();
             verify(canonicalCallback).phraseRecognitionCallback(eq(handle), eventCaptor.capture());
-            TestUtil.validatePhraseRecognitionEvent(eventCaptor.getValue(),
+            PhraseRecognitionEventSys lastEvent = eventCaptor.getValue();
+            assertThat(lastEvent.halEventReceivedMillis).isGreaterThan(0);
+            TestUtil.validatePhraseRecognitionEvent(lastEvent.phraseRecognitionEvent,
                     RecognitionStatus.SUCCESS, false);
         }
 
         {
             final int handle = 102;
             final int status = 3; // FORCED;
-            ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
-                    PhraseRecognitionEvent.class);
+            ArgumentCaptor<PhraseRecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+                    PhraseRecognitionEventSys.class);
 
             hwCallback.phraseRecognitionCallback_2_1(
                     TestUtil.createPhraseRecognitionEvent_2_1(handle, status), 99);
             mCanonical.flushCallbacks();
             verify(canonicalCallback).phraseRecognitionCallback(eq(handle), eventCaptor.capture());
-            TestUtil.validatePhraseRecognitionEvent(eventCaptor.getValue(),
+            PhraseRecognitionEventSys lastEvent = eventCaptor.getValue();
+            assertThat(lastEvent.halEventReceivedMillis).isGreaterThan(0);
+            TestUtil.validatePhraseRecognitionEvent(lastEvent.phraseRecognitionEvent,
                     RecognitionStatus.FORCED, true);
         }
         verifyNoMoreInteractions(canonicalCallback);
diff --git a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandlerTest.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandlerTest.java
index 6198925..9a59ede 100644
--- a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandlerTest.java
+++ b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandlerTest.java
@@ -30,8 +30,8 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.verifyZeroInteractions;
 
-import android.media.soundtrigger.RecognitionEvent;
 import android.media.soundtrigger.RecognitionStatus;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
 
 import androidx.annotation.NonNull;
 
@@ -68,13 +68,14 @@
 
         mNotifier.setActive(true);
         verify(mUnderlying).stopRecognition(handle);
-        ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
-                RecognitionEvent.class);
+        ArgumentCaptor<RecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+                RecognitionEventSys.class);
         Thread.sleep(50);
         verify(callback).recognitionCallback(eq(handle), eventCaptor.capture());
-        RecognitionEvent event = eventCaptor.getValue();
-        assertEquals(event.status, RecognitionStatus.ABORTED);
-        assertFalse(event.recognitionStillActive);
+        RecognitionEventSys event = eventCaptor.getValue();
+        assertEquals(event.halEventReceivedMillis, -1);
+        assertEquals(event.recognitionEvent.status, RecognitionStatus.ABORTED);
+        assertFalse(event.recognitionEvent.recognitionStillActive);
         verifyZeroInteractions(mGlobalCallback);
         clearInvocations(callback, mUnderlying);
 
@@ -116,8 +117,11 @@
 
         mNotifier.setActive(true);
         verify(mUnderlying, times(1)).stopRecognition(handle);
+        ArgumentCaptor<RecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+                RecognitionEventSys.class);
         mHandler.stopRecognition(handle);
-        verify(callback, times(1)).recognitionCallback(eq(handle), any());
+        verify(callback).recognitionCallback(eq(handle), eventCaptor.capture());
+        assertEquals(eventCaptor.getValue().halEventReceivedMillis, -1);
     }
 
     @Test(timeout = 200)
@@ -133,19 +137,21 @@
         verify(mUnderlying).startRecognition(eq(handle), eq(101), eq(102), any());
 
         doAnswer(invocation -> {
-            RecognitionEvent event = TestUtil.createRecognitionEvent(RecognitionStatus.ABORTED,
+            RecognitionEventSys recognitionEventSys = new RecognitionEventSys();
+            recognitionEventSys.recognitionEvent = TestUtil.createRecognitionEvent(
+                    RecognitionStatus.ABORTED,
                     false);
+            recognitionEventSys.halEventReceivedMillis = 12345;
             // Call the callback from a different thread to detect deadlocks by preventing recursive
             // locking from working.
-            runOnSeparateThread(() -> modelCallback.recognitionCallback(handle, event));
+            runOnSeparateThread(
+                    () -> modelCallback.recognitionCallback(handle, recognitionEventSys));
             return null;
         }).when(mUnderlying).stopRecognition(handle);
         mHandler.stopRecognition(handle);
         verify(mUnderlying, times(1)).stopRecognition(handle);
 
-        ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
-                RecognitionEvent.class);
-        verify(callback, atMost(1)).recognitionCallback(eq(handle), eventCaptor.capture());
+        verify(callback, atMost(1)).recognitionCallback(eq(handle), any(RecognitionEventSys.class));
     }
 
     @Test(timeout = 200)
@@ -162,11 +168,15 @@
 
         doAnswer(invocation -> {
             // The stop request causes a callback to be flushed.
-            RecognitionEvent event = TestUtil.createRecognitionEvent(RecognitionStatus.FORCED,
+            RecognitionEventSys recognitionEventSys = new RecognitionEventSys();
+            recognitionEventSys.recognitionEvent = TestUtil.createRecognitionEvent(
+                    RecognitionStatus.FORCED,
                     true);
+            recognitionEventSys.halEventReceivedMillis = 12345;
             // Call the callback from a different thread to detect deadlocks by preventing recursive
             // locking from working.
-            runOnSeparateThread(() -> modelCallback.recognitionCallback(handle, event));
+            runOnSeparateThread(
+                    () -> modelCallback.recognitionCallback(handle, recognitionEventSys));
             // While the HAL is processing the stop request, capture state becomes active.
             new Thread(() -> mNotifier.setActive(true)).start();
             Thread.sleep(50);
@@ -194,11 +204,15 @@
 
         doAnswer(invocation -> {
             // The stop request causes a callback to be flushed.
-            RecognitionEvent event = TestUtil.createRecognitionEvent(RecognitionStatus.FORCED,
+            RecognitionEventSys recognitionEventSys = new RecognitionEventSys();
+            recognitionEventSys.recognitionEvent = TestUtil.createRecognitionEvent(
+                    RecognitionStatus.FORCED,
                     true);
+            recognitionEventSys.halEventReceivedMillis = 12345;
             // Call the callback from a different thread to detect deadlocks by preventing recursive
             // locking from working.
-            runOnSeparateThread(() -> modelCallback.recognitionCallback(handle, event));
+            runOnSeparateThread(
+                    () -> modelCallback.recognitionCallback(handle, recognitionEventSys));
             // While the HAL is processing the stop request, client requests stop.
             new Thread(() -> mHandler.stopRecognition(handle)).start();
             Thread.sleep(50);
@@ -223,23 +237,22 @@
         verify(mUnderlying).startRecognition(eq(handle), eq(101), eq(102), any());
 
         doAnswer(invocation -> {
-            RecognitionEvent event = TestUtil.createRecognitionEvent(RecognitionStatus.SUCCESS,
+            RecognitionEventSys recognitionEventSys = new RecognitionEventSys();
+            recognitionEventSys.recognitionEvent = TestUtil.createRecognitionEvent(
+                    RecognitionStatus.SUCCESS,
                     false);
+            recognitionEventSys.halEventReceivedMillis = 12345;
             // Call the callback from a different thread to detect deadlocks by preventing recursive
             // locking from working.
-            runOnSeparateThread(() -> modelCallback.recognitionCallback(handle, event));
+            runOnSeparateThread(
+                    () -> modelCallback.recognitionCallback(handle, recognitionEventSys));
             return null;
         }).when(mUnderlying).stopRecognition(handle);
         mNotifier.setActive(true);
         verify(mUnderlying, times(1)).stopRecognition(handle);
         Thread.sleep(50);
 
-        ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
-                RecognitionEvent.class);
-        verify(callback, atMost(2)).recognitionCallback(eq(handle), eventCaptor.capture());
-        RecognitionEvent lastEvent = eventCaptor.getValue();
-        assertEquals(lastEvent.status, RecognitionStatus.ABORTED);
-        assertFalse(lastEvent.recognitionStillActive);
+        verify(callback, atMost(2)).recognitionCallback(eq(handle), any());
     }
 
 
@@ -256,11 +269,15 @@
         verify(mUnderlying).startRecognition(eq(handle), eq(101), eq(102), any());
 
         doAnswer(invocation -> {
-            RecognitionEvent event = TestUtil.createRecognitionEvent(RecognitionStatus.FORCED,
+            RecognitionEventSys recognitionEventSys = new RecognitionEventSys();
+            recognitionEventSys.recognitionEvent = TestUtil.createRecognitionEvent(
+                    RecognitionStatus.FORCED,
                     true);
+            recognitionEventSys.halEventReceivedMillis = 12345;
             // Call the callback from a different thread to detect deadlocks by preventing recursive
             // locking from working.
-            runOnSeparateThread(() -> modelCallback.recognitionCallback(handle, event));
+            runOnSeparateThread(
+                    () -> modelCallback.recognitionCallback(handle, recognitionEventSys));
 
             return null;
         }).when(mUnderlying).stopRecognition(handle);
@@ -268,12 +285,7 @@
         verify(mUnderlying, times(1)).stopRecognition(handle);
 
         Thread.sleep(50);
-        ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
-                RecognitionEvent.class);
-        verify(callback, atMost(2)).recognitionCallback(eq(handle), eventCaptor.capture());
-        RecognitionEvent lastEvent = eventCaptor.getValue();
-        assertEquals(lastEvent.status, RecognitionStatus.ABORTED);
-        assertFalse(lastEvent.recognitionStillActive);
+        verify(callback, atMost(2)).recognitionCallback(eq(handle), any());
     }
 
     private static void runOnSeparateThread(Runnable runnable) {
diff --git a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
index 3bebc94..5a2451f 100644
--- a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
+++ b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
@@ -30,18 +30,19 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.annotation.ElapsedRealtimeLong;
 import android.media.soundtrigger.ModelParameter;
 import android.media.soundtrigger.ModelParameterRange;
-import android.media.soundtrigger.PhraseRecognitionEvent;
 import android.media.soundtrigger.PhraseSoundModel;
 import android.media.soundtrigger.Properties;
 import android.media.soundtrigger.RecognitionConfig;
-import android.media.soundtrigger.RecognitionEvent;
 import android.media.soundtrigger.RecognitionStatus;
 import android.media.soundtrigger.SoundModel;
 import android.media.soundtrigger.Status;
 import android.media.soundtrigger_middleware.ISoundTriggerCallback;
 import android.media.soundtrigger_middleware.ISoundTriggerModule;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
 import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
 import android.os.RemoteException;
 import android.util.Pair;
@@ -224,10 +225,12 @@
         // Stop the recognition.
         stopRecognition(module, handle, hwHandle);
 
-        ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
-                RecognitionEvent.class);
+        ArgumentCaptor<RecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+                RecognitionEventSys.class);
         verify(callback).onRecognition(eq(handle), eventCaptor.capture(), eq(101));
-        assertEquals(RecognitionStatus.ABORTED, eventCaptor.getValue().status);
+        RecognitionEventSys lastEvent = eventCaptor.getValue();
+        assertEquals(-1, lastEvent.halEventReceivedMillis);
+        assertEquals(RecognitionStatus.ABORTED, lastEvent.recognitionEvent.status);
 
         // Unload the model.
         unloadModel(module, handle, hwHandle);
@@ -273,10 +276,12 @@
         // Stop the recognition.
         stopRecognition(module, handle, hwHandle);
 
-        ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
-                PhraseRecognitionEvent.class);
+        ArgumentCaptor<PhraseRecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+                PhraseRecognitionEventSys.class);
         verify(callback).onPhraseRecognition(eq(handle), eventCaptor.capture(), eq(101));
-        assertEquals(RecognitionStatus.ABORTED, eventCaptor.getValue().common.status);
+        PhraseRecognitionEventSys lastEvent = eventCaptor.getValue();
+        assertEquals(-1, lastEvent.halEventReceivedMillis);
+        assertEquals(RecognitionStatus.ABORTED, lastEvent.phraseRecognitionEvent.common.status);
 
         // Unload the model.
         unloadModel(module, handle, hwHandle);
@@ -299,11 +304,11 @@
 
         {
             // Signal a capture from the driver (with "still active").
-            RecognitionEvent event = hwCallback.sendRecognitionEvent(hwHandle,
-                    RecognitionStatus.SUCCESS, true);
+            RecognitionEventSys event = hwCallback.sendRecognitionEvent(hwHandle,
+                    RecognitionStatus.SUCCESS, true, 12345);
 
-            ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
-                    RecognitionEvent.class);
+            ArgumentCaptor<RecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+                    RecognitionEventSys.class);
             verify(callback).onRecognition(eq(handle), eventCaptor.capture(), eq(101));
 
             // Validate the event.
@@ -312,11 +317,11 @@
 
         {
             // Signal a capture from the driver (without "still active").
-            RecognitionEvent event = hwCallback.sendRecognitionEvent(hwHandle,
-                    RecognitionStatus.SUCCESS, false);
+            RecognitionEventSys event = hwCallback.sendRecognitionEvent(hwHandle,
+                    RecognitionStatus.SUCCESS, false, 12345);
 
-            ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
-                    RecognitionEvent.class);
+            ArgumentCaptor<RecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+                    RecognitionEventSys.class);
             verify(callback, times(2)).onRecognition(eq(handle), eventCaptor.capture(), eq(101));
 
             // Validate the event.
@@ -343,11 +348,11 @@
         startRecognition(module, handle, hwHandle);
 
         // Signal a capture from the driver.
-        PhraseRecognitionEvent event = hwCallback.sendPhraseRecognitionEvent(hwHandle,
-                RecognitionStatus.SUCCESS, false);
+        PhraseRecognitionEventSys event = hwCallback.sendPhraseRecognitionEvent(hwHandle,
+                RecognitionStatus.SUCCESS, false, 12345);
 
-        ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
-                PhraseRecognitionEvent.class);
+        ArgumentCaptor<PhraseRecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+                PhraseRecognitionEventSys.class);
         verify(callback).onPhraseRecognition(eq(handle), eventCaptor.capture(), eq(101));
 
         // Validate the event.
@@ -377,11 +382,11 @@
         verify(mHalDriver).forceRecognitionEvent(hwHandle);
 
         // Signal a capture from the driver.
-        RecognitionEvent event = hwCallback.sendRecognitionEvent(hwHandle,
-                RecognitionStatus.FORCED, true);
+        RecognitionEventSys event = hwCallback.sendRecognitionEvent(hwHandle,
+                RecognitionStatus.FORCED, true, 12345);
 
-        ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
-                RecognitionEvent.class);
+        ArgumentCaptor<RecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+                RecognitionEventSys.class);
         verify(callback).onRecognition(eq(handle), eventCaptor.capture(), eq(101));
 
         // Validate the event.
@@ -445,11 +450,11 @@
         verify(mHalDriver).forceRecognitionEvent(hwHandle);
 
         // Signal a capture from the driver.
-        PhraseRecognitionEvent event = hwCallback.sendPhraseRecognitionEvent(hwHandle,
-                RecognitionStatus.FORCED, true);
+        PhraseRecognitionEventSys event = hwCallback.sendPhraseRecognitionEvent(hwHandle,
+                RecognitionStatus.FORCED, true, 12345);
 
-        ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
-                PhraseRecognitionEvent.class);
+        ArgumentCaptor<PhraseRecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+                PhraseRecognitionEventSys.class);
         verify(callback).onPhraseRecognition(eq(handle), eventCaptor.capture(), eq(101));
 
         // Validate the event.
@@ -510,14 +515,16 @@
         startRecognition(module, handle, hwHandle);
 
         // Abort.
-        hwCallback.sendRecognitionEvent(hwHandle, RecognitionStatus.ABORTED, false);
+        hwCallback.sendRecognitionEvent(hwHandle, RecognitionStatus.ABORTED, false, 12345);
 
-        ArgumentCaptor<RecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
-                RecognitionEvent.class);
+        ArgumentCaptor<RecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+                RecognitionEventSys.class);
         verify(callback).onRecognition(eq(handle), eventCaptor.capture(), eq(101));
 
         // Validate the event.
-        assertEquals(RecognitionStatus.ABORTED, eventCaptor.getValue().status);
+        RecognitionEventSys lastEvent = eventCaptor.getValue();
+        assertEquals(12345, lastEvent.halEventReceivedMillis);
+        assertEquals(RecognitionStatus.ABORTED, lastEvent.recognitionEvent.status);
 
         // Unload the model.
         unloadModel(module, handle, hwHandle);
@@ -540,14 +547,16 @@
         startRecognition(module, handle, hwHandle);
 
         // Abort.
-        hwCallback.sendPhraseRecognitionEvent(hwHandle, RecognitionStatus.ABORTED, false);
+        hwCallback.sendPhraseRecognitionEvent(hwHandle, RecognitionStatus.ABORTED, false, 12345);
 
-        ArgumentCaptor<PhraseRecognitionEvent> eventCaptor = ArgumentCaptor.forClass(
-                PhraseRecognitionEvent.class);
+        ArgumentCaptor<PhraseRecognitionEventSys> eventCaptor = ArgumentCaptor.forClass(
+                PhraseRecognitionEventSys.class);
         verify(callback).onPhraseRecognition(eq(handle), eventCaptor.capture(), eq(101));
 
         // Validate the event.
-        assertEquals(RecognitionStatus.ABORTED, eventCaptor.getValue().common.status);
+        PhraseRecognitionEventSys lastEvent = eventCaptor.getValue();
+        assertEquals(12345, lastEvent.halEventReceivedMillis);
+        assertEquals(RecognitionStatus.ABORTED, lastEvent.phraseRecognitionEvent.common.status);
 
         // Unload the model.
         unloadModel(module, handle, hwHandle);
@@ -630,18 +639,24 @@
             mCallback = callback;
         }
 
-        private RecognitionEvent sendRecognitionEvent(int hwHandle, @RecognitionStatus int status,
-                boolean recognitionStillActive) {
-            RecognitionEvent event = TestUtil.createRecognitionEvent(status,
+        private RecognitionEventSys sendRecognitionEvent(int hwHandle,
+                @RecognitionStatus int status,
+                boolean recognitionStillActive, @ElapsedRealtimeLong long halEventReceivedMillis) {
+            RecognitionEventSys event = new RecognitionEventSys();
+            event.recognitionEvent = TestUtil.createRecognitionEvent(status,
                     recognitionStillActive);
+            event.halEventReceivedMillis = halEventReceivedMillis;
             mCallback.recognitionCallback(hwHandle, event);
             return event;
         }
 
-        private PhraseRecognitionEvent sendPhraseRecognitionEvent(int hwHandle,
-                @RecognitionStatus int status, boolean recognitionStillActive) {
-            PhraseRecognitionEvent event = TestUtil.createPhraseRecognitionEvent(status,
+        private PhraseRecognitionEventSys sendPhraseRecognitionEvent(int hwHandle,
+                @RecognitionStatus int status, boolean recognitionStillActive,
+                @ElapsedRealtimeLong long halEventReceivedMillis) {
+            PhraseRecognitionEventSys event = new PhraseRecognitionEventSys();
+            event.phraseRecognitionEvent = TestUtil.createPhraseRecognitionEvent(status,
                     recognitionStillActive);
+            event.halEventReceivedMillis = halEventReceivedMillis;
             mCallback.phraseRecognitionCallback(hwHandle, event);
             return event;
         }
diff --git a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java
index f8a068c..cc357d7 100644
--- a/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java
+++ b/services/tests/voiceinteractiontests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLoggingLatencyTest.java
@@ -32,7 +32,7 @@
 import android.media.soundtrigger.RecognitionEvent;
 import android.media.soundtrigger.RecognitionStatus;
 import android.media.soundtrigger_middleware.ISoundTriggerCallback;
-import android.media.soundtrigger_middleware.ISoundTriggerModule;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
 import android.os.BatteryStatsInternal;
 import android.os.Process;
 import android.os.RemoteException;
@@ -51,8 +51,6 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-import java.util.Optional;
-
 @RunWith(JUnit4.class)
 public class SoundTriggerMiddlewareLoggingLatencyTest {
 
@@ -63,8 +61,6 @@
     private ISoundTriggerMiddlewareInternal mDelegateMiddleware;
     @Mock
     private ISoundTriggerCallback mISoundTriggerCallback;
-    @Mock
-    private ISoundTriggerModule mSoundTriggerModule;
     private SoundTriggerMiddlewareLogging mSoundTriggerMiddlewareLogging;
 
     @Before
@@ -109,7 +105,7 @@
         verify(mDelegateMiddleware).attach(anyInt(), soundTriggerCallbackCaptor.capture());
 
         triggerPhraseRecognitionEvent(soundTriggerCallbackCaptor.getValue(),
-                RecognitionStatus.SUCCESS, Optional.of(100) /* keyphraseId */);
+                RecognitionStatus.SUCCESS, 100 /* keyphraseId */);
 
         assertThat(mLatencyTracker.getActiveActionStartTime(
                 ACTION_SHOW_VOICE_INTERACTION)).isGreaterThan(-1);
@@ -124,11 +120,11 @@
         verify(mDelegateMiddleware).attach(anyInt(), soundTriggerCallbackCaptor.capture());
 
         triggerPhraseRecognitionEvent(soundTriggerCallbackCaptor.getValue(),
-                RecognitionStatus.SUCCESS, Optional.of(100) /* keyphraseId */);
+                RecognitionStatus.SUCCESS, 100 /* keyphraseId */);
         long firstTriggerSessionStartTime = mLatencyTracker.getActiveActionStartTime(
                 ACTION_SHOW_VOICE_INTERACTION);
         triggerPhraseRecognitionEvent(soundTriggerCallbackCaptor.getValue(),
-                RecognitionStatus.SUCCESS, Optional.of(100) /* keyphraseId */);
+                RecognitionStatus.SUCCESS, 100 /* keyphraseId */);
         assertThat(mLatencyTracker.getActiveActionStartTime(
                 ACTION_SHOW_VOICE_INTERACTION)).isGreaterThan(-1);
         assertThat(mLatencyTracker.getActiveActionStartTime(
@@ -145,7 +141,7 @@
         verify(mDelegateMiddleware).attach(anyInt(), soundTriggerCallbackCaptor.capture());
 
         triggerPhraseRecognitionEvent(soundTriggerCallbackCaptor.getValue(),
-                RecognitionStatus.ABORTED, Optional.of(100) /* keyphraseId */);
+                RecognitionStatus.ABORTED, 100 /* keyphraseId */);
 
         assertThat(
                 mLatencyTracker.getActiveActionStartTime(ACTION_SHOW_VOICE_INTERACTION)).isEqualTo(
@@ -162,7 +158,7 @@
         verify(mDelegateMiddleware).attach(anyInt(), soundTriggerCallbackCaptor.capture());
 
         triggerPhraseRecognitionEvent(soundTriggerCallbackCaptor.getValue(),
-                RecognitionStatus.SUCCESS, Optional.empty() /* keyphraseId */);
+                RecognitionStatus.SUCCESS);
 
         assertThat(
                 mLatencyTracker.getActiveActionStartTime(ACTION_SHOW_VOICE_INTERACTION)).isEqualTo(
@@ -170,19 +166,27 @@
     }
 
     private void triggerPhraseRecognitionEvent(ISoundTriggerCallback callback,
-            @RecognitionStatus int triggerEventStatus, Optional<Integer> optionalKeyphraseId)
-            throws RemoteException {
+            @RecognitionStatus int triggerEventStatus) throws RemoteException {
+        triggerPhraseRecognitionEvent(callback, triggerEventStatus, -1 /* keyphraseId */);
+    }
+
+    private void triggerPhraseRecognitionEvent(ISoundTriggerCallback callback,
+            @RecognitionStatus int triggerEventStatus, int keyphraseId) throws RemoteException {
         // trigger a phrase recognition to start a latency tracker session
         PhraseRecognitionEvent successEventWithKeyphraseId = new PhraseRecognitionEvent();
         successEventWithKeyphraseId.common = new RecognitionEvent();
         successEventWithKeyphraseId.common.status = triggerEventStatus;
-        if (optionalKeyphraseId.isPresent()) {
+        if (keyphraseId > 0) {
             PhraseRecognitionExtra recognitionExtra = new PhraseRecognitionExtra();
-            recognitionExtra.id = optionalKeyphraseId.get();
+            recognitionExtra.id = keyphraseId;
             successEventWithKeyphraseId.phraseExtras =
                     new PhraseRecognitionExtra[]{recognitionExtra};
         }
-        callback.onPhraseRecognition(0 /* modelHandle */, successEventWithKeyphraseId,
+        PhraseRecognitionEventSys phraseRecognitionEventSys = new PhraseRecognitionEventSys();
+        phraseRecognitionEventSys.phraseRecognitionEvent = successEventWithKeyphraseId;
+        phraseRecognitionEventSys.halEventReceivedMillis = 12345;
+        callback.onPhraseRecognition(0 /* modelHandle */, phraseRecognitionEventSys,
                 0 /* captureSession */);
     }
+
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncherTest.java b/services/tests/wmtests/src/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncherTest.java
new file mode 100644
index 0000000..cc8dab9
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncherTest.java
@@ -0,0 +1,273 @@
+/*
+ * 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.server.wm;
+
+import static android.view.WindowManager.TRANSIT_CHANGE;
+
+import static com.android.server.wm.DeviceStateController.DeviceState.FOLDED;
+import static com.android.server.wm.DeviceStateController.DeviceState.HALF_FOLDED;
+import static com.android.server.wm.DeviceStateController.DeviceState.OPEN;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
+import android.window.TransitionRequestInfo.DisplayChange;
+
+import static com.android.internal.R.bool.config_unfoldTransitionEnabled;
+import static com.android.server.wm.DeviceStateController.DeviceState.REAR;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for the {@link WindowToken} class.
+ *
+ * Build/Install/Run:
+ * atest WmTests:PhysicalDisplaySwitchTransitionLauncherTest
+ */
+@SmallTest
+@Presubmit
+@RunWith(WindowTestRunner.class)
+public class PhysicalDisplaySwitchTransitionLauncherTest extends WindowTestsBase {
+
+    @Mock
+    DisplayContent mDisplayContent;
+    @Mock
+    Context mContext;
+    @Mock
+    Resources mResources;
+    @Mock
+    ActivityTaskManagerService mActivityTaskManagerService;
+    @Mock
+    TransitionController mTransitionController;
+
+    private PhysicalDisplaySwitchTransitionLauncher mTarget;
+    private float mOriginalAnimationScale;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        when(mContext.getResources()).thenReturn(mResources);
+        mTarget = new PhysicalDisplaySwitchTransitionLauncher(mDisplayContent,
+                mActivityTaskManagerService, mContext, mTransitionController);
+        mOriginalAnimationScale = ValueAnimator.getDurationScale();
+    }
+
+    @After
+    public void after() {
+        ValueAnimator.setDurationScale(mOriginalAnimationScale);
+    }
+
+    @Test
+    public void testDisplaySwitchAfterUnfoldToOpen_animationsEnabled_requestsTransition() {
+        givenAllAnimationsEnabled();
+        mTarget.foldStateChanged(FOLDED);
+
+        mTarget.foldStateChanged(OPEN);
+        mTarget.requestDisplaySwitchTransitionIfNeeded(
+                /* displayId= */ 123,
+                /* oldDisplayWidth= */ 100,
+                /* oldDisplayHeight= */ 150,
+                /* newDisplayWidth= */ 200,
+                /* newDisplayHeight= */ 250
+        );
+
+        ArgumentCaptor<DisplayChange> displayChangeArgumentCaptor =
+                ArgumentCaptor.forClass(DisplayChange.class);
+        verify(mTransitionController).requestTransitionIfNeeded(eq(TRANSIT_CHANGE), /* flags= */
+                eq(0), eq(mDisplayContent), eq(mDisplayContent), /* remoteTransition= */ isNull(),
+                displayChangeArgumentCaptor.capture());
+        assertThat(displayChangeArgumentCaptor.getValue().getDisplayId()).isEqualTo(123);
+        assertThat(displayChangeArgumentCaptor.getValue().getStartAbsBounds()).isEqualTo(
+                new Rect(0, 0, 100, 150));
+        assertThat(displayChangeArgumentCaptor.getValue().getEndAbsBounds()).isEqualTo(
+                new Rect(0, 0, 200, 250));
+    }
+
+    @Test
+    public void testDisplaySwitchAfterFolding_animationEnabled_doesNotRequestTransition() {
+        givenAllAnimationsEnabled();
+        mTarget.foldStateChanged(OPEN);
+
+        mTarget.foldStateChanged(FOLDED);
+        requestDisplaySwitch();
+
+        assertTransitionNotRequested();
+    }
+
+    @Test
+    public void testDisplaySwitchAfterUnfoldingToHalf_animationEnabled_requestsTransition() {
+        givenAllAnimationsEnabled();
+        mTarget.foldStateChanged(FOLDED);
+
+        mTarget.foldStateChanged(HALF_FOLDED);
+        requestDisplaySwitch();
+
+        assertTransitionRequested();
+    }
+
+    @Test
+    public void testDisplaySwitchSecondTimeAfterUnfolding_animationEnabled_noTransition() {
+        givenAllAnimationsEnabled();
+        mTarget.foldStateChanged(FOLDED);
+        mTarget.foldStateChanged(OPEN);
+        requestDisplaySwitch();
+        clearInvocations(mTransitionController);
+
+        requestDisplaySwitch();
+
+        assertTransitionNotRequested();
+    }
+
+
+    @Test
+    public void testDisplaySwitchAfterGoingToRearAndBack_animationEnabled_noTransition() {
+        givenAllAnimationsEnabled();
+        mTarget.foldStateChanged(OPEN);
+
+        mTarget.foldStateChanged(REAR);
+        mTarget.foldStateChanged(OPEN);
+        requestDisplaySwitch();
+
+        assertTransitionNotRequested();
+    }
+
+    @Test
+    public void testDisplaySwitchAfterUnfoldingAndFolding_animationEnabled_noTransition() {
+        givenAllAnimationsEnabled();
+        mTarget.foldStateChanged(FOLDED);
+        mTarget.foldStateChanged(OPEN);
+        // No request display switch event (simulate very fast fold after unfold, even before
+        // the displays switched)
+        mTarget.foldStateChanged(FOLDED);
+
+        requestDisplaySwitch();
+
+        assertTransitionNotRequested();
+    }
+
+    @Test
+    public void testDisplaySwitch_whenShellTransitionsNotEnabled_noTransition() {
+        givenAllAnimationsEnabled();
+        givenShellTransitionsEnabled(false);
+        mTarget.foldStateChanged(FOLDED);
+
+        mTarget.foldStateChanged(OPEN);
+        requestDisplaySwitch();
+
+        assertTransitionNotRequested();
+    }
+
+    @Test
+    public void testDisplaySwitch_whenAnimationsDisabled_noTransition() {
+        givenAllAnimationsEnabled();
+        givenAnimationsEnabled(false);
+        mTarget.foldStateChanged(FOLDED);
+
+        mTarget.foldStateChanged(OPEN);
+        requestDisplaySwitch();
+
+        assertTransitionNotRequested();
+    }
+
+    @Test
+    public void testDisplaySwitch_whenUnfoldAnimationDisabled_noTransition() {
+        givenAllAnimationsEnabled();
+        givenUnfoldTransitionEnabled(false);
+        mTarget.foldStateChanged(FOLDED);
+
+        mTarget.foldStateChanged(OPEN);
+        requestDisplaySwitch();
+
+        assertTransitionNotRequested();
+    }
+
+    @Test
+    public void testDisplaySwitch_whenNoContentInDisplayContent_noTransition() {
+        givenAllAnimationsEnabled();
+        givenDisplayContentHasContent(false);
+        mTarget.foldStateChanged(FOLDED);
+
+        mTarget.foldStateChanged(OPEN);
+        requestDisplaySwitch();
+
+        assertTransitionNotRequested();
+    }
+
+    private void assertTransitionRequested() {
+        verify(mTransitionController).requestTransitionIfNeeded(anyInt(), anyInt(), any(), any(),
+                any(), any());
+    }
+
+    private void assertTransitionNotRequested() {
+        verify(mTransitionController, never()).requestTransitionIfNeeded(anyInt(), anyInt(), any(),
+                any(), any(), any());
+    }
+
+    private void requestDisplaySwitch() {
+        mTarget.requestDisplaySwitchTransitionIfNeeded(
+                /* displayId= */ 123,
+                /* oldDisplayWidth= */ 100,
+                /* oldDisplayHeight= */ 150,
+                /* newDisplayWidth= */ 200,
+                /* newDisplayHeight= */ 250
+        );
+    }
+
+    private void givenAllAnimationsEnabled() {
+        givenAnimationsEnabled(true);
+        givenUnfoldTransitionEnabled(true);
+        givenShellTransitionsEnabled(true);
+        givenDisplayContentHasContent(true);
+    }
+
+    private void givenUnfoldTransitionEnabled(boolean enabled) {
+        when(mResources.getBoolean(config_unfoldTransitionEnabled)).thenReturn(enabled);
+    }
+
+    private void givenAnimationsEnabled(boolean enabled) {
+        ValueAnimator.setDurationScale(enabled ? 1.0f : 0.0f);
+    }
+
+    private void givenShellTransitionsEnabled(boolean enabled) {
+        when(mTransitionController.isShellTransitionsEnabled()).thenReturn(enabled);
+    }
+
+    private void givenDisplayContentHasContent(boolean hasContent) {
+        when(mDisplayContent.getLastHasContent()).thenReturn(hasContent);
+    }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupTest.java
index c8fc6b8..d84620b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupTest.java
@@ -32,6 +32,7 @@
 
 import com.android.server.testutils.StubTransaction;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -52,6 +53,11 @@
         SurfaceSyncGroup.setTransactionFactory(StubTransaction::new);
     }
 
+    @After
+    public void tearDown() {
+        SurfaceSyncGroup.setTransactionFactory(SurfaceControl.Transaction::new);
+    }
+
     @Test
     public void testSyncOne() throws InterruptedException {
         final CountDownLatch finishedLatch = new CountDownLatch(1);
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/AidlUtil.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/AidlUtil.java
index f3457f5..56a159e 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/AidlUtil.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/AidlUtil.java
@@ -21,6 +21,8 @@
 import android.media.soundtrigger.RecognitionEvent;
 import android.media.soundtrigger.RecognitionStatus;
 import android.media.soundtrigger.SoundModelType;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
 
 /**
  * Utilities for working with sound trigger related AIDL generated types.
@@ -49,23 +51,29 @@
 
     /**
      * Creates a new generic abort event.
+     *
      * @return The new event.
      */
-    static RecognitionEvent newAbortEvent() {
-        RecognitionEvent event = newEmptyRecognitionEvent();
-        event.type = SoundModelType.GENERIC;
-        event.status = RecognitionStatus.ABORTED;
-        return event;
+    static RecognitionEventSys newAbortEvent() {
+        RecognitionEvent recognitionEvent = newEmptyRecognitionEvent();
+        recognitionEvent.type = SoundModelType.GENERIC;
+        recognitionEvent.status = RecognitionStatus.ABORTED;
+        RecognitionEventSys recognitionEventSys = new RecognitionEventSys();
+        recognitionEventSys.recognitionEvent = recognitionEvent;
+        return recognitionEventSys;
     }
 
     /**
      * Creates a new generic phrase event.
+     *
      * @return The new event.
      */
-    static PhraseRecognitionEvent newAbortPhraseEvent() {
-        PhraseRecognitionEvent event = newEmptyPhraseRecognitionEvent();
-        event.common.type = SoundModelType.KEYPHRASE;
-        event.common.status = RecognitionStatus.ABORTED;
-        return event;
+    static PhraseRecognitionEventSys newAbortPhraseEvent() {
+        PhraseRecognitionEvent recognitionEvent = newEmptyPhraseRecognitionEvent();
+        recognitionEvent.common.type = SoundModelType.KEYPHRASE;
+        recognitionEvent.common.status = RecognitionStatus.ABORTED;
+        PhraseRecognitionEventSys phraseRecognitionEventSys = new PhraseRecognitionEventSys();
+        phraseRecognitionEventSys.phraseRecognitionEvent = recognitionEvent;
+        return phraseRecognitionEventSys;
     }
 }
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ISoundTriggerHal.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ISoundTriggerHal.java
index 75206e6..6f4a946 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ISoundTriggerHal.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/ISoundTriggerHal.java
@@ -20,12 +20,12 @@
 import android.hardware.soundtrigger3.ISoundTriggerHwCallback;
 import android.hardware.soundtrigger3.ISoundTriggerHwGlobalCallback;
 import android.media.soundtrigger.ModelParameterRange;
-import android.media.soundtrigger.PhraseRecognitionEvent;
 import android.media.soundtrigger.PhraseSoundModel;
 import android.media.soundtrigger.Properties;
 import android.media.soundtrigger.RecognitionConfig;
-import android.media.soundtrigger.RecognitionEvent;
 import android.media.soundtrigger.SoundModel;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
 import android.os.IBinder;
 
 /**
@@ -173,14 +173,19 @@
      */
     interface ModelCallback {
         /**
-         * @see ISoundTriggerHwCallback#recognitionCallback(int, RecognitionEvent)
+         * Decorated callback of
+         * {@link ISoundTriggerHwCallback#recognitionCallback(int, RecognitionEvent)} where
+         * {@link RecognitionEventSys} is decorating the returned {@link RecognitionEvent}
          */
-        void recognitionCallback(int modelHandle, RecognitionEvent event);
+        void recognitionCallback(int modelHandle, RecognitionEventSys event);
 
         /**
-         * @see ISoundTriggerHwCallback#phraseRecognitionCallback(int, PhraseRecognitionEvent)
+         * Decorated callback of
+         * {@link ISoundTriggerHwCallback#phraseRecognitionCallback(int, PhraseRecognitionEvent)}
+         * where {@link PhraseRecognitionEventSys} is decorating the returned
+         * {@link PhraseRecognitionEvent}
          */
-        void phraseRecognitionCallback(int modelHandle, PhraseRecognitionEvent event);
+        void phraseRecognitionCallback(int modelHandle, PhraseRecognitionEventSys event);
 
         /**
          * @see ISoundTriggerHwCallback#modelUnloaded(int)
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java
index 8c7cabe..d8ef2b6 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java
@@ -19,14 +19,14 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.media.soundtrigger.ModelParameterRange;
-import android.media.soundtrigger.PhraseRecognitionEvent;
 import android.media.soundtrigger.PhraseSoundModel;
 import android.media.soundtrigger.Properties;
 import android.media.soundtrigger.RecognitionConfig;
-import android.media.soundtrigger.RecognitionEvent;
 import android.media.soundtrigger.SoundModel;
 import android.media.soundtrigger.SoundModelType;
 import android.media.soundtrigger.Status;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
 import android.os.IBinder;
 
 import java.util.HashSet;
@@ -238,13 +238,13 @@
         }
 
         @Override
-        public void recognitionCallback(int modelHandle, RecognitionEvent event) {
+        public void recognitionCallback(int modelHandle, RecognitionEventSys event) {
             synchronized (mActiveModels) {
                 if (!mActiveModels.contains(modelHandle)) {
                     // Discard the event.
                     return;
                 }
-                if (!event.recognitionStillActive) {
+                if (!event.recognitionEvent.recognitionStillActive) {
                     mActiveModels.remove(modelHandle);
                 }
                 // A recognition event must be the last one for its model, unless it indicates that
@@ -255,13 +255,13 @@
         }
 
         @Override
-        public void phraseRecognitionCallback(int modelHandle, PhraseRecognitionEvent event) {
+        public void phraseRecognitionCallback(int modelHandle, PhraseRecognitionEventSys event) {
             synchronized (mActiveModels) {
                 if (!mActiveModels.contains(modelHandle)) {
                     // Discard the event.
                     return;
                 }
-                if (!event.common.recognitionStillActive) {
+                if (!event.phraseRecognitionEvent.common.recognitionStillActive) {
                     mActiveModels.remove(modelHandle);
                 }
                 // A recognition event must be the last one for its model, unless it indicates that
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalEnforcer.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalEnforcer.java
index 24741e1..bac2466 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalEnforcer.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHalEnforcer.java
@@ -17,14 +17,14 @@
 package com.android.server.soundtrigger_middleware;
 
 import android.media.soundtrigger.ModelParameterRange;
-import android.media.soundtrigger.PhraseRecognitionEvent;
 import android.media.soundtrigger.PhraseSoundModel;
 import android.media.soundtrigger.Properties;
 import android.media.soundtrigger.RecognitionConfig;
-import android.media.soundtrigger.RecognitionEvent;
 import android.media.soundtrigger.RecognitionStatus;
 import android.media.soundtrigger.SoundModel;
 import android.media.soundtrigger.Status;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
 import android.os.DeadObjectException;
 import android.os.IBinder;
 import android.util.Log;
@@ -253,7 +253,7 @@
         }
 
         @Override
-        public void recognitionCallback(int model, RecognitionEvent event) {
+        public void recognitionCallback(int model, RecognitionEventSys event) {
             synchronized (mModelStates) {
                 ModelState state = mModelStates.get(model);
                 if (state == null || state == ModelState.INACTIVE) {
@@ -261,15 +261,16 @@
                     reboot();
                     return;
                 }
-                if (event.recognitionStillActive && event.status != RecognitionStatus.SUCCESS
-                        && event.status != RecognitionStatus.FORCED) {
+                if (event.recognitionEvent.recognitionStillActive
+                        && event.recognitionEvent.status != RecognitionStatus.SUCCESS
+                        && event.recognitionEvent.status != RecognitionStatus.FORCED) {
                     Log.wtfStack(TAG,
                             "recognitionStillActive is only allowed when the recognition status "
                                     + "is SUCCESS");
                     reboot();
                     return;
                 }
-                if (!event.recognitionStillActive) {
+                if (!event.recognitionEvent.recognitionStillActive) {
                     mModelStates.replace(model, ModelState.INACTIVE);
                 }
             }
@@ -278,7 +279,7 @@
         }
 
         @Override
-        public void phraseRecognitionCallback(int model, PhraseRecognitionEvent event) {
+        public void phraseRecognitionCallback(int model, PhraseRecognitionEventSys event) {
             synchronized (mModelStates) {
                 ModelState state = mModelStates.get(model);
                 if (state == null || state == ModelState.INACTIVE) {
@@ -286,16 +287,16 @@
                     reboot();
                     return;
                 }
-                if (event.common.recognitionStillActive
-                        && event.common.status != RecognitionStatus.SUCCESS
-                        && event.common.status != RecognitionStatus.FORCED) {
+                if (event.phraseRecognitionEvent.common.recognitionStillActive
+                        && event.phraseRecognitionEvent.common.status != RecognitionStatus.SUCCESS
+                        && event.phraseRecognitionEvent.common.status != RecognitionStatus.FORCED) {
                     Log.wtfStack(TAG,
                             "recognitionStillActive is only allowed when the recognition status "
                                     + "is SUCCESS");
                     reboot();
                     return;
                 }
-                if (!event.common.recognitionStillActive) {
+                if (!event.phraseRecognitionEvent.common.recognitionStillActive) {
                     mModelStates.replace(model, ModelState.INACTIVE);
                 }
             }
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java
index c67bdd7..df2e9b4 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Compat.java
@@ -25,9 +25,12 @@
 import android.media.soundtrigger.RecognitionConfig;
 import android.media.soundtrigger.SoundModel;
 import android.media.soundtrigger.Status;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
 import android.os.IBinder;
 import android.os.IHwBinder;
 import android.os.RemoteException;
+import android.os.SystemClock;
 import android.system.OsConstants;
 import android.util.Log;
 
@@ -570,16 +573,20 @@
         public void recognitionCallback_2_1(
                 android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.RecognitionEvent event,
                 int cookie) {
-            mDelegate.recognitionCallback(event.header.model,
-                    ConversionUtil.hidl2aidlRecognitionEvent(event));
+            RecognitionEventSys eventSys = new RecognitionEventSys();
+            eventSys.recognitionEvent = ConversionUtil.hidl2aidlRecognitionEvent(event);
+            eventSys.halEventReceivedMillis = SystemClock.elapsedRealtime();
+            mDelegate.recognitionCallback(event.header.model, eventSys);
         }
 
         @Override
         public void phraseRecognitionCallback_2_1(
                 android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback.PhraseRecognitionEvent event,
                 int cookie) {
-            mDelegate.phraseRecognitionCallback(event.common.header.model,
-                    ConversionUtil.hidl2aidlPhraseRecognitionEvent(event));
+            PhraseRecognitionEventSys eventSys = new PhraseRecognitionEventSys();
+            eventSys.phraseRecognitionEvent = ConversionUtil.hidl2aidlPhraseRecognitionEvent(event);
+            eventSys.halEventReceivedMillis = SystemClock.elapsedRealtime();
+            mDelegate.phraseRecognitionCallback(event.common.header.model, eventSys);
         }
 
         @Override
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHw3Compat.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHw3Compat.java
index 8bb5eb1..b1165bb 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHw3Compat.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerHw3Compat.java
@@ -29,9 +29,12 @@
 import android.media.soundtrigger.RecognitionStatus;
 import android.media.soundtrigger.SoundModel;
 import android.media.soundtrigger.Status;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
+import android.os.SystemClock;
 
 public class SoundTriggerHw3Compat implements ISoundTriggerHal {
     private final @NonNull ISoundTriggerHw mDriver;
@@ -244,14 +247,20 @@
         public void phraseRecognitionCallback(int model, PhraseRecognitionEvent event) {
             // A FORCED status implies that recognition is still active after the event.
             event.common.recognitionStillActive |= event.common.status == RecognitionStatus.FORCED;
-            mDelegate.phraseRecognitionCallback(model, event);
+            PhraseRecognitionEventSys phraseRecognitionEventSys = new PhraseRecognitionEventSys();
+            phraseRecognitionEventSys.phraseRecognitionEvent = event;
+            phraseRecognitionEventSys.halEventReceivedMillis = SystemClock.elapsedRealtimeNanos();
+            mDelegate.phraseRecognitionCallback(model, phraseRecognitionEventSys);
         }
 
         @Override
         public void recognitionCallback(int model, RecognitionEvent event) {
             // A FORCED status implies that recognition is still active after the event.
             event.recognitionStillActive |= event.status == RecognitionStatus.FORCED;
-            mDelegate.recognitionCallback(model, event);
+            RecognitionEventSys recognitionEventSys = new RecognitionEventSys();
+            recognitionEventSys.recognitionEvent = event;
+            recognitionEventSys.halEventReceivedMillis = SystemClock.elapsedRealtimeNanos();
+            mDelegate.recognitionCallback(model, recognitionEventSys);
         }
 
         @Override
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
index 0e796d1..2ee4e3c 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java
@@ -16,12 +16,24 @@
 
 package com.android.server.soundtrigger_middleware;
 
-import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.*;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.DETACH;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.FORCE_RECOGNITION;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.GET_MODEL_PARAMETER;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.LOAD_MODEL;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.LOAD_PHRASE_MODEL;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.MODEL_UNLOADED;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.MODULE_DIED;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.QUERY_MODEL_PARAMETER;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.RECOGNITION;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.RESOURCES_AVAILABLE;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.SET_MODEL_PARAMETER;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.START_RECOGNITION;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.STOP_RECOGNITION;
+import static com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareLogging.SessionEvent.Type.UNLOAD_MODEL;
 import static com.android.server.utils.EventLogger.Event.ALOGI;
 import static com.android.server.utils.EventLogger.Event.ALOGW;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.content.Context;
 import android.media.permission.Identity;
 import android.media.permission.IdentityContext;
@@ -29,11 +41,12 @@
 import android.media.soundtrigger.PhraseRecognitionEvent;
 import android.media.soundtrigger.PhraseSoundModel;
 import android.media.soundtrigger.RecognitionConfig;
-import android.media.soundtrigger.RecognitionEvent;
 import android.media.soundtrigger.RecognitionStatus;
 import android.media.soundtrigger.SoundModel;
 import android.media.soundtrigger_middleware.ISoundTriggerCallback;
 import android.media.soundtrigger_middleware.ISoundTriggerModule;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
 import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
 import android.os.BatteryStatsInternal;
 import android.os.IBinder;
@@ -45,19 +58,18 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.LatencyTracker;
 import com.android.server.LocalServices;
-import com.android.server.utils.EventLogger.Event;
 import com.android.server.utils.EventLogger;
-
+import com.android.server.utils.EventLogger.Event;
 
 import java.io.PrintWriter;
 import java.util.Arrays;
+import java.util.Deque;
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.LinkedBlockingDeque;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Supplier;
-import java.util.Deque;
 
 
 /**
@@ -370,7 +382,7 @@
         }
 
         @Override
-        public void onRecognition(int modelHandle, RecognitionEvent event, int captureSession)
+        public void onRecognition(int modelHandle, RecognitionEventSys event, int captureSession)
                 throws RemoteException {
             try {
                 mBatteryStatsInternalSupplier.get().noteWakingSoundTrigger(
@@ -388,13 +400,13 @@
         }
 
         @Override
-        public void onPhraseRecognition(int modelHandle, PhraseRecognitionEvent event,
+        public void onPhraseRecognition(int modelHandle, PhraseRecognitionEventSys event,
                 int captureSession)
                 throws RemoteException {
             try {
                 mBatteryStatsInternalSupplier.get().noteWakingSoundTrigger(
                         SystemClock.elapsedRealtime(), mOriginatorIdentity.uid);
-                startKeyphraseEventLatencyTracking(event);
+                startKeyphraseEventLatencyTracking(event.phraseRecognitionEvent);
                 mCallbackDelegate.onPhraseRecognition(modelHandle, event, captureSession);
                 mEventLogger.enqueue(SessionEvent.createForVoid(
                             RECOGNITION, modelHandle, event, captureSession)
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
index 00cedd7..00b894e 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
@@ -27,15 +27,15 @@
 import android.media.permission.IdentityContext;
 import android.media.permission.PermissionUtil;
 import android.media.soundtrigger.ModelParameterRange;
-import android.media.soundtrigger.PhraseRecognitionEvent;
 import android.media.soundtrigger.PhraseSoundModel;
 import android.media.soundtrigger.RecognitionConfig;
-import android.media.soundtrigger.RecognitionEvent;
 import android.media.soundtrigger.SoundModel;
 import android.media.soundtrigger.Status;
 import android.media.soundtrigger_middleware.ISoundTriggerCallback;
 import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService;
 import android.media.soundtrigger_middleware.ISoundTriggerModule;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
 import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -307,16 +307,15 @@
             }
 
             @Override
-            public void onRecognition(int modelHandle, RecognitionEvent event, int captureSession)
-                    throws RemoteException {
+            public void onRecognition(int modelHandle, RecognitionEventSys event,
+                    int captureSession) throws RemoteException {
                 enforcePermissions("Sound trigger recognition.");
                 mDelegate.onRecognition(modelHandle, event, captureSession);
             }
 
             @Override
-            public void onPhraseRecognition(int modelHandle, PhraseRecognitionEvent event,
-                    int captureSession)
-                    throws RemoteException {
+            public void onPhraseRecognition(int modelHandle, PhraseRecognitionEventSys event,
+                    int captureSession) throws RemoteException {
                 enforcePermissions("Sound trigger phrase recognition.");
                 mDelegate.onPhraseRecognition(modelHandle, event, captureSession);
             }
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
index 15c9ba9..f208c03 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
@@ -21,17 +21,17 @@
 import android.media.permission.Identity;
 import android.media.permission.IdentityContext;
 import android.media.soundtrigger.ModelParameterRange;
-import android.media.soundtrigger.PhraseRecognitionEvent;
 import android.media.soundtrigger.PhraseSoundModel;
 import android.media.soundtrigger.Properties;
 import android.media.soundtrigger.RecognitionConfig;
-import android.media.soundtrigger.RecognitionEvent;
 import android.media.soundtrigger.RecognitionStatus;
 import android.media.soundtrigger.SoundModel;
 import android.media.soundtrigger.Status;
 import android.media.soundtrigger_middleware.ISoundTriggerCallback;
 import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService;
 import android.media.soundtrigger_middleware.ISoundTriggerModule;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
 import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -710,8 +710,7 @@
             }
         }
 
-        class CallbackWrapper implements ISoundTriggerCallback,
-                IBinder.DeathRecipient {
+        class CallbackWrapper implements ISoundTriggerCallback, IBinder.DeathRecipient {
             private final ISoundTriggerCallback mCallback;
 
             CallbackWrapper(ISoundTriggerCallback callback) {
@@ -728,11 +727,11 @@
             }
 
             @Override
-            public void onRecognition(int modelHandle, @NonNull RecognitionEvent event,
+            public void onRecognition(int modelHandle, @NonNull RecognitionEventSys event,
                     int captureSession) {
                 synchronized (SoundTriggerMiddlewareValidation.this) {
                     ModelState modelState = mLoadedModels.get(modelHandle);
-                    if (!event.recognitionStillActive) {
+                    if (!event.recognitionEvent.recognitionStillActive) {
                         modelState.activityState = ModelState.Activity.LOADED;
                     }
                 }
@@ -744,7 +743,7 @@
                     Log.w(TAG, "Client callback exception.", e);
                     synchronized (SoundTriggerMiddlewareValidation.this) {
                         ModelState modelState = mLoadedModels.get(modelHandle);
-                        if (event.status != RecognitionStatus.FORCED) {
+                        if (event.recognitionEvent.status != RecognitionStatus.FORCED) {
                             modelState.activityState = ModelState.Activity.INTERCEPTED;
                             // If we failed to deliver an actual event to the client, they would
                             // never know to restart it whenever circumstances change. Thus, we
@@ -758,10 +757,10 @@
 
             @Override
             public void onPhraseRecognition(int modelHandle,
-                    @NonNull PhraseRecognitionEvent event, int captureSession) {
+                    @NonNull PhraseRecognitionEventSys event, int captureSession) {
                 synchronized (SoundTriggerMiddlewareValidation.this) {
                     ModelState modelState = mLoadedModels.get(modelHandle);
-                    if (!event.common.recognitionStillActive) {
+                    if (!event.phraseRecognitionEvent.common.recognitionStillActive) {
                         modelState.activityState = ModelState.Activity.LOADED;
                     }
                 }
@@ -773,7 +772,7 @@
                     Log.w(TAG, "Client callback exception.", e);
                     synchronized (SoundTriggerMiddlewareValidation.this) {
                         ModelState modelState = mLoadedModels.get(modelHandle);
-                        if (!event.common.recognitionStillActive) {
+                        if (!event.phraseRecognitionEvent.common.recognitionStillActive) {
                             modelState.activityState = ModelState.Activity.INTERCEPTED;
                             // If we failed to deliver an actual event to the client, they would
                             // never know to restart it whenever circumstances change. Thus, we
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
index 6223b2e..84cec55 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
@@ -19,16 +19,16 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.media.soundtrigger.ModelParameterRange;
-import android.media.soundtrigger.PhraseRecognitionEvent;
 import android.media.soundtrigger.PhraseSoundModel;
 import android.media.soundtrigger.Properties;
 import android.media.soundtrigger.RecognitionConfig;
-import android.media.soundtrigger.RecognitionEvent;
 import android.media.soundtrigger.SoundModel;
 import android.media.soundtrigger.SoundModelType;
 import android.media.soundtrigger.Status;
 import android.media.soundtrigger_middleware.ISoundTriggerCallback;
 import android.media.soundtrigger_middleware.ISoundTriggerModule;
+import android.media.soundtrigger_middleware.PhraseRecognitionEventSys;
+import android.media.soundtrigger_middleware.RecognitionEventSys;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -499,10 +499,10 @@
 
             @Override
             public void recognitionCallback(int modelHandle,
-                    @NonNull RecognitionEvent recognitionEvent) {
+                    @NonNull RecognitionEventSys event) {
                 ISoundTriggerCallback callback;
                 synchronized (SoundTriggerModule.this) {
-                    if (!recognitionEvent.recognitionStillActive) {
+                    if (!event.recognitionEvent.recognitionStillActive) {
                         setState(ModelState.LOADED);
                     }
                     callback = mCallback;
@@ -510,7 +510,7 @@
                 // The callback must be invoked outside of the lock.
                 try {
                     if (callback != null) {
-                        callback.onRecognition(mHandle, recognitionEvent, mSession.mSessionHandle);
+                        callback.onRecognition(mHandle, event, mSession.mSessionHandle);
                     }
                 } catch (RemoteException e) {
                     // We're not expecting any exceptions here.
@@ -520,10 +520,10 @@
 
             @Override
             public void phraseRecognitionCallback(int modelHandle,
-                    @NonNull PhraseRecognitionEvent phraseRecognitionEvent) {
+                    @NonNull PhraseRecognitionEventSys event) {
                 ISoundTriggerCallback callback;
                 synchronized (SoundTriggerModule.this) {
-                    if (!phraseRecognitionEvent.common.recognitionStillActive) {
+                    if (!event.phraseRecognitionEvent.common.recognitionStillActive) {
                         setState(ModelState.LOADED);
                     }
                     callback = mCallback;
@@ -532,8 +532,7 @@
                 // The callback must be invoked outside of the lock.
                 try {
                     if (callback != null) {
-                        mCallback.onPhraseRecognition(mHandle, phraseRecognitionEvent,
-                                mSession.mSessionHandle);
+                        mCallback.onPhraseRecognition(mHandle, event, mSession.mSessionHandle);
                     }
                 } catch (RemoteException e) {
                     // We're not expecting any exceptions here.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
index 6053f1d..daecfe7 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
@@ -17,8 +17,8 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
+import android.tools.common.PlatformConsts
 import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.common.traces.wm.WindowManagerState.Companion.STATE_RESUMED
 import android.tools.device.apphelpers.StandardAppHelper
 import android.tools.device.helpers.FIND_TIMEOUT
 import android.tools.device.traces.parsers.WindowManagerStateHelper
@@ -54,8 +54,8 @@
         launchButton.click()
         wmHelper
             .StateSyncBuilder()
-            .withActivityState(SECONDARY_ACTIVITY_COMPONENT, STATE_RESUMED)
-            .withActivityState(MAIN_ACTIVITY_COMPONENT, STATE_RESUMED)
+            .withActivityState(SECONDARY_ACTIVITY_COMPONENT, PlatformConsts.STATE_RESUMED)
+            .withActivityState(MAIN_ACTIVITY_COMPONENT, PlatformConsts.STATE_RESUMED)
             .waitForAndVerify()
     }
 
@@ -73,8 +73,8 @@
         launchButton.click()
         wmHelper
             .StateSyncBuilder()
-            .withActivityState(PLACEHOLDER_PRIMARY_COMPONENT, STATE_RESUMED)
-            .withActivityState(PLACEHOLDER_SECONDARY_COMPONENT, STATE_RESUMED)
+            .withActivityState(PLACEHOLDER_PRIMARY_COMPONENT, PlatformConsts.STATE_RESUMED)
+            .withActivityState(PLACEHOLDER_SECONDARY_COMPONENT, PlatformConsts.STATE_RESUMED)
             .waitForAndVerify()
     }
 
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIcon.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIcon.kt
index a658293..3a80c66 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIcon.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIcon.kt
@@ -16,6 +16,7 @@
 
 package com.android.server.wm.flicker.launch
 
+import android.platform.test.annotations.FlakyTest
 import android.tools.common.Rotation
 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.device.flicker.legacy.FlickerBuilder
@@ -24,6 +25,7 @@
 import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule
 import androidx.test.filters.RequiresDevice
 import org.junit.FixMethodOrder
+import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
 import org.junit.runners.Parameterized
@@ -76,6 +78,131 @@
             teardown { testApp.exit(wmHelper) }
         }
 
+    @FlakyTest(bugId = 240916028)
+    @Test
+    override fun focusChanges() {
+        super.focusChanges()
+    }
+
+    @FlakyTest(bugId = 240916028)
+    @Test
+    override fun appWindowReplacesLauncherAsTopWindow() {
+        super.appWindowReplacesLauncherAsTopWindow()
+    }
+    @FlakyTest(bugId = 240916028)
+    @Test
+    override fun appWindowAsTopWindowAtEnd() {
+        super.appWindowAsTopWindowAtEnd()
+    }
+
+    @FlakyTest(bugId = 240916028)
+    @Test
+    override fun appWindowBecomesTopWindow() {
+        super.appWindowBecomesTopWindow()
+    }
+
+    @FlakyTest(bugId = 240916028)
+    @Test
+    override fun appWindowBecomesVisible() {
+        super.appWindowBecomesVisible()
+    }
+
+    @FlakyTest(bugId = 240916028)
+    @Test
+    override fun appWindowIsTopWindowAtEnd() {
+        super.appWindowIsTopWindowAtEnd()
+    }
+
+    @FlakyTest(bugId = 240916028)
+    @Test
+    override fun appLayerBecomesVisible() {
+        super.appLayerBecomesVisible()
+    }
+
+    @FlakyTest(bugId = 240916028)
+    @Test
+    override fun appLayerReplacesLauncher() {
+        super.appLayerReplacesLauncher()
+    }
+
+    @FlakyTest(bugId = 240916028)
+    @Test
+    override fun cujCompleted() {
+        super.cujCompleted()
+    }
+
+    @FlakyTest(bugId = 240916028)
+    @Test
+    override fun entireScreenCovered() {
+        super.entireScreenCovered()
+    }
+
+    @FlakyTest(bugId = 240916028)
+    @Test
+    override fun navBarLayerIsVisibleAtStartAndEnd() {
+        super.navBarLayerIsVisibleAtStartAndEnd()
+    }
+
+    @FlakyTest(bugId = 240916028)
+    @Test
+    override fun navBarLayerPositionAtStartAndEnd() {
+        super.navBarLayerPositionAtStartAndEnd()
+    }
+
+    @FlakyTest(bugId = 240916028)
+    @Test
+    override fun navBarWindowIsAlwaysVisible() {
+        super.navBarWindowIsAlwaysVisible()
+    }
+
+    @FlakyTest(bugId = 240916028)
+    @Test
+    override fun navBarWindowIsVisibleAtStartAndEnd() {
+        super.navBarWindowIsVisibleAtStartAndEnd()
+    }
+
+    @FlakyTest(bugId = 240916028)
+    @Test
+    override fun statusBarLayerIsVisibleAtStartAndEnd() {
+        super.statusBarLayerIsVisibleAtStartAndEnd()
+    }
+
+    @FlakyTest(bugId = 240916028)
+    @Test
+    override fun statusBarLayerPositionAtStartAndEnd() {
+        super.statusBarLayerPositionAtStartAndEnd()
+    }
+
+    @FlakyTest(bugId = 240916028)
+    @Test
+    override fun statusBarWindowIsAlwaysVisible() {
+        super.statusBarWindowIsAlwaysVisible()
+    }
+
+    @FlakyTest(bugId = 240916028)
+    @Test
+    override fun taskBarLayerIsVisibleAtStartAndEnd() {
+        super.taskBarLayerIsVisibleAtStartAndEnd()
+    }
+
+    @FlakyTest(bugId = 240916028)
+    @Test
+    override fun taskBarWindowIsAlwaysVisible() {
+        super.taskBarWindowIsAlwaysVisible()
+    }
+
+    @FlakyTest(bugId = 240916028)
+    @Test
+    override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+        super.visibleLayersShownMoreThanOneConsecutiveEntry()
+    }
+
+    @FlakyTest(bugId = 240916028)
+    @Test
+    override fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
+        super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+    }
+
     companion object {
         /**
          * Creates the test configurations.
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorBitmapActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorBitmapActivity.java
index 017de60..e2d17cd 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorBitmapActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorBitmapActivity.java
@@ -26,39 +26,57 @@
 import android.graphics.PixelFormat;
 import android.graphics.RenderNode;
 import android.graphics.Shader;
+import android.graphics.SurfaceTexture;
 import android.hardware.HardwareBuffer;
 import android.media.Image;
 import android.media.ImageWriter;
 import android.os.Bundle;
+import android.view.Surface;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
+import android.view.TextureView;
 import android.view.View;
 import android.widget.AdapterView;
 import android.widget.ArrayAdapter;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.Spinner;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
 
 import java.time.Duration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.FutureTask;
 
 @SuppressWarnings({"UnusedDeclaration"})
 public class ColorBitmapActivity extends Activity implements SurfaceHolder.Callback,
-        AdapterView.OnItemSelectedListener {
+        TextureView.SurfaceTextureListener {
 
     private static final int WIDTH = 512;
     private static final int HEIGHT = 512;
 
     private ImageView mImageView;
     private SurfaceView mSurfaceView;
+    private TextureView mTextureView;
     private HardwareBuffer mGradientBuffer;
-    private ImageWriter mImageWriter;
+    private Map<View, ImageWriter> mImageWriters = new HashMap<>();
     private ColorSpace mColorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
     private String[] mColorNames = {"sRGB", "BT2020_HLG", "BT2020_PQ"};
-    private String mCurrentColorName = "sRGB";
 
-    private FutureTask<HardwareBuffer> authorGradientBuffer(HardwareBuffer buffer) {
+    private int mGradientEndColor = 0xFFFFFFFF;
+
+    private int[] mGradientEndColors = {0xFFFFFFFF, 0xFFFF0000, 0xFF00FF00, 0xFF0000FF};
+    private String[] mGradientColorNames = {"Grayscale", "Red", "Green", "Blue"};
+
+    private final ExecutorService mBufferFenceExecutor = Executors.newFixedThreadPool(1);
+    private final ExecutorService mBufferExecutor = Executors.newFixedThreadPool(1);
+
+    private FutureTask<HardwareBuffer> authorGradientBuffer(
+            HardwareBuffer buffer, int gradentEndColor) {
         HardwareBufferRenderer renderer = new HardwareBufferRenderer(buffer);
         RenderNode node = new RenderNode("content");
         node.setPosition(0, 0, buffer.getWidth(), buffer.getHeight());
@@ -66,9 +84,10 @@
         Canvas canvas = node.beginRecording();
         LinearGradient gradient = new LinearGradient(
                 0, 0, buffer.getWidth(), buffer.getHeight(), 0xFF000000,
-                0xFFFFFFFF, Shader.TileMode.CLAMP);
+                gradentEndColor, Shader.TileMode.CLAMP);
         Paint paint = new Paint();
         paint.setShader(gradient);
+        paint.setDither(true);
         canvas.drawRect(0f, 0f, buffer.getWidth(), buffer.getHeight(), paint);
         node.endRecording();
 
@@ -78,7 +97,7 @@
         FutureTask<HardwareBuffer> resolvedBuffer = new FutureTask<>(() -> buffer);
         renderer.obtainRenderRequest()
                 .setColorSpace(colorSpace)
-                .draw(Executors.newSingleThreadExecutor(), result -> {
+                .draw(mBufferFenceExecutor, result -> {
                     result.getFence().await(Duration.ofSeconds(3));
                     resolvedBuffer.run();
                 });
@@ -90,7 +109,7 @@
                 WIDTH, HEIGHT, PixelFormat.RGBA_8888, 1,
                 HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE
                         | HardwareBuffer.USAGE_GPU_COLOR_OUTPUT);
-        return authorGradientBuffer(buffer);
+        return authorGradientBuffer(buffer, mGradientEndColor);
     }
 
     @Override
@@ -101,29 +120,70 @@
 
             mColorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
 
-            ArrayAdapter<String> adapter = new ArrayAdapter<>(
+            ArrayAdapter<String> colorSpaceAdapter = new ArrayAdapter<>(
                     this, android.R.layout.simple_spinner_item, mColorNames);
 
-            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
-            Spinner spinner = new Spinner(this);
-            spinner.setAdapter(adapter);
-            spinner.setOnItemSelectedListener(this);
+            colorSpaceAdapter
+                    .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+            Spinner colorSpaceSpinner = new Spinner(this);
+            colorSpaceSpinner.setAdapter(colorSpaceAdapter);
+            colorSpaceSpinner.setOnItemSelectedListener(new ColorSpaceOnItemSelectedListener());
+
+            ArrayAdapter<String> gradientColorAdapter = new ArrayAdapter<>(
+                    this, android.R.layout.simple_spinner_item, mGradientColorNames);
+
+            gradientColorAdapter
+                    .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+            Spinner gradientColorSpinner = new Spinner(this);
+            gradientColorSpinner.setAdapter(gradientColorAdapter);
+            gradientColorSpinner
+                    .setOnItemSelectedListener(new GradientColorOnItemSelectedListener());
 
             mGradientBuffer = getGradientBuffer().get();
 
             LinearLayout linearLayout = new LinearLayout(this);
             linearLayout.setOrientation(LinearLayout.VERTICAL);
 
+            TextView imageViewText = new TextView(this);
+            imageViewText.setText("ImageView");
             mImageView = new ImageView(this);
 
+            TextView textureViewText = new TextView(this);
+            textureViewText.setText("TextureView");
+            mTextureView = new TextureView(this);
+            mTextureView.setSurfaceTextureListener(this);
+
+            TextView surfaceViewText = new TextView(this);
+            surfaceViewText.setText("SurfaceView");
             mSurfaceView = new SurfaceView(this);
             mSurfaceView.getHolder().addCallback(this);
 
-            linearLayout.addView(spinner, new LinearLayout.LayoutParams(
+            LinearLayout spinnerLayout = new LinearLayout(this);
+            spinnerLayout.setOrientation(LinearLayout.HORIZONTAL);
+
+            spinnerLayout.addView(colorSpaceSpinner, new LinearLayout.LayoutParams(
                     LinearLayout.LayoutParams.WRAP_CONTENT,
                     LinearLayout.LayoutParams.WRAP_CONTENT));
 
+            spinnerLayout.addView(gradientColorSpinner, new LinearLayout.LayoutParams(
+                    LinearLayout.LayoutParams.WRAP_CONTENT,
+                    LinearLayout.LayoutParams.WRAP_CONTENT));
+
+            linearLayout.addView(spinnerLayout, new LinearLayout.LayoutParams(
+                    LinearLayout.LayoutParams.WRAP_CONTENT,
+                    LinearLayout.LayoutParams.WRAP_CONTENT));
+
+            linearLayout.addView(imageViewText,  new LinearLayout.LayoutParams(
+                    LinearLayout.LayoutParams.WRAP_CONTENT,
+                    LinearLayout.LayoutParams.WRAP_CONTENT));
             linearLayout.addView(mImageView, new LinearLayout.LayoutParams(WIDTH, HEIGHT));
+            linearLayout.addView(textureViewText,  new LinearLayout.LayoutParams(
+                    LinearLayout.LayoutParams.WRAP_CONTENT,
+                    LinearLayout.LayoutParams.WRAP_CONTENT));
+            linearLayout.addView(mTextureView, new LinearLayout.LayoutParams(WIDTH, HEIGHT));
+            linearLayout.addView(surfaceViewText,  new LinearLayout.LayoutParams(
+                    LinearLayout.LayoutParams.WRAP_CONTENT,
+                    LinearLayout.LayoutParams.WRAP_CONTENT));
             linearLayout.addView(mSurfaceView, new LinearLayout.LayoutParams(WIDTH, HEIGHT));
 
             setContentView(linearLayout);
@@ -145,16 +205,24 @@
     }
 
     private void populateBuffers() {
-        Bitmap bitmap = Bitmap.wrapHardwareBuffer(
-                mGradientBuffer, ColorSpace.get(ColorSpace.Named.SRGB));
-        Bitmap copy = bitmap.copy(Bitmap.Config.ARGB_8888, false);
-        copy.setColorSpace(mColorSpace);
-        mImageView.setImageBitmap(copy);
+        try {
+            Bitmap bitmap = Bitmap.wrapHardwareBuffer(
+                    getGradientBuffer().get(), ColorSpace.get(ColorSpace.Named.SRGB));
+            Bitmap copy = bitmap.copy(Bitmap.Config.ARGB_8888, false);
+            copy.setColorSpace(mColorSpace);
+            mImageView.setImageBitmap(copy);
 
-        try (Image image = mImageWriter.dequeueInputImage()) {
-            authorGradientBuffer(image.getHardwareBuffer()).get();
-            image.setDataSpace(mColorSpace.getDataSpace());
-            mImageWriter.queueInputImage(image);
+            for (ImageWriter writer : mImageWriters.values()) {
+                mBufferExecutor.execute(() -> {
+                    try (Image image = writer.dequeueInputImage()) {
+                        authorGradientBuffer(image.getHardwareBuffer(), mGradientEndColor).get();
+                        image.setDataSpace(mColorSpace.getDataSpace());
+                        writer.queueInputImage(image);
+                    } catch (Exception e) {
+                        throw new RuntimeException(e);
+                    }
+                });
+            }
         } catch (Exception e) {
             throw new RuntimeException(e);
         }
@@ -167,30 +235,81 @@
 
     @Override
     public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
-        mImageWriter = new ImageWriter.Builder(holder.getSurface())
+        mImageWriters.put(mSurfaceView, new ImageWriter.Builder(holder.getSurface())
                 .setUsage(HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE
                         | HardwareBuffer.USAGE_GPU_COLOR_OUTPUT
                         | HardwareBuffer.USAGE_COMPOSER_OVERLAY)
-                .build();
+                .build());
         populateBuffers();
     }
 
     @Override
     public void surfaceDestroyed(SurfaceHolder holder) {
-        mImageWriter.close();
-        mImageWriter = null;
+        if (mImageWriters.containsKey(mSurfaceView)) {
+            mImageWriters.remove(mSurfaceView);
+        }
     }
 
-
     @Override
-    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
-        mCurrentColorName = mColorNames[position];
-        mColorSpace = getFromName(mCurrentColorName);
+    public void onSurfaceTextureAvailable(
+            @NonNull SurfaceTexture surface, int width, int height) {
+        mImageWriters.put(mTextureView, new ImageWriter.Builder(new Surface(surface))
+                .setUsage(HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE
+                        | HardwareBuffer.USAGE_GPU_COLOR_OUTPUT)
+                .build());
         populateBuffers();
     }
 
     @Override
-    public void onNothingSelected(AdapterView<?> parent) {
+    public void onSurfaceTextureSizeChanged(
+            @NonNull SurfaceTexture surface, int width, int height) {
 
     }
+
+    @Override
+    public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
+        if (mImageWriters.containsKey(mTextureView)) {
+            mImageWriters.remove(mTextureView);
+        }
+        return false;
+    }
+
+    @Override
+    public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {
+
+    }
+
+    private final class ColorSpaceOnItemSelectedListener
+            implements AdapterView.OnItemSelectedListener {
+
+        @Override
+        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+            ColorBitmapActivity.this.mColorSpace =
+                    getFromName(ColorBitmapActivity.this.mColorNames[position]);
+            ColorBitmapActivity.this.getMainExecutor()
+                    .execute(ColorBitmapActivity.this::populateBuffers);
+        }
+
+        @Override
+        public void onNothingSelected(AdapterView<?> parent) {
+
+        }
+    }
+
+    private final class GradientColorOnItemSelectedListener
+            implements AdapterView.OnItemSelectedListener {
+
+        @Override
+        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+            ColorBitmapActivity.this.mGradientEndColor =
+                    ColorBitmapActivity.this.mGradientEndColors[position];
+            ColorBitmapActivity.this.getMainExecutor()
+                    .execute(ColorBitmapActivity.this::populateBuffers);
+        }
+
+        @Override
+        public void onNothingSelected(AdapterView<?> parent) {
+
+        }
+    }
 }