Merge "Remove AmbientState.hasPulsingNotifications()" into main
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 8ddc178..7885cd9 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -900,6 +900,8 @@
                 + Integer.toHexString(mIsDefaultResId));
         pw.println(prefix + "Service:");
         mService.dump(pw, prefix + "  ");
+        pw.println(prefix + "InputMethodSubtype array: count=" + mSubtypes.getCount());
+        mSubtypes.dump(pw, prefix + "  ");
     }
 
     @Override
diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java
index b0b9460..be91cfb 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtype.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtype.java
@@ -28,6 +28,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
+import android.util.Printer;
 import android.util.Slog;
 
 import com.android.internal.inputmethod.SubtypeLocaleUtils;
@@ -791,6 +792,20 @@
         dest.writeInt(mIsAsciiCapable ? 1 : 0);
     }
 
+    void dump(@NonNull Printer pw, @NonNull String prefix) {
+        pw.println(prefix + "mSubtypeNameOverride=" + mSubtypeNameOverride
+                + " mPkLanguageTag=" + mPkLanguageTag
+                + " mPkLayoutType=" + mPkLayoutType
+                + " mSubtypeId=" + mSubtypeId
+                + " mSubtypeLocale=" + mSubtypeLocale
+                + " mSubtypeLanguageTag=" + mSubtypeLanguageTag
+                + " mSubtypeMode=" + mSubtypeMode
+                + " mIsAuxiliary=" + mIsAuxiliary
+                + " mOverridesImplicitlyEnabledSubtype=" + mOverridesImplicitlyEnabledSubtype
+                + " mIsAsciiCapable=" + mIsAsciiCapable
+                + " mSubtypeHashCode=" + mSubtypeHashCode);
+    }
+
     public static final @android.annotation.NonNull Parcelable.Creator<InputMethodSubtype> CREATOR
             = new Parcelable.Creator<InputMethodSubtype>() {
         @Override
diff --git a/core/java/android/view/inputmethod/InputMethodSubtypeArray.java b/core/java/android/view/inputmethod/InputMethodSubtypeArray.java
index ee36dc7..c243a22 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtypeArray.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtypeArray.java
@@ -16,9 +16,11 @@
 
 package android.view.inputmethod;
 
+import android.annotation.NonNull;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.BadParcelableException;
 import android.os.Parcel;
+import android.util.Printer;
 import android.util.Slog;
 
 import java.io.ByteArrayInputStream;
@@ -174,6 +176,19 @@
     private volatile byte[] mCompressedData;
     private volatile int mDecompressedSize;
 
+    void dump(@NonNull Printer pw, @NonNull String prefix) {
+        final var innerPrefix = prefix + "  ";
+        for (int i = 0; i < mCount; i++) {
+            pw.println(prefix + "InputMethodSubtype #" + i + ":");
+            final var subtype = get(i);
+            if (subtype != null) {
+                subtype.dump(pw, innerPrefix);
+            } else {
+                pw.println(innerPrefix + "missing subtype");
+            }
+        }
+    }
+
     private static byte[] marshall(final InputMethodSubtype[] array) {
         Parcel parcel = null;
         try {
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 6ffc638..a2efbd2 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -370,9 +370,10 @@
     /**
      * Enters stage split from a current running app.
      *
+     * @param displayId the id of the current display.
      * @param leftOrTop indicates where the stage split is.
      */
-    void enterStageSplitFromRunningApp(boolean leftOrTop);
+    void moveFocusedTaskToStageSplit(int displayId, boolean leftOrTop);
 
     /**
      * Shows the media output switcher dialog.
diff --git a/core/res/res/values-watch/colors.xml b/core/res/res/values-watch/colors.xml
index 0b00bd8..e2b7505 100644
--- a/core/res/res/values-watch/colors.xml
+++ b/core/res/res/values-watch/colors.xml
@@ -18,11 +18,26 @@
 <resources>
   <color name="system_error_light">#B3261E</color>
   <color name="system_on_error_light">#FFFFFF</color>
-  <color name="system_error_container_light">#F9DEDC</color>
+  <color name="system_error_container_light">#F7DCDA</color>
   <color name="system_on_error_container_light">#410E0B</color>
 
-  <color name="system_error_dark">#EC928E</color>
-  <color name="system_on_error_dark">#410E0B</color>
-  <color name="system_error_container_dark">#F2B8B5</color>
-  <color name="system_on_error_container_dark">#601410</color>
+  <color name="system_error_dark">#F2B8B5</color>
+  <color name="system_on_error_dark">#601410</color>
+  <color name="system_error_container_dark">#FF8986</color>
+  <color name="system_on_error_container_dark">#410E0B</color>
+
+  <!-- With material deprecation of 'background' in favor of 'surface' we flatten these
+       on watches to match the black background requirements -->
+  <color name="system_surface_dark">#000000</color>
+  <color name="system_surface_dim_dark">#000000</color>
+  <color name="system_surface_bright_dark">#000000</color>
+
+  <!-- Wear flattens the typical 5 container layers to 3; container + high & low -->
+  <color name="system_surface_container_dark">#303030</color>
+  <color name="system_surface_variant_dark">#303030</color>
+  <color name="system_surface_container_high_dark">#474747</color>
+  <color name="system_surface_container_highest_dark">#474747</color>
+  <color name="system_surface_container_low_dark">#252626</color>
+  <color name="system_surface_container_lowest_dark">#252626</color>
+
 </resources>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java
index 1071d72..838603f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java
@@ -53,4 +53,7 @@
 
     /** Called when requested to go to fullscreen from the current focused desktop app. */
     void moveFocusedTaskToFullscreen(int displayId);
+
+    /** Called when requested to go to split screen from the current focused desktop app. */
+    void moveFocusedTaskToStageSplit(int displayId, boolean leftOrTop);
 }
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 2c66fd6..c2c9442 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
@@ -62,6 +62,7 @@
 import com.android.wm.shell.common.annotations.ExternalThread
 import com.android.wm.shell.common.annotations.ShellMainThread
 import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT
+import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT
 import com.android.wm.shell.desktopmode.DesktopModeTaskRepository.VisibleTasksListener
 import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler.DragToDesktopStateListener
 import com.android.wm.shell.draganddrop.DragAndDropController
@@ -388,14 +389,8 @@
 
     /** Enter fullscreen by moving the focused freeform task in given `displayId` to fullscreen. */
     fun enterFullscreen(displayId: Int) {
-        if (DesktopModeStatus.isEnabled()) {
-            shellTaskOrganizer
-                    .getRunningTasks(displayId)
-                    .find { taskInfo ->
-                        taskInfo.isFocused && taskInfo.windowingMode == WINDOWING_MODE_FREEFORM
-                    }
-                    ?.let { moveToFullscreenWithAnimation(it, it.positionInParent) }
-        }
+        getFocusedFreeformTask(displayId)
+                ?.let { moveToFullscreenWithAnimation(it, it.positionInParent) }
     }
 
     /** Move a desktop app to split screen. */
@@ -876,12 +871,28 @@
         wct.setDensityDpi(taskInfo.token, getDefaultDensityDpi())
     }
 
+    /** Enter split by using the focused desktop task in given `displayId`. */
+    fun enterSplit(
+        displayId: Int,
+        leftOrTop: Boolean
+    ) {
+        getFocusedFreeformTask(displayId)?.let { requestSplit(it, leftOrTop) }
+    }
+
+    private fun getFocusedFreeformTask(displayId: Int): RunningTaskInfo? {
+        return shellTaskOrganizer.getRunningTasks(displayId)
+                .find { taskInfo -> taskInfo.isFocused &&
+                        taskInfo.windowingMode == WINDOWING_MODE_FREEFORM }
+    }
+
     /**
      * Requests a task be transitioned from desktop to split select. Applies needed windowing
      * changes if this transition is enabled.
      */
+    @JvmOverloads
     fun requestSplit(
-        taskInfo: RunningTaskInfo
+        taskInfo: RunningTaskInfo,
+        leftOrTop: Boolean = false,
     ) {
         val windowingMode = taskInfo.windowingMode
         if (windowingMode == WINDOWING_MODE_FULLSCREEN || windowingMode == WINDOWING_MODE_FREEFORM
@@ -889,7 +900,8 @@
             val wct = WindowContainerTransaction()
             addMoveToSplitChanges(wct, taskInfo)
             splitScreenController.requestEnterSplitSelect(taskInfo, wct,
-                SPLIT_POSITION_BOTTOM_OR_RIGHT, taskInfo.configuration.windowConfiguration.bounds)
+                if (leftOrTop) SPLIT_POSITION_TOP_OR_LEFT else SPLIT_POSITION_BOTTOM_OR_RIGHT,
+                taskInfo.configuration.windowConfiguration.bounds)
         }
     }
 
@@ -1140,6 +1152,12 @@
                 this@DesktopTasksController.enterFullscreen(displayId)
             }
         }
+
+        override fun moveFocusedTaskToStageSplit(displayId: Int, leftOrTop: Boolean) {
+            mainExecutor.execute {
+                this@DesktopTasksController.enterSplit(displayId, leftOrTop)
+            }
+        }
     }
 
     /** The interface for calls from outside the host process. */
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index 4c8a308..92b187f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -53,6 +53,7 @@
 import com.android.wm.shell.common.MultiInstanceHelper
 import com.android.wm.shell.common.ShellExecutor
 import com.android.wm.shell.common.SyncTransactionQueue
+import com.android.wm.shell.common.split.SplitScreenConstants
 import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask
 import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFullscreenTask
 import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createHomeTask
@@ -839,6 +840,22 @@
                 .isEqualTo(WINDOWING_MODE_FULLSCREEN)
     }
 
+    fun enterSplit_freeformTaskIsMovedToSplit() {
+        val task1 = setUpFreeformTask()
+        val task2 = setUpFreeformTask()
+        val task3 = setUpFreeformTask()
+
+        task1.isFocused = false
+        task2.isFocused = true
+        task3.isFocused = false
+
+        controller.enterSplit(DEFAULT_DISPLAY, false)
+
+        verify(splitScreenController).requestEnterSplitSelect(task2, any(),
+            SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT,
+            task2.configuration.windowConfiguration.bounds)
+    }
+
     private fun setUpFreeformTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo {
         val task = createFreeformTask(displayId)
         whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt
index b3380ff..69a1a0f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.keyguard.data.repository
 
 import android.graphics.Point
+import android.os.PowerManager.WAKE_REASON_UNKNOWN
 import android.testing.TestableLooper
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
@@ -26,8 +27,9 @@
 import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
 import com.android.systemui.keyguard.shared.model.BiometricUnlockSource
 import com.android.systemui.kosmos.testScope
-import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
-import com.android.systemui.power.domain.interactor.powerInteractor
+import com.android.systemui.power.data.repository.powerRepository
+import com.android.systemui.power.shared.model.WakeSleepReason
+import com.android.systemui.power.shared.model.WakefulnessState
 import com.android.systemui.statusbar.CircleReveal
 import com.android.systemui.statusbar.LightRevealEffect
 import com.android.systemui.testKosmos
@@ -51,7 +53,7 @@
     private val kosmos = testKosmos()
     private val testScope = kosmos.testScope
     private val fakeKeyguardRepository = kosmos.fakeKeyguardRepository
-    private val powerInteractor = kosmos.powerInteractor
+    private val powerRepository = kosmos.powerRepository
     private lateinit var underTest: LightRevealScrimRepositoryImpl
 
     @get:Rule val animatorTestRule = AnimatorTestRule(this)
@@ -63,7 +65,7 @@
             LightRevealScrimRepositoryImpl(
                 kosmos.fakeKeyguardRepository,
                 context,
-                kosmos.powerInteractor,
+                powerRepository,
                 mock()
             )
     }
@@ -73,7 +75,14 @@
         val values = mutableListOf<LightRevealEffect>()
         val job = launch { underTest.revealEffect.collect { values.add(it) } }
 
-        powerInteractor.setAwakeForTest()
+        powerRepository.updateWakefulness(
+            rawState = WakefulnessState.STARTING_TO_WAKE,
+            lastWakeReason = WakeSleepReason.fromPowerManagerWakeReason(WAKE_REASON_UNKNOWN),
+            powerButtonLaunchGestureTriggered =
+                powerRepository.wakefulness.value.powerButtonLaunchGestureTriggered,
+        )
+        powerRepository.updateWakefulness(rawState = WakefulnessState.AWAKE)
+
         // We should initially emit the default reveal effect.
         runCurrent()
         values.assertEffectsMatchPredicates({ it == DEFAULT_REVEAL_EFFECT })
@@ -171,7 +180,7 @@
         testScope.runTest {
             val value by collectLastValue(underTest.revealAmount)
             runCurrent()
-            underTest.startRevealAmountAnimator(true)
+            underTest.startRevealAmountAnimator(true, 500L)
             assertEquals(0.0f, value)
             animatorTestRule.advanceTimeBy(500L)
             assertEquals(1.0f, value)
@@ -183,11 +192,11 @@
         testScope.runTest {
             val value by collectLastValue(underTest.revealAmount)
             runCurrent()
-            underTest.startRevealAmountAnimator(true)
+            underTest.startRevealAmountAnimator(true, 500L)
             assertEquals(0.0f, value)
             animatorTestRule.advanceTimeBy(250L)
             assertEquals(0.5f, value)
-            underTest.startRevealAmountAnimator(true)
+            underTest.startRevealAmountAnimator(true, 500L)
             animatorTestRule.advanceTimeBy(250L)
             assertEquals(1.0f, value)
         }
@@ -198,9 +207,9 @@
         testScope.runTest {
             val lastValue by collectLastValue(underTest.revealAmount)
             runCurrent()
-            underTest.startRevealAmountAnimator(true)
+            underTest.startRevealAmountAnimator(true, 500L)
             animatorTestRule.advanceTimeBy(500L)
-            underTest.startRevealAmountAnimator(false)
+            underTest.startRevealAmountAnimator(false, 500L)
             animatorTestRule.advanceTimeBy(500L)
             assertEquals(0.0f, lastValue)
         }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt
index 2b6e6c7..3e0a1f3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt
@@ -24,7 +24,6 @@
 import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.TransitionState
 import com.android.systemui.keyguard.shared.model.TransitionStep
-import com.android.systemui.kosmos.testScope
 import com.android.systemui.statusbar.LightRevealEffect
 import com.android.systemui.statusbar.LightRevealScrim
 import com.android.systemui.testKosmos
@@ -50,7 +49,6 @@
     private val fakeLightRevealScrimRepository = kosmos.fakeLightRevealScrimRepository
 
     private val fakeKeyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
-    private val testScope = kosmos.testScope
 
     private val underTest = kosmos.lightRevealScrimInteractor
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt
index d9479de..eac476f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt
@@ -26,7 +26,7 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
 import com.android.systemui.keyguard.shared.model.BiometricUnlockSource
-import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.power.data.repository.PowerRepository
 import com.android.systemui.power.shared.model.WakeSleepReason
 import com.android.systemui.power.shared.model.WakeSleepReason.TAP
 import com.android.systemui.res.R
@@ -47,6 +47,7 @@
 import kotlinx.coroutines.flow.map
 
 val DEFAULT_REVEAL_EFFECT = LiftReveal
+const val DEFAULT_REVEAL_DURATION = 500L
 
 /**
  * Encapsulates state relevant to the light reveal scrim, the view used to reveal/hide screen
@@ -63,7 +64,9 @@
 
     val revealAmount: Flow<Float>
 
-    fun startRevealAmountAnimator(reveal: Boolean)
+    val isAnimating: Boolean
+
+    fun startRevealAmountAnimator(reveal: Boolean, duration: Long = DEFAULT_REVEAL_DURATION)
 }
 
 @SysUISingleton
@@ -72,7 +75,7 @@
 constructor(
     keyguardRepository: KeyguardRepository,
     val context: Context,
-    powerInteractor: PowerInteractor,
+    powerRepository: PowerRepository,
     private val scrimLogger: ScrimLogger,
 ) : LightRevealScrimRepository {
     companion object {
@@ -125,7 +128,7 @@
 
     /** The reveal effect we'll use for the next non-biometric unlock (tap, power button, etc). */
     private val nonBiometricRevealEffect: Flow<LightRevealEffect?> =
-        powerInteractor.detailedWakefulness.flatMapLatest { wakefulnessModel ->
+        powerRepository.wakefulness.flatMapLatest { wakefulnessModel ->
             when {
                 wakefulnessModel.isAwakeOrAsleepFrom(WakeSleepReason.POWER_BUTTON) ->
                     powerButtonRevealEffect
@@ -134,7 +137,7 @@
             }
         }
 
-    private val revealAmountAnimator = ValueAnimator.ofFloat(0f, 1f).apply { duration = 500 }
+    private val revealAmountAnimator = ValueAnimator.ofFloat(0f, 1f)
 
     override val revealAmount: Flow<Float> = callbackFlow {
         val updateListener =
@@ -149,18 +152,21 @@
         revealAmountAnimator.addUpdateListener(updateListener)
         awaitClose { revealAmountAnimator.removeUpdateListener(updateListener) }
     }
+    override val isAnimating: Boolean
+        get() = revealAmountAnimator.isRunning
 
     private var willBeOrIsRevealed: Boolean? = null
 
-    override fun startRevealAmountAnimator(reveal: Boolean) {
+    override fun startRevealAmountAnimator(reveal: Boolean, duration: Long) {
         if (reveal == willBeOrIsRevealed) return
         willBeOrIsRevealed = reveal
+        revealAmountAnimator.duration = duration
         if (reveal && !revealAmountAnimator.isRunning) {
             revealAmountAnimator.start()
         } else {
             revealAmountAnimator.reverse()
         }
-        scrimLogger.d(TAG, "startRevealAmountAnimator, reveal: ", reveal)
+        scrimLogger.d(TAG, "startRevealAmountAnimator, reveal", reveal)
     }
 
     override val revealEffect =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt
index 8905c9e..2d944c6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt
@@ -25,14 +25,13 @@
 import com.android.systemui.power.shared.model.ScreenPowerState
 import com.android.systemui.statusbar.LightRevealEffect
 import com.android.systemui.util.kotlin.sample
+import dagger.Lazy
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.filter
 import kotlinx.coroutines.launch
 
-@ExperimentalCoroutinesApi
 @SysUISingleton
 class LightRevealScrimInteractor
 @Inject
@@ -41,7 +40,7 @@
     private val lightRevealScrimRepository: LightRevealScrimRepository,
     @Application private val scope: CoroutineScope,
     private val scrimLogger: ScrimLogger,
-    private val powerInteractor: PowerInteractor,
+    private val powerInteractor: Lazy<PowerInteractor>,
 ) {
     init {
         listenForStartedKeyguardTransitionStep()
@@ -81,31 +80,33 @@
         }
 
     private fun screenIsShowingContent() =
-        powerInteractor.screenPowerState.value != ScreenPowerState.SCREEN_OFF &&
-            powerInteractor.screenPowerState.value != ScreenPowerState.SCREEN_TURNING_ON
+        powerInteractor.get().screenPowerState.value != ScreenPowerState.SCREEN_OFF &&
+            powerInteractor.get().screenPowerState.value != ScreenPowerState.SCREEN_TURNING_ON
+
+    val isAnimating: Boolean
+        get() = lightRevealScrimRepository.isAnimating
+
+    /**
+     * Whether the light reveal scrim will be fully revealed (revealAmount = 1.0f) in the given
+     * state after the transition is complete. If false, scrim will be fully hidden.
+     */
+    private fun willBeRevealedInState(state: KeyguardState): Boolean {
+        return when (state) {
+            KeyguardState.OFF -> false
+            KeyguardState.DOZING -> false
+            KeyguardState.AOD -> false
+            KeyguardState.DREAMING -> true
+            KeyguardState.DREAMING_LOCKSCREEN_HOSTED -> true
+            KeyguardState.GLANCEABLE_HUB -> true
+            KeyguardState.ALTERNATE_BOUNCER -> true
+            KeyguardState.PRIMARY_BOUNCER -> true
+            KeyguardState.LOCKSCREEN -> true
+            KeyguardState.GONE -> true
+            KeyguardState.OCCLUDED -> true
+        }
+    }
 
     companion object {
-
-        /**
-         * Whether the light reveal scrim will be fully revealed (revealAmount = 1.0f) in the given
-         * state after the transition is complete. If false, scrim will be fully hidden.
-         */
-        private fun willBeRevealedInState(state: KeyguardState): Boolean {
-            return when (state) {
-                KeyguardState.OFF -> false
-                KeyguardState.DOZING -> false
-                KeyguardState.AOD -> false
-                KeyguardState.DREAMING -> true
-                KeyguardState.DREAMING_LOCKSCREEN_HOSTED -> true
-                KeyguardState.GLANCEABLE_HUB -> true
-                KeyguardState.ALTERNATE_BOUNCER -> true
-                KeyguardState.PRIMARY_BOUNCER -> true
-                KeyguardState.LOCKSCREEN -> true
-                KeyguardState.GONE -> true
-                KeyguardState.OCCLUDED -> true
-            }
-        }
-
         val TAG = LightRevealScrimInteractor::class.simpleName!!
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 5f8b5dd..d0ff338 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -33,6 +33,7 @@
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DOZING;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DREAMING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_GOING_AWAY;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED;
@@ -111,6 +112,7 @@
 import com.android.systemui.statusbar.phone.StatusBarWindowCallback;
 import com.android.systemui.statusbar.policy.CallbackController;
 import com.android.systemui.unfold.progress.UnfoldTransitionProgressForwarder;
+import com.android.wm.shell.desktopmode.DesktopModeStatus;
 import com.android.wm.shell.sysui.ShellInterface;
 
 import dagger.Lazy;
@@ -673,9 +675,13 @@
             }
 
             @Override
-            public void enterStageSplitFromRunningApp(boolean leftOrTop) {
+            public void moveFocusedTaskToStageSplit(int displayId, boolean leftOrTop) {
                 if (mOverviewProxy != null) {
                     try {
+                        if (DesktopModeStatus.isEnabled() && (sysUiState.getFlags()
+                                & SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE) != 0) {
+                            return;
+                        }
                         mOverviewProxy.enterStageSplitFromRunningApp(leftOrTop);
                     } catch (RemoteException e) {
                         Log.w(TAG_OPS, "Unable to enter stage split from the current running app");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index bb81683..4275fc6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -169,7 +169,7 @@
     private static final int MSG_TILE_SERVICE_REQUEST_LISTENING_STATE = 68 << MSG_SHIFT;
     private static final int MSG_SHOW_REAR_DISPLAY_DIALOG = 69 << MSG_SHIFT;
     private static final int MSG_MOVE_FOCUSED_TASK_TO_FULLSCREEN = 70 << MSG_SHIFT;
-    private static final int MSG_ENTER_STAGE_SPLIT_FROM_RUNNING_APP = 71 << MSG_SHIFT;
+    private static final int MSG_MOVE_FOCUSED_TASK_TO_STAGE_SPLIT = 71 << MSG_SHIFT;
     private static final int MSG_SHOW_MEDIA_OUTPUT_SWITCHER = 72 << MSG_SHIFT;
     private static final int MSG_TOGGLE_TASKBAR = 73 << MSG_SHIFT;
     private static final int MSG_SETTING_CHANGED = 74 << MSG_SHIFT;
@@ -503,9 +503,9 @@
         default void moveFocusedTaskToFullscreen(int displayId) {}
 
         /**
-         * @see IStatusBar#enterStageSplitFromRunningApp
+         * @see IStatusBar#moveFocusedTaskToStageSplit
          */
-        default void enterStageSplitFromRunningApp(boolean leftOrTop) {}
+        default void moveFocusedTaskToStageSplit(int displayId, boolean leftOrTop) {}
 
         /**
          * @see IStatusBar#showMediaOutputSwitcher
@@ -1338,10 +1338,13 @@
     }
 
     @Override
-    public void enterStageSplitFromRunningApp(boolean leftOrTop) {
+    public void moveFocusedTaskToStageSplit(int displayId, boolean leftOrTop) {
         synchronized (mLock) {
-            mHandler.obtainMessage(MSG_ENTER_STAGE_SPLIT_FROM_RUNNING_APP,
-                    leftOrTop).sendToTarget();
+            SomeArgs args = SomeArgs.obtain();
+            args.argi1 = displayId;
+            args.argi2 = leftOrTop ? 1 : 0;
+            mHandler.obtainMessage(MSG_MOVE_FOCUSED_TASK_TO_STAGE_SPLIT,
+                    args).sendToTarget();
         }
     }
 
@@ -1907,11 +1910,15 @@
                     }
                     break;
                 }
-                case MSG_ENTER_STAGE_SPLIT_FROM_RUNNING_APP:
+                case MSG_MOVE_FOCUSED_TASK_TO_STAGE_SPLIT: {
+                    args = (SomeArgs) msg.obj;
+                    int displayId = args.argi1;
+                    boolean leftOrTop = args.argi2 != 0;
                     for (int i = 0; i < mCallbacks.size(); i++) {
-                        mCallbacks.get(i).enterStageSplitFromRunningApp((Boolean) msg.obj);
+                        mCallbacks.get(i).moveFocusedTaskToStageSplit(displayId, leftOrTop);
                     }
                     break;
+                }
                 case MSG_SHOW_MEDIA_OUTPUT_SWITCHER:
                     args = (SomeArgs) msg.obj;
                     String clientPackageName = (String) args.arg1;
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 223eaf7..88374d6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
@@ -32,6 +32,7 @@
 import com.android.systemui.statusbar.notification.stack.AnimationProperties
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator
 import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.Flags.lightRevealMigration
 import com.android.app.tracing.namedRunnable
 import com.android.systemui.util.settings.GlobalSettings
 import javax.inject.Inject
@@ -45,7 +46,7 @@
 /**
  * Duration for the light reveal portion of the animation.
  */
-private const val LIGHT_REVEAL_ANIMATION_DURATION = 750L
+private const val LIGHT_REVEAL_ANIMATION_DURATION = 500L
 
 /**
  * Controller for the unlocked screen off animation, which runs when the device is going to sleep
@@ -66,7 +67,7 @@
     private val notifShadeWindowControllerLazy: dagger.Lazy<NotificationShadeWindowController>,
     private val interactionJankMonitor: InteractionJankMonitor,
     private val powerManager: PowerManager,
-    private val handler: Handler = Handler(),
+    private val handler: Handler = Handler()
 ) : WakefulnessLifecycle.Observer, ScreenOffAnimation {
     private lateinit var centralSurfaces: CentralSurfaces
     private lateinit var shadeViewController: ShadeViewController
@@ -95,6 +96,7 @@
         duration = LIGHT_REVEAL_ANIMATION_DURATION
         interpolator = Interpolators.LINEAR
         addUpdateListener {
+            if (lightRevealMigration()) return@addUpdateListener
             if (lightRevealScrim.revealEffect !is CircleReveal) {
                 lightRevealScrim.revealAmount = it.animatedValue as Float
             }
@@ -107,6 +109,7 @@
         }
         addListener(object : AnimatorListenerAdapter() {
             override fun onAnimationCancel(animation: Animator) {
+                if (lightRevealMigration()) return
                 if (lightRevealScrim.revealEffect !is CircleReveal) {
                     lightRevealScrim.revealAmount = 1f
                 }
@@ -371,7 +374,7 @@
      * AOD UI.
      */
     override fun isAnimationPlaying(): Boolean {
-        return lightRevealAnimationPlaying || aodUiAnimationPlaying
+        return isScreenOffLightRevealAnimationPlaying() || aodUiAnimationPlaying
     }
 
     override fun shouldAnimateInKeyguard(): Boolean =
@@ -395,6 +398,9 @@
     /**
      * Whether the light reveal animation is playing. The second part of the screen off animation,
      * where AOD animates in, might still be playing if this returns false.
+     *
+     * Note: This only refers to the specific light reveal animation that is playing during lock
+     * therefore LightRevealScrimInteractor.isAnimating is not the desired response.
      */
     fun isScreenOffLightRevealAnimationPlaying(): Boolean {
         return lightRevealAnimationPlaying
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index 324d723..7674fe9 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -361,12 +361,14 @@
             public void enterDesktop(int displayId) {
                 desktopMode.enterDesktop(displayId);
             }
-        });
-        mCommandQueue.addCallback(new CommandQueue.Callbacks() {
             @Override
             public void moveFocusedTaskToFullscreen(int displayId) {
                 desktopMode.moveFocusedTaskToFullscreen(displayId);
             }
+            @Override
+            public void moveFocusedTaskToStageSplit(int displayId, boolean leftOrTop) {
+                desktopMode.moveFocusedTaskToStageSplit(displayId, leftOrTop);
+            }
         });
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
index 6a0375d..3bf54a3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
@@ -31,6 +31,7 @@
 import com.android.systemui.statusbar.NotificationShadeWindowController
 import com.android.systemui.statusbar.StatusBarStateControllerImpl
 import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.testKosmos
 import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.settings.GlobalSettings
 import junit.framework.Assert.assertFalse
@@ -80,6 +81,8 @@
     @Mock
     private lateinit var handler: Handler
 
+    val kosmos = testKosmos()
+
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
@@ -87,14 +90,14 @@
                 context,
                 wakefulnessLifecycle,
                 statusBarStateController,
-                dagger.Lazy<KeyguardViewMediator> { keyguardViewMediator },
+                { keyguardViewMediator },
                 keyguardStateController,
-                dagger.Lazy<DozeParameters> { dozeParameters },
+                { dozeParameters },
                 globalSettings,
-                dagger.Lazy<NotificationShadeWindowController> { notifShadeWindowController },
+                { notifShadeWindowController },
                 interactionJankMonitor,
                 powerManager,
-                handler = handler,
+                handler = handler
         )
         controller.initialize(centralSurfaces, shadeViewController, lightRevealScrim)
 
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeLightRevealScrimRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeLightRevealScrimRepository.kt
index b24b95e..f26bb83 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeLightRevealScrimRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeLightRevealScrimRepository.kt
@@ -35,7 +35,10 @@
     private val _revealAmount: MutableStateFlow<Float> = MutableStateFlow(0.0f)
     override val revealAmount: Flow<Float> = _revealAmount
 
-    override fun startRevealAmountAnimator(reveal: Boolean) {
+    override val isAnimating: Boolean
+        get() = false
+
+    override fun startRevealAmountAnimator(reveal: Boolean, duration: Long) {
         if (reveal) {
             _revealAmount.value = 1.0f
         } else {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorKosmos.kt
index 58e0a3b..d5bdbdb 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorKosmos.kt
@@ -29,6 +29,6 @@
             lightRevealScrimRepository,
             applicationCoroutineScope,
             scrimLogger,
-            powerInteractor,
+            { powerInteractor },
         )
     }
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 7afb780..13bc772 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -1246,7 +1246,8 @@
     @GuardedBy("mLock")
     private void requestNewFillResponseLocked(@NonNull ViewState viewState, int newState,
             int flags) {
-        final FillResponse existingResponse = shouldRequestSecondaryProvider(flags)
+        boolean isSecondary = shouldRequestSecondaryProvider(flags);
+        final FillResponse existingResponse = isSecondary
                 ? viewState.getSecondaryResponse() : viewState.getResponse();
         mFillRequestEventLogger.startLogForNewRequest();
         mRequestCount++;
@@ -1283,12 +1284,7 @@
         }
 
         viewState.setState(newState);
-
-        int requestId;
-        // TODO(b/158623971): Update this to prevent possible overflow
-        do {
-            requestId = sIdCounter.getAndIncrement();
-        } while (requestId == INVALID_REQUEST_ID);
+        int requestId = getRequestId(isSecondary);
 
         // Create a metrics log for the request
         final int ordinal = mRequestLogs.size() + 1;
@@ -1367,6 +1363,25 @@
         requestAssistStructureLocked(requestId, flags);
     }
 
+    private static int getRequestId(boolean isSecondary) {
+        // For authentication flows, there needs to be a way to know whether to retrieve the Fill
+        // Response from the primary provider or the secondary provider from the requestId. A simple
+        // way to achieve this is by assigning odd number request ids to secondary provider and
+        // even numbers to primary provider.
+        int requestId;
+        // TODO(b/158623971): Update this to prevent possible overflow
+        if (isSecondary) {
+            do {
+                requestId = sIdCounter.getAndIncrement();
+            } while (!isSecondaryProviderRequestId(requestId));
+        } else {
+            do {
+                requestId = sIdCounter.getAndIncrement();
+            } while (requestId == INVALID_REQUEST_ID || isSecondaryProviderRequestId(requestId));
+        }
+        return requestId;
+    }
+
     private boolean isRequestSupportFillDialog(int flags) {
         return (flags & FLAG_SUPPORTS_FILL_DIALOG) != 0;
     }
@@ -2790,7 +2805,9 @@
             removeFromService();
             return;
         }
-        final FillResponse authenticatedResponse = mResponses.get(requestId);
+        final FillResponse authenticatedResponse = isSecondaryProviderRequestId(requestId)
+                ? mSecondaryResponses.get(requestId)
+                : mResponses.get(requestId);
         if (authenticatedResponse == null || data == null) {
             Slog.w(TAG, "no authenticated response");
             mPresentationStatsEventLogger.maybeSetAuthenticationResult(
@@ -2915,6 +2932,10 @@
         }
     }
 
+    private static boolean isSecondaryProviderRequestId(int requestId) {
+        return requestId % 2 == 1;
+    }
+
     private Dataset getDatasetFromCredentialResponse(GetCredentialResponse result) {
         if (result == null) {
             return null;
diff --git a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
index 3e68920..1f8736b 100644
--- a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
+++ b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
@@ -31,6 +31,7 @@
 import android.os.ParcelFileDescriptor;
 import android.util.Slog;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.backup.utils.BackupEligibilityRules;
 
 import java.io.BufferedInputStream;
@@ -62,7 +63,7 @@
 
     // key under which we store global metadata (individual app metadata
     // is stored using the package name as a key)
-    private static final String GLOBAL_METADATA_KEY = "@meta@";
+    @VisibleForTesting static final String GLOBAL_METADATA_KEY = "@meta@";
 
     // key under which we store the identity of the user's chosen default home app
     private static final String DEFAULT_HOME_KEY = "@home@";
@@ -72,19 +73,19 @@
     // ANCESTRAL_RECORD_VERSION=1 (introduced Android P).
     // Should the ANCESTRAL_RECORD_VERSION be bumped up in the future, STATE_FILE_VERSION will also
     // need bumping up, assuming more data needs saving to the state file.
-    private static final String STATE_FILE_HEADER = "=state=";
-    private static final int STATE_FILE_VERSION = 2;
+    @VisibleForTesting static final String STATE_FILE_HEADER = "=state=";
+    @VisibleForTesting static final int STATE_FILE_VERSION = 2;
 
     // key under which we store the saved ancestral-dataset format (starting from Android P)
     // IMPORTANT: this key needs to come first in the restore data stream (to find out
     // whether this version of Android knows how to restore the incoming data set), so it needs
     // to be always the first one in alphabetical order of all the keys
-    private static final String ANCESTRAL_RECORD_KEY = "@ancestral_record@";
+    @VisibleForTesting static final String ANCESTRAL_RECORD_KEY = "@ancestral_record@";
 
     // Current version of the saved ancestral-dataset format
     // Note that this constant was not used until Android P, and started being used
     // to version @pm@ data for forwards-compatibility.
-    private static final int ANCESTRAL_RECORD_VERSION = 1;
+    @VisibleForTesting static final int ANCESTRAL_RECORD_VERSION = 1;
 
     // Undefined version of the saved ancestral-dataset file format means that the restore data
     // is coming from pre-Android P device.
@@ -593,7 +594,8 @@
     }
 
     // Util: write out our new backup state file
-    private void writeStateFile(List<PackageInfo> pkgs, ParcelFileDescriptor stateFile) {
+    @VisibleForTesting
+    static void writeStateFile(List<PackageInfo> pkgs, ParcelFileDescriptor stateFile) {
         FileOutputStream outstream = new FileOutputStream(stateFile.getFileDescriptor());
         BufferedOutputStream outbuf = new BufferedOutputStream(outstream);
         DataOutputStream out = new DataOutputStream(outbuf);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index d13b28f..19f0298 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -5023,6 +5023,14 @@
                             .getSortedInputMethodAndSubtypeList(
                                     showAuxSubtypes, isScreenLocked, true /* forImeMenu */,
                                     mContext, mSettings.getMethodMap(), mSettings.getUserId());
+                    if (imList.isEmpty()) {
+                        Slog.w(TAG, "Show switching menu failed, imList is empty,"
+                                + " showAuxSubtypes: " + showAuxSubtypes
+                                + " isScreenLocked: " + isScreenLocked
+                                + " userId: " + mSettings.getUserId());
+                        return false;
+                    }
+
                     mMenuController.showInputMethodMenuLocked(showAuxSubtypes, displayId,
                             lastInputMethodId, lastInputMethodSubtypeId, imList);
                 }
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
index 6ed4848..3bd0a9f 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
@@ -80,10 +80,6 @@
 
         final int userId = mService.getCurrentImeUserIdLocked();
 
-        if (imList.isEmpty()) {
-            return;
-        }
-
         hideInputMethodMenuLocked();
 
         if (preferredInputMethodSubtypeId == NOT_A_SUBTYPE_ID) {
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java b/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java
index 1379d16..1c958a9 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java
@@ -167,6 +167,7 @@
 
         final ArrayList<InputMethodInfo> imis = settings.getEnabledInputMethodList();
         if (imis.isEmpty()) {
+            Slog.w(TAG, "Enabled input method list is empty.");
             return new ArrayList<>();
         }
         if (isScreenLocked && includeAuxiliarySubtypes) {
diff --git a/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java b/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java
index 9caf5cf..396192e 100644
--- a/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java
+++ b/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java
@@ -101,7 +101,6 @@
     }
 
     private void offloadInner(Runnable r) {
-        boolean useThrowingRunnable = r instanceof ThrowingRunnable;
         final long identity = Binder.clearCallingIdentity();
         try {
             mExecutor.execute(() -> {
@@ -110,14 +109,9 @@
                 Binder.restoreCallingIdentity(identity);
                 try {
                     try {
-                        if (useThrowingRunnable) {
-                            ((ThrowingRunnable) r).runOrThrow();
-                        } else {
-                            r.run();
-                        }
+                        r.run();
                     } catch (Exception e) {
-                        Slog.e(TAG, "Error in async call", e);
-                        throw ExceptionUtils.propagate(e);
+                        Slog.e(TAG, "Error in async IMMS call", e);
                     }
                 } finally {
                     Binder.restoreCallingIdentity(inner);
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index ec4b38b..5974ac8 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3523,7 +3523,8 @@
             case KeyEvent.KEYCODE_DPAD_LEFT:
                 if (firstDown && event.isMetaPressed()) {
                     if (event.isCtrlPressed()) {
-                        enterStageSplitFromRunningApp(true /* leftOrTop */);
+                        moveFocusedTaskToStageSplit(getTargetDisplayIdForKeyEvent(event),
+                                true /* leftOrTop */);
                         logKeyboardSystemsEvent(event, KeyboardLogEvent.SPLIT_SCREEN_NAVIGATION);
                     } else {
                         logKeyboardSystemsEvent(event, KeyboardLogEvent.BACK);
@@ -3534,7 +3535,8 @@
                 break;
             case KeyEvent.KEYCODE_DPAD_RIGHT:
                 if (firstDown && event.isMetaPressed() && event.isCtrlPressed()) {
-                    enterStageSplitFromRunningApp(false /* leftOrTop */);
+                    moveFocusedTaskToStageSplit(getTargetDisplayIdForKeyEvent(event),
+                            false /* leftOrTop */);
                     logKeyboardSystemsEvent(event, KeyboardLogEvent.SPLIT_SCREEN_NAVIGATION);
                     return true;
                 }
@@ -4387,10 +4389,10 @@
         }
     }
 
-    private void enterStageSplitFromRunningApp(boolean leftOrTop) {
+    private void moveFocusedTaskToStageSplit(int displayId, boolean leftOrTop) {
         StatusBarManagerInternal statusbar = getStatusBarManagerInternal();
         if (statusbar != null) {
-            statusbar.enterStageSplitFromRunningApp(leftOrTop);
+            statusbar.moveFocusedTaskToStageSplit(displayId, leftOrTop);
         }
     }
 
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index 14e0ce1..c73f89c 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -233,9 +233,9 @@
     /**
      * Enters stage split from a current running app.
      *
-     * @see com.android.internal.statusbar.IStatusBar#enterStageSplitFromRunningApp
+     * @see com.android.internal.statusbar.IStatusBar#moveFocusedTaskToStageSplit
      */
-    void enterStageSplitFromRunningApp(boolean leftOrTop);
+    void moveFocusedTaskToStageSplit(int displayId, boolean leftOrTop);
 
     /**
      * Shows the media output switcher dialog.
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 0b48a75..214dbe0 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -820,11 +820,11 @@
         }
 
         @Override
-        public void enterStageSplitFromRunningApp(boolean leftOrTop) {
+        public void moveFocusedTaskToStageSplit(int displayId, boolean leftOrTop) {
             IStatusBar bar = mBar;
             if (bar != null) {
                 try {
-                    bar.enterStageSplitFromRunningApp(leftOrTop);
+                    bar.moveFocusedTaskToStageSplit(displayId, leftOrTop);
                 } catch (RemoteException ex) { }
             }
         }
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 9b19a70..3fb5998 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -157,13 +157,21 @@
             mFindResults.setUseTopWallpaperAsTarget(true);
         }
 
-        if (mService.mPolicy.isKeyguardLocked() && w.canShowWhenLocked()) {
-            if (mService.mPolicy.isKeyguardOccluded() || (useShellTransition
-                    ? w.inTransition() : mService.mPolicy.isKeyguardUnoccluding())) {
-                // The lowest show when locked window decides whether we need to put the wallpaper
-                // behind.
-                mFindResults.mNeedsShowWhenLockedWallpaper = !isFullscreen(w.mAttrs)
-                        || (w.mActivityRecord != null && !w.mActivityRecord.fillsParent());
+        if (mService.mPolicy.isKeyguardLocked()) {
+            if (w.canShowWhenLocked()) {
+                if (mService.mPolicy.isKeyguardOccluded() || (useShellTransition
+                        ? w.inTransition() : mService.mPolicy.isKeyguardUnoccluding())) {
+                    // The lowest show-when-locked window decides whether to show wallpaper.
+                    mFindResults.mNeedsShowWhenLockedWallpaper = !isFullscreen(w.mAttrs)
+                            || (w.mActivityRecord != null && !w.mActivityRecord.fillsParent());
+                }
+            } else if (w.hasWallpaper() && mService.mPolicy.isKeyguardHostWindow(w.mAttrs)
+                    && w.mTransitionController.isTransitionOnDisplay(mDisplayContent)) {
+                // If we have no candidates at all, notification shade is allowed to be the target
+                // of last resort even if it has not been made visible yet.
+                if (DEBUG_WALLPAPER) Slog.v(TAG, "Found keyguard as wallpaper target: " + w);
+                mFindResults.setWallpaperTarget(w);
+                return false;
             }
         }
 
@@ -200,14 +208,7 @@
 
     private boolean isRecentsTransitionTarget(WindowState w) {
         if (w.mTransitionController.isShellTransitionsEnabled()) {
-            // Because the recents activity is invisible in background while keyguard is occluded
-            // (the activity window is on screen while keyguard is locked) with recents animation,
-            // the task animating by recents needs to be wallpaper target to make wallpaper visible.
-            // While for unlocked case, because recents activity will be moved to top, it can be
-            // the wallpaper target naturally.
-            return w.mActivityRecord != null && w.mAttrs.type == TYPE_BASE_APPLICATION
-                    && mDisplayContent.isKeyguardLocked()
-                    && w.mTransitionController.isTransientHide(w.getTask());
+            return false;
         }
         // The window is either the recents activity or is in the task animating by the recents.
         final RecentsAnimationController controller = mService.getRecentsAnimationController();
diff --git a/services/foldables/devicestateprovider/src/com/android/server/policy/BookStyleClosedStatePredicate.java b/services/foldables/devicestateprovider/src/com/android/server/policy/BookStyleClosedStatePredicate.java
index 209107e..ce4126a 100644
--- a/services/foldables/devicestateprovider/src/com/android/server/policy/BookStyleClosedStatePredicate.java
+++ b/services/foldables/devicestateprovider/src/com/android/server/policy/BookStyleClosedStatePredicate.java
@@ -177,8 +177,11 @@
      */
     private static class PostureEstimator implements SensorEventListener, Dumpable {
 
+        private static final String FLAT_INCLINATION_THRESHOLD_DEGREES_PROPERTY
+                = "persist.foldable_postures.wedge_inclination_threshold_degrees";
 
-        private static final int FLAT_INCLINATION_THRESHOLD_DEGREES = 8;
+        private static final int FLAT_INCLINATION_THRESHOLD_DEGREES = Integer.parseInt(
+                System.getProperty(FLAT_INCLINATION_THRESHOLD_DEGREES_PROPERTY, "25"));
 
         /**
          * Alpha parameter of the accelerometer low pass filter: the lower the value, the less high
diff --git a/services/tests/mockingservicestests/src/com/android/server/backup/PackageManagerBackupAgentTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/PackageManagerBackupAgentTest.java
new file mode 100644
index 0000000..d1b6de0
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/backup/PackageManagerBackupAgentTest.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.backup.BackupDataInput;
+import android.app.backup.BackupDataOutput;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.os.ParcelFileDescriptor;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+
+import java.io.BufferedOutputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.nio.ByteBuffer;
+import java.util.Optional;
+
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class PackageManagerBackupAgentTest {
+
+    private static final String EXISTING_PACKAGE_NAME = "com.android.wallpaperbackup";
+    private static final int USER_ID = 0;
+
+    @Rule public TemporaryFolder folder = new TemporaryFolder();
+
+    private PackageManagerBackupAgent mPackageManagerBackupAgent;
+    private ImmutableList<PackageInfo> mPackages;
+    private File mBackupData, mOldState, mNewState;
+
+    @Before
+    public void setUp() throws Exception {
+        PackageManager packageManager = getApplicationContext().getPackageManager();
+
+        PackageInfo existingPackageInfo =
+                packageManager.getPackageInfoAsUser(
+                        EXISTING_PACKAGE_NAME, PackageManager.GET_SIGNING_CERTIFICATES, USER_ID);
+        mPackages = ImmutableList.of(existingPackageInfo);
+        mPackageManagerBackupAgent =
+                new PackageManagerBackupAgent(packageManager, mPackages, USER_ID);
+
+        mBackupData = folder.newFile("backup_data");
+        mOldState = folder.newFile("old_state");
+        mNewState = folder.newFile("new_state");
+    }
+
+    @Test
+    public void onBackup_noState_backsUpEverything() throws Exception {
+        // no setup needed
+
+        runBackupAgentOnBackup();
+
+        // key/values should be written to backup data
+        ImmutableMap<String, Optional<ByteBuffer>> keyValues = getKeyValues(mBackupData);
+        assertThat(keyValues.keySet())
+                .containsExactly(
+                        PackageManagerBackupAgent.ANCESTRAL_RECORD_KEY,
+                        PackageManagerBackupAgent.GLOBAL_METADATA_KEY,
+                        EXISTING_PACKAGE_NAME)
+                .inOrder();
+        // new state must not be empty
+        assertThat(mNewState.length()).isGreaterThan(0);
+    }
+
+    @Test
+    public void onBackup_recentState_backsUpNothing() throws Exception {
+        try (ParcelFileDescriptor oldStateDescriptor = openForWriting(mOldState)) {
+            PackageManagerBackupAgent.writeStateFile(mPackages, oldStateDescriptor);
+        }
+
+        runBackupAgentOnBackup();
+
+        // We shouldn't have written anything, but a known issue is that we always write the
+        // ancestral record version.
+        ImmutableMap<String, Optional<ByteBuffer>> keyValues = getKeyValues(mBackupData);
+        assertThat(keyValues.keySet())
+                .containsExactly(PackageManagerBackupAgent.ANCESTRAL_RECORD_KEY);
+        assertThat(mNewState.length()).isGreaterThan(0);
+        assertThat(mNewState.length()).isEqualTo(mOldState.length());
+    }
+
+    @Test
+    public void onBackup_oldState_backsUpChanges() throws Exception {
+        String uninstalledPackageName = "does.not.exist";
+        try (ParcelFileDescriptor oldStateDescriptor = openForWriting(mOldState)) {
+            PackageManagerBackupAgent.writeStateFile(
+                    ImmutableList.of(createPackage(uninstalledPackageName, 1)), oldStateDescriptor);
+        }
+
+        runBackupAgentOnBackup();
+
+        // Note that uninstalledPackageName should not exist, i.e. it did not get deleted.
+        ImmutableMap<String, Optional<ByteBuffer>> keyValues = getKeyValues(mBackupData);
+        assertThat(keyValues.keySet())
+                .containsExactly(
+                        PackageManagerBackupAgent.ANCESTRAL_RECORD_KEY, EXISTING_PACKAGE_NAME);
+        assertThat(mNewState.length()).isGreaterThan(0);
+    }
+
+    @Test
+    public void onBackup_legacyState_backsUpEverything() throws Exception {
+        String uninstalledPackageName = "does.not.exist";
+        writeLegacyStateFile(
+                mOldState,
+                ImmutableList.of(createPackage(uninstalledPackageName, 1), mPackages.getFirst()));
+
+        runBackupAgentOnBackup();
+
+        ImmutableMap<String, Optional<ByteBuffer>> keyValues = getKeyValues(mBackupData);
+        assertThat(keyValues.keySet())
+                .containsExactly(
+                        PackageManagerBackupAgent.ANCESTRAL_RECORD_KEY,
+                        PackageManagerBackupAgent.GLOBAL_METADATA_KEY,
+                        EXISTING_PACKAGE_NAME);
+        assertThat(mNewState.length()).isGreaterThan(0);
+    }
+
+    @Test
+    public void onRestore_recentBackup_restoresBackup() throws Exception {
+        runBackupAgentOnBackup();
+
+        runBackupAgentOnRestore();
+
+        assertThat(mPackageManagerBackupAgent.getRestoredPackages())
+                .containsExactly(EXISTING_PACKAGE_NAME);
+        // onRestore does not write to newState
+        assertThat(mNewState.length()).isEqualTo(0);
+    }
+
+    @Test
+    public void onRestore_legacyBackup_restoresBackup() throws Exception {
+        // A legacy backup is one without an ancestral record version. Ancestral record versions
+        // are always written however, so we'll need to delete it from the backup data before
+        // restoring.
+        runBackupAgentOnBackup();
+        deleteKeyFromBackupData(mBackupData, PackageManagerBackupAgent.ANCESTRAL_RECORD_KEY);
+
+        runBackupAgentOnRestore();
+
+        assertThat(mPackageManagerBackupAgent.getRestoredPackages())
+                .containsExactly(EXISTING_PACKAGE_NAME);
+        // onRestore does not write to newState
+        assertThat(mNewState.length()).isEqualTo(0);
+    }
+
+    private void runBackupAgentOnBackup() throws Exception {
+        try (ParcelFileDescriptor oldStateDescriptor = openForReading(mOldState);
+                ParcelFileDescriptor backupDataDescriptor = openForWriting(mBackupData);
+                ParcelFileDescriptor newStateDescriptor = openForWriting(mNewState)) {
+            mPackageManagerBackupAgent.onBackup(
+                    oldStateDescriptor,
+                    new BackupDataOutput(backupDataDescriptor.getFileDescriptor()),
+                    newStateDescriptor);
+        }
+    }
+
+    private void runBackupAgentOnRestore() throws Exception {
+        try (ParcelFileDescriptor backupDataDescriptor = openForReading(mBackupData);
+                ParcelFileDescriptor newStateDescriptor = openForWriting(mNewState)) {
+            mPackageManagerBackupAgent.onRestore(
+                    new BackupDataInput(backupDataDescriptor.getFileDescriptor()),
+                    /* appVersionCode= */ 0,
+                    newStateDescriptor);
+        }
+    }
+
+    private void deleteKeyFromBackupData(File backupData, String key) throws Exception {
+        File temporaryBackupData = folder.newFile("backup_data.tmp");
+        try (ParcelFileDescriptor inputDescriptor = openForReading(backupData);
+                ParcelFileDescriptor outputDescriptor = openForWriting(temporaryBackupData); ) {
+            BackupDataInput input = new BackupDataInput(inputDescriptor.getFileDescriptor());
+            BackupDataOutput output = new BackupDataOutput(outputDescriptor.getFileDescriptor());
+            while (input.readNextHeader()) {
+                if (input.getKey().equals(key)) {
+                    if (input.getDataSize() > 0) {
+                        input.skipEntityData();
+                    }
+                    continue;
+                }
+                output.writeEntityHeader(input.getKey(), input.getDataSize());
+                if (input.getDataSize() < 0) {
+                    input.skipEntityData();
+                } else {
+                    byte[] buf = new byte[input.getDataSize()];
+                    input.readEntityData(buf, 0, buf.length);
+                    output.writeEntityData(buf, buf.length);
+                }
+            }
+        }
+        assertThat(temporaryBackupData.renameTo(backupData)).isTrue();
+    }
+
+    private static PackageInfo createPackage(String name, int versionCode) {
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.packageName = name;
+        packageInfo.versionCodeMajor = versionCode;
+        return packageInfo;
+    }
+
+    /** This creates a legacy state file in which {@code STATE_FILE_HEADER} was not yet present. */
+    private static void writeLegacyStateFile(File stateFile, ImmutableList<PackageInfo> packages)
+            throws Exception {
+        try (ParcelFileDescriptor stateFileDescriptor = openForWriting(stateFile);
+                DataOutputStream out =
+                        new DataOutputStream(
+                                new BufferedOutputStream(
+                                        new FileOutputStream(
+                                                stateFileDescriptor.getFileDescriptor())))) {
+            out.writeUTF(PackageManagerBackupAgent.GLOBAL_METADATA_KEY);
+            out.writeInt(Build.VERSION.SDK_INT);
+            out.writeUTF(Build.VERSION.INCREMENTAL);
+
+            // now write all the app names + versions
+            for (PackageInfo pkg : packages) {
+                out.writeUTF(pkg.packageName);
+                out.writeInt(pkg.versionCode);
+            }
+            out.flush();
+        }
+    }
+
+    /**
+     * Reads the given backup data file and returns a map of key-value pairs. The value is a {@link
+     * ByteBuffer} wrapped in an {@link Optional}, where the empty {@link Optional} represents a key
+     * deletion.
+     */
+    private static ImmutableMap<String, Optional<ByteBuffer>> getKeyValues(File backupData)
+            throws Exception {
+        ImmutableMap.Builder<String, Optional<ByteBuffer>> builder = ImmutableMap.builder();
+        try (ParcelFileDescriptor backupDataDescriptor = openForReading(backupData)) {
+            BackupDataInput backupDataInput =
+                    new BackupDataInput(backupDataDescriptor.getFileDescriptor());
+            while (backupDataInput.readNextHeader()) {
+                ByteBuffer value = null;
+                if (backupDataInput.getDataSize() >= 0) {
+                    byte[] val = new byte[backupDataInput.getDataSize()];
+                    backupDataInput.readEntityData(val, 0, val.length);
+                    value = ByteBuffer.wrap(val);
+                }
+                builder.put(backupDataInput.getKey(), Optional.ofNullable(value));
+            }
+        }
+        return builder.build();
+    }
+
+    private static ParcelFileDescriptor openForWriting(File file) throws Exception {
+        return ParcelFileDescriptor.open(
+                file,
+                ParcelFileDescriptor.MODE_CREATE
+                        | ParcelFileDescriptor.MODE_TRUNCATE
+                        | ParcelFileDescriptor.MODE_WRITE_ONLY);
+    }
+
+    private static ParcelFileDescriptor openForReading(File file) throws Exception {
+        return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
+    }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
index 38a66a9..eeec54f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
@@ -411,6 +411,10 @@
         app2.mAboveInsetsState.addSource(statusBarSource);
         assertTrue(app2.getInsetsState().peekSource(statusBarId).isVisible());
 
+        // Let app2 be the focused window. Otherwise, the control target could be overwritten by
+        // DisplayPolicy#updateSystemBarAttributes unexpectedly.
+        mDisplayContent.getDisplayPolicy().focusChangedLw(null, app2);
+
         app2.setRequestedVisibleTypes(0, navigationBars() | statusBars());
         mDisplayContent.getInsetsPolicy().updateBarControlTarget(app2);
         waitUntilWindowAnimatorIdle();
diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
index 80fb44a..72bedf2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -39,6 +39,8 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeFalse;
 import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -305,12 +307,12 @@
         final WallpaperController wallpaperController = mDisplayContent.mWallpaperController;
         wallpaperController.adjustWallpaperWindows();
         // Wallpaper is visible because the show-when-locked activity is translucent.
-        assertTrue(wallpaperController.isWallpaperTarget(wallpaperWindow));
+        assertSame(wallpaperWindow, wallpaperController.getWallpaperTarget());
 
         behind.mActivityRecord.setShowWhenLocked(true);
         wallpaperController.adjustWallpaperWindows();
         // Wallpaper is invisible because the lowest show-when-locked activity is opaque.
-        assertTrue(wallpaperController.isWallpaperTarget(null));
+        assertNull(wallpaperController.getWallpaperTarget());
 
         // A show-when-locked wallpaper is used for lockscreen. So the top wallpaper should
         // be the one that is not show-when-locked.
@@ -374,10 +376,10 @@
         // The activity in restore-below task should not be the target if keyguard is not locked.
         mDisplayContent.mWallpaperController.adjustWallpaperWindows();
         assertNotEquals(appWin, mDisplayContent.mWallpaperController.getWallpaperTarget());
-        // The activity in restore-below task should be the target if keyguard is occluded.
+        // The activity in restore-below task should not be the target if keyguard is occluded.
         doReturn(true).when(mDisplayContent).isKeyguardLocked();
         mDisplayContent.mWallpaperController.adjustWallpaperWindows();
-        assertEquals(appWin, mDisplayContent.mWallpaperController.getWallpaperTarget());
+        assertNotEquals(appWin, mDisplayContent.mWallpaperController.getWallpaperTarget());
     }
 
     @Test