Loading libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +31 −2 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.wm.shell.dagger; import static android.window.DesktopExperienceFlags.ENABLE_INORDER_TRANSITION_CALLBACKS_FOR_DESKTOP; import static android.window.DesktopExperienceFlags.ENABLE_MULTI_DISPLAY_HOME_FOCUS_BUG_FIX; import static android.window.DesktopExperienceFlags.ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS; import static android.window.DesktopModeFlags.ENABLE_DESKTOP_SYSTEM_DIALOGS_TRANSITIONS; import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_ENTER_TRANSITIONS_BUGFIX; Loading Loading @@ -133,6 +134,7 @@ import com.android.wm.shell.desktopmode.DesktopTasksLimiter; import com.android.wm.shell.desktopmode.DesktopTasksTransitionObserver; import com.android.wm.shell.desktopmode.DesktopUserRepositories; import com.android.wm.shell.desktopmode.DisplayDisconnectTransitionHandler; import com.android.wm.shell.desktopmode.DisplayFocusResolver; import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler; import com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler; import com.android.wm.shell.desktopmode.ExitDesktopTaskTransitionHandler; Loading Loading @@ -1102,7 +1104,8 @@ public abstract class WMShellModule { DesktopState desktopState, Optional<DesktopImeHandler> desktopImeHandler, Optional<DesktopBackNavTransitionObserver> desktopBackNavTransitionObserver, DesktopModeLoggerTransitionObserver desktopModeLoggerTransitionObserver) { DesktopModeLoggerTransitionObserver desktopModeLoggerTransitionObserver, Optional<DisplayFocusResolver> displayFocusResolver) { if (ENABLE_INORDER_TRANSITION_CALLBACKS_FOR_DESKTOP.isTrue() && ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS.isTrue() && desktopState.canEnterDesktopMode()) { Loading @@ -1112,7 +1115,8 @@ public abstract class WMShellModule { desksTransitionObserver, desktopImeHandler, desktopBackNavTransitionObserver, desktopModeLoggerTransitionObserver)); desktopModeLoggerTransitionObserver, displayFocusResolver)); } return Optional.empty(); } Loading Loading @@ -1583,6 +1587,31 @@ public abstract class WMShellModule { shellInit))); } @WMSingleton @Provides static Optional<DisplayFocusResolver> provideDisplayFocusResolver( Transitions transitions, ShellTaskOrganizer shellTaskOrganizer, FocusTransitionObserver focusTransitionObserver, DesktopState desktopState, Optional<DesktopUserRepositories> desktopUserRepositories, Optional<DesktopTasksController> desktopTasksController, ShellInit shellInit) { if (desktopUserRepositories.isPresent() && desktopTasksController.isPresent() && desktopState.canEnterDesktopMode() && ENABLE_MULTI_DISPLAY_HOME_FOCUS_BUG_FIX.isTrue()) { return Optional.of( new DisplayFocusResolver( transitions, shellTaskOrganizer, focusTransitionObserver, desktopUserRepositories.get(), desktopTasksController.get())); } return Optional.empty(); } @WMSingleton @Provides static Optional<DesktopBackNavTransitionObserver> provideDesktopBackNavTransitionObserver( Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopInOrderTransitionObserver.kt +2 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ class DesktopInOrderTransitionObserver( private val desktopImeHandler: Optional<DesktopImeHandler>, private val desktopBackNavTransitionObserver: Optional<DesktopBackNavTransitionObserver>, private val desktopModeLoggerTransitionObserver: DesktopModeLoggerTransitionObserver, private val displayFocusResolver: Optional<DisplayFocusResolver>, ) : Transitions.TransitionObserver { override fun onTransitionReady( Loading Loading @@ -64,6 +65,7 @@ class DesktopInOrderTransitionObserver( desktopImeHandler.ifPresent { it.onTransitionReady(transition, info) } desktopBackNavTransitionObserver.ifPresent { it.onTransitionReady(transition, info) } desktopModeLoggerTransitionObserver.onTransitionReady(transition, info, startT, finishT) displayFocusResolver.ifPresent { it.onTransitionReady(info) } } override fun onTransitionStarting(transition: IBinder) { Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DisplayFocusResolver.kt 0 → 100644 +177 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.wm.shell.desktopmode import android.app.ActivityManager.RunningTaskInfo import android.app.ActivityTaskManager.INVALID_TASK_ID import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD import android.view.Display.INVALID_DISPLAY import android.window.TransitionInfo import android.window.TransitionInfo.FLAG_MOVED_TO_TOP import com.android.internal.protolog.ProtoLog import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.UnminimizeReason import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE import com.android.wm.shell.shared.TransitionUtil import com.android.wm.shell.transition.FocusTransitionObserver import com.android.wm.shell.transition.Transitions /** * A [Transitions.TransitionObserver] that observes shell transitions to manage display focus in * desktop mode. * * When the last desktop task on a display is closed, this class prevents focus from returning to a * non-task surface (like the home screen) on that display. Instead, it attempts to move focus to a * desktop task on another display, if one exists. */ class DisplayFocusResolver( private val transitions: Transitions, private val shellTaskOrganizer: ShellTaskOrganizer, private val focusTransitionObserver: FocusTransitionObserver, private val desktopUserRepositories: DesktopUserRepositories, private val desktopTasksController: DesktopTasksController, ) { private var userId: Int = -1 /** * Observes shell transitions to manage display focus. * * This method is called when a shell transition is ready. It inspects the transition to * determine if a desktop task is closing. If the closing task is the last one on its display, * this method may trigger a focus change to a task on another display to prevent the home * screen from taking focus. * * @param info The [TransitionInfo] for the transition, containing details about the windows * involved. */ fun onTransitionReady(info: TransitionInfo) { handleFocusOnTaskCloseIfNeeded(info) } private fun isDesktopTaskClosingTransitionOnDisplay( info: TransitionInfo, displayId: Int, ): Boolean { for (change in info.changes) { if ( change.taskInfo != null && change.taskInfo?.taskId != INVALID_TASK_ID && change.taskInfo?.displayId == displayId && TransitionUtil.isClosingMode(change.mode) ) { userId = change.taskInfo!!.userId return true } } return false } /** * Finds the task that is being brought to the top on a given display during a transition. This * is identified by the [FLAG_MOVED_TO_TOP] flag. * * @return the [RunningTaskInfo] of the task being focused, or `null` if none is found. */ private fun findNextFocusedTaskInDisplay( info: TransitionInfo, displayId: Int, ): RunningTaskInfo? { val change = info.changes.firstOrNull { it.endDisplayId == displayId && (it.flags and FLAG_MOVED_TO_TOP) != 0 } return change?.taskInfo } /** * Finds the task ID of the top-most expanded desktop task on any display other than the one * that is currently focused. * * @param currentFocusedDisplayId The display that should be excluded from the search. * @return The task ID of the next task to focus, or [INVALID_TASK_ID] if none is found. */ private fun findNextTopDesktopWindowGlobally(currentFocusedDisplayId: Int): Int { val desktopRepository = desktopUserRepositories.getProfile(userId) for (deskId in desktopRepository.getAllDeskIds()) { if (!desktopRepository.isDeskActive(deskId)) continue val expandedTasksInDesk = desktopRepository.getExpandedTasksIdsInDeskOrdered(deskId) if (!expandedTasksInDesk.isEmpty()) { if (desktopRepository.getDisplayForDesk(deskId) == currentFocusedDisplayId) { // This should not happen. If the closing task's display is now empty of // desktop tasks, the repository should reflect that. This is a safeguard. ProtoLog.e( WM_SHELL_DESKTOP_MODE, "Unexpected task found in $currentFocusedDisplayId. This display is " + "empty according to TransitionInfo but not empty in" + "DesktopRepository", ) continue } return expandedTasksInDesk.first() } } return INVALID_TASK_ID } /** * When a desktop task is closed, checks if focus should be moved to a task on another display. * This is done if the closing task was the last standard task on its display, preventing focus * from falling back to the home screen. */ private fun handleFocusOnTaskCloseIfNeeded(info: TransitionInfo) { // TODO: b/436407117 - Re-evaluate with pressing home button scenario. val currentFocusDisplayId = focusTransitionObserver.globallyFocusedDisplayId if ( currentFocusDisplayId == INVALID_DISPLAY || !isDesktopTaskClosingTransitionOnDisplay(info, currentFocusDisplayId) ) { // This logic only applies when a desktop task is closing on the currently focused // display. return } // TODO: b/435099775 - Support DesktopWallpaperActivity val nextFocusedTaskInfo = findNextFocusedTaskInDisplay(info, currentFocusDisplayId) if ( nextFocusedTaskInfo == null || nextFocusedTaskInfo.topActivityType == ACTIVITY_TYPE_STANDARD ) { // If another standard task is becoming focused on the same display, let it proceed. // We only want to intervene if focus is falling back to a non-standard task, // like the home screen. return } // The focused display is now empty of standard tasks. Find a desktop task on another // display to focus instead. val newFocusedTaskId = findNextTopDesktopWindowGlobally(currentFocusDisplayId) if (newFocusedTaskId != INVALID_TASK_ID) { ProtoLog.e( WM_SHELL_DESKTOP_MODE, "Display $currentFocusDisplayId became empty. Moving focus to other display", ) transitions.runOnIdle { desktopTasksController.moveTaskToFront( taskId = newFocusedTaskId, userId = userId, remoteTransition = null, unminimizeReason = UnminimizeReason.UNKNOWN, ) } } } } libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopInOrderTransitionObserverTest.kt +18 −0 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ class DesktopInOrderTransitionObserverTest : ShellTestCase() { private val desktopImeHandler = mock<DesktopImeHandler>() private val desktopBackNavTransitionObserver = mock<DesktopBackNavTransitionObserver>() private val desktopModeLoggerTransitionObserver = mock<DesktopModeLoggerTransitionObserver>() private val displayFocusResolver = mock<DisplayFocusResolver>() private lateinit var transitionObserver: DesktopInOrderTransitionObserver @Before Loading @@ -64,6 +65,7 @@ class DesktopInOrderTransitionObserverTest : ShellTestCase() { Optional.of(desktopImeHandler), Optional.of(desktopBackNavTransitionObserver), desktopModeLoggerTransitionObserver, Optional.of(displayFocusResolver), ) } Loading Loading @@ -188,4 +190,20 @@ class DesktopInOrderTransitionObserverTest : ShellTestCase() { .verify(desktopModeLoggerTransitionObserver) .onTransitionFinished(transition, aborted) } @Test @EnableFlags( Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP, Flags.FLAG_ENABLE_INORDER_TRANSITION_CALLBACKS_FOR_DESKTOP, ) fun onTransitionReady_forwardsToDisplayFocusResolver() { val transition = Mockito.mock(IBinder::class.java) val info = TransitionInfoBuilder(TRANSIT_CHANGE, 0).build() val startT = mock<SurfaceControl.Transaction>() val finishT = mock<SurfaceControl.Transaction>() transitionObserver.onTransitionReady(transition, info, startT, finishT) verify(displayFocusResolver).onTransitionReady(info) } } libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt +2 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ object DesktopTestHelpers { .setParentTaskId(displayId) .setToken(MockToken().token()) .setActivityType(ACTIVITY_TYPE_STANDARD) .setTopActivityType(ACTIVITY_TYPE_STANDARD) .setWindowingMode(WINDOWING_MODE_FREEFORM) .setLastActiveTime(100) .setUserId(userId) Loading Loading @@ -111,6 +112,7 @@ object DesktopTestHelpers { .setDisplayId(displayId) .setToken(MockToken().token()) .setActivityType(ACTIVITY_TYPE_HOME) .setTopActivityType(ACTIVITY_TYPE_HOME) .setWindowingMode(WINDOWING_MODE_FULLSCREEN) .setUserId(userId) .setLastActiveTime(100) Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +31 −2 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.wm.shell.dagger; import static android.window.DesktopExperienceFlags.ENABLE_INORDER_TRANSITION_CALLBACKS_FOR_DESKTOP; import static android.window.DesktopExperienceFlags.ENABLE_MULTI_DISPLAY_HOME_FOCUS_BUG_FIX; import static android.window.DesktopExperienceFlags.ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS; import static android.window.DesktopModeFlags.ENABLE_DESKTOP_SYSTEM_DIALOGS_TRANSITIONS; import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_ENTER_TRANSITIONS_BUGFIX; Loading Loading @@ -133,6 +134,7 @@ import com.android.wm.shell.desktopmode.DesktopTasksLimiter; import com.android.wm.shell.desktopmode.DesktopTasksTransitionObserver; import com.android.wm.shell.desktopmode.DesktopUserRepositories; import com.android.wm.shell.desktopmode.DisplayDisconnectTransitionHandler; import com.android.wm.shell.desktopmode.DisplayFocusResolver; import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler; import com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler; import com.android.wm.shell.desktopmode.ExitDesktopTaskTransitionHandler; Loading Loading @@ -1102,7 +1104,8 @@ public abstract class WMShellModule { DesktopState desktopState, Optional<DesktopImeHandler> desktopImeHandler, Optional<DesktopBackNavTransitionObserver> desktopBackNavTransitionObserver, DesktopModeLoggerTransitionObserver desktopModeLoggerTransitionObserver) { DesktopModeLoggerTransitionObserver desktopModeLoggerTransitionObserver, Optional<DisplayFocusResolver> displayFocusResolver) { if (ENABLE_INORDER_TRANSITION_CALLBACKS_FOR_DESKTOP.isTrue() && ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS.isTrue() && desktopState.canEnterDesktopMode()) { Loading @@ -1112,7 +1115,8 @@ public abstract class WMShellModule { desksTransitionObserver, desktopImeHandler, desktopBackNavTransitionObserver, desktopModeLoggerTransitionObserver)); desktopModeLoggerTransitionObserver, displayFocusResolver)); } return Optional.empty(); } Loading Loading @@ -1583,6 +1587,31 @@ public abstract class WMShellModule { shellInit))); } @WMSingleton @Provides static Optional<DisplayFocusResolver> provideDisplayFocusResolver( Transitions transitions, ShellTaskOrganizer shellTaskOrganizer, FocusTransitionObserver focusTransitionObserver, DesktopState desktopState, Optional<DesktopUserRepositories> desktopUserRepositories, Optional<DesktopTasksController> desktopTasksController, ShellInit shellInit) { if (desktopUserRepositories.isPresent() && desktopTasksController.isPresent() && desktopState.canEnterDesktopMode() && ENABLE_MULTI_DISPLAY_HOME_FOCUS_BUG_FIX.isTrue()) { return Optional.of( new DisplayFocusResolver( transitions, shellTaskOrganizer, focusTransitionObserver, desktopUserRepositories.get(), desktopTasksController.get())); } return Optional.empty(); } @WMSingleton @Provides static Optional<DesktopBackNavTransitionObserver> provideDesktopBackNavTransitionObserver( Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopInOrderTransitionObserver.kt +2 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ class DesktopInOrderTransitionObserver( private val desktopImeHandler: Optional<DesktopImeHandler>, private val desktopBackNavTransitionObserver: Optional<DesktopBackNavTransitionObserver>, private val desktopModeLoggerTransitionObserver: DesktopModeLoggerTransitionObserver, private val displayFocusResolver: Optional<DisplayFocusResolver>, ) : Transitions.TransitionObserver { override fun onTransitionReady( Loading Loading @@ -64,6 +65,7 @@ class DesktopInOrderTransitionObserver( desktopImeHandler.ifPresent { it.onTransitionReady(transition, info) } desktopBackNavTransitionObserver.ifPresent { it.onTransitionReady(transition, info) } desktopModeLoggerTransitionObserver.onTransitionReady(transition, info, startT, finishT) displayFocusResolver.ifPresent { it.onTransitionReady(info) } } override fun onTransitionStarting(transition: IBinder) { Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DisplayFocusResolver.kt 0 → 100644 +177 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.wm.shell.desktopmode import android.app.ActivityManager.RunningTaskInfo import android.app.ActivityTaskManager.INVALID_TASK_ID import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD import android.view.Display.INVALID_DISPLAY import android.window.TransitionInfo import android.window.TransitionInfo.FLAG_MOVED_TO_TOP import com.android.internal.protolog.ProtoLog import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.UnminimizeReason import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE import com.android.wm.shell.shared.TransitionUtil import com.android.wm.shell.transition.FocusTransitionObserver import com.android.wm.shell.transition.Transitions /** * A [Transitions.TransitionObserver] that observes shell transitions to manage display focus in * desktop mode. * * When the last desktop task on a display is closed, this class prevents focus from returning to a * non-task surface (like the home screen) on that display. Instead, it attempts to move focus to a * desktop task on another display, if one exists. */ class DisplayFocusResolver( private val transitions: Transitions, private val shellTaskOrganizer: ShellTaskOrganizer, private val focusTransitionObserver: FocusTransitionObserver, private val desktopUserRepositories: DesktopUserRepositories, private val desktopTasksController: DesktopTasksController, ) { private var userId: Int = -1 /** * Observes shell transitions to manage display focus. * * This method is called when a shell transition is ready. It inspects the transition to * determine if a desktop task is closing. If the closing task is the last one on its display, * this method may trigger a focus change to a task on another display to prevent the home * screen from taking focus. * * @param info The [TransitionInfo] for the transition, containing details about the windows * involved. */ fun onTransitionReady(info: TransitionInfo) { handleFocusOnTaskCloseIfNeeded(info) } private fun isDesktopTaskClosingTransitionOnDisplay( info: TransitionInfo, displayId: Int, ): Boolean { for (change in info.changes) { if ( change.taskInfo != null && change.taskInfo?.taskId != INVALID_TASK_ID && change.taskInfo?.displayId == displayId && TransitionUtil.isClosingMode(change.mode) ) { userId = change.taskInfo!!.userId return true } } return false } /** * Finds the task that is being brought to the top on a given display during a transition. This * is identified by the [FLAG_MOVED_TO_TOP] flag. * * @return the [RunningTaskInfo] of the task being focused, or `null` if none is found. */ private fun findNextFocusedTaskInDisplay( info: TransitionInfo, displayId: Int, ): RunningTaskInfo? { val change = info.changes.firstOrNull { it.endDisplayId == displayId && (it.flags and FLAG_MOVED_TO_TOP) != 0 } return change?.taskInfo } /** * Finds the task ID of the top-most expanded desktop task on any display other than the one * that is currently focused. * * @param currentFocusedDisplayId The display that should be excluded from the search. * @return The task ID of the next task to focus, or [INVALID_TASK_ID] if none is found. */ private fun findNextTopDesktopWindowGlobally(currentFocusedDisplayId: Int): Int { val desktopRepository = desktopUserRepositories.getProfile(userId) for (deskId in desktopRepository.getAllDeskIds()) { if (!desktopRepository.isDeskActive(deskId)) continue val expandedTasksInDesk = desktopRepository.getExpandedTasksIdsInDeskOrdered(deskId) if (!expandedTasksInDesk.isEmpty()) { if (desktopRepository.getDisplayForDesk(deskId) == currentFocusedDisplayId) { // This should not happen. If the closing task's display is now empty of // desktop tasks, the repository should reflect that. This is a safeguard. ProtoLog.e( WM_SHELL_DESKTOP_MODE, "Unexpected task found in $currentFocusedDisplayId. This display is " + "empty according to TransitionInfo but not empty in" + "DesktopRepository", ) continue } return expandedTasksInDesk.first() } } return INVALID_TASK_ID } /** * When a desktop task is closed, checks if focus should be moved to a task on another display. * This is done if the closing task was the last standard task on its display, preventing focus * from falling back to the home screen. */ private fun handleFocusOnTaskCloseIfNeeded(info: TransitionInfo) { // TODO: b/436407117 - Re-evaluate with pressing home button scenario. val currentFocusDisplayId = focusTransitionObserver.globallyFocusedDisplayId if ( currentFocusDisplayId == INVALID_DISPLAY || !isDesktopTaskClosingTransitionOnDisplay(info, currentFocusDisplayId) ) { // This logic only applies when a desktop task is closing on the currently focused // display. return } // TODO: b/435099775 - Support DesktopWallpaperActivity val nextFocusedTaskInfo = findNextFocusedTaskInDisplay(info, currentFocusDisplayId) if ( nextFocusedTaskInfo == null || nextFocusedTaskInfo.topActivityType == ACTIVITY_TYPE_STANDARD ) { // If another standard task is becoming focused on the same display, let it proceed. // We only want to intervene if focus is falling back to a non-standard task, // like the home screen. return } // The focused display is now empty of standard tasks. Find a desktop task on another // display to focus instead. val newFocusedTaskId = findNextTopDesktopWindowGlobally(currentFocusDisplayId) if (newFocusedTaskId != INVALID_TASK_ID) { ProtoLog.e( WM_SHELL_DESKTOP_MODE, "Display $currentFocusDisplayId became empty. Moving focus to other display", ) transitions.runOnIdle { desktopTasksController.moveTaskToFront( taskId = newFocusedTaskId, userId = userId, remoteTransition = null, unminimizeReason = UnminimizeReason.UNKNOWN, ) } } } }
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopInOrderTransitionObserverTest.kt +18 −0 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ class DesktopInOrderTransitionObserverTest : ShellTestCase() { private val desktopImeHandler = mock<DesktopImeHandler>() private val desktopBackNavTransitionObserver = mock<DesktopBackNavTransitionObserver>() private val desktopModeLoggerTransitionObserver = mock<DesktopModeLoggerTransitionObserver>() private val displayFocusResolver = mock<DisplayFocusResolver>() private lateinit var transitionObserver: DesktopInOrderTransitionObserver @Before Loading @@ -64,6 +65,7 @@ class DesktopInOrderTransitionObserverTest : ShellTestCase() { Optional.of(desktopImeHandler), Optional.of(desktopBackNavTransitionObserver), desktopModeLoggerTransitionObserver, Optional.of(displayFocusResolver), ) } Loading Loading @@ -188,4 +190,20 @@ class DesktopInOrderTransitionObserverTest : ShellTestCase() { .verify(desktopModeLoggerTransitionObserver) .onTransitionFinished(transition, aborted) } @Test @EnableFlags( Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP, Flags.FLAG_ENABLE_INORDER_TRANSITION_CALLBACKS_FOR_DESKTOP, ) fun onTransitionReady_forwardsToDisplayFocusResolver() { val transition = Mockito.mock(IBinder::class.java) val info = TransitionInfoBuilder(TRANSIT_CHANGE, 0).build() val startT = mock<SurfaceControl.Transaction>() val finishT = mock<SurfaceControl.Transaction>() transitionObserver.onTransitionReady(transition, info, startT, finishT) verify(displayFocusResolver).onTransitionReady(info) } }
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTestHelpers.kt +2 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ object DesktopTestHelpers { .setParentTaskId(displayId) .setToken(MockToken().token()) .setActivityType(ACTIVITY_TYPE_STANDARD) .setTopActivityType(ACTIVITY_TYPE_STANDARD) .setWindowingMode(WINDOWING_MODE_FREEFORM) .setLastActiveTime(100) .setUserId(userId) Loading Loading @@ -111,6 +112,7 @@ object DesktopTestHelpers { .setDisplayId(displayId) .setToken(MockToken().token()) .setActivityType(ACTIVITY_TYPE_HOME) .setTopActivityType(ACTIVITY_TYPE_HOME) .setWindowingMode(WINDOWING_MODE_FULLSCREEN) .setUserId(userId) .setLastActiveTime(100) Loading