diff options
| author | 2024-10-29 12:46:36 +0000 | |
|---|---|---|
| committer | 2024-10-29 12:46:36 +0000 | |
| commit | cec2ad0c35d561f425b7eb880facc625a677fa35 (patch) | |
| tree | bdcc750753b69c35ced9ba65bf372a3e59e0f6d3 | |
| parent | f0e9f80992782edf1f26dd2262be7cb1c1330718 (diff) | |
| parent | e0fd816d8e0475f122f2dce57bddcacd114f3871 (diff) | |
Merge "Connect DesktopTaskChangeListener with DesktopRepository. This migrates existing code from FreeformTaskListener." into main
8 files changed, 728 insertions, 279 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java index 0942e058bbdc..8d25a9a7fe2d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java @@ -18,6 +18,7 @@ package com.android.wm.shell.dagger; import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_ENTER_TRANSITIONS; import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TASK_LIMIT; +import static android.window.DesktopModeFlags.ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS; import android.annotation.Nullable; import android.app.KeyguardManager; @@ -153,12 +154,7 @@ import java.util.Optional; * <p>This module only defines Shell dependencies for handheld SystemUI implementation. Common * dependencies should go into {@link WMShellBaseModule}. */ -@Module( - includes = { - WMShellBaseModule.class, - PipModule.class, - ShellBackAnimationModule.class - }) +@Module(includes = {WMShellBaseModule.class, PipModule.class, ShellBackAnimationModule.class}) public abstract class WMShellModule { // @@ -173,8 +169,7 @@ public abstract class WMShellModule { @WMSingleton @Provides - static BubblePositioner provideBubblePositioner(Context context, - WindowManager windowManager) { + static BubblePositioner provideBubblePositioner(Context context, WindowManager windowManager) { return new BubblePositioner(context, windowManager); } @@ -186,20 +181,22 @@ public abstract class WMShellModule { @WMSingleton @Provides - static BubbleData provideBubbleData(Context context, + static BubbleData provideBubbleData( + Context context, BubbleLogger logger, BubblePositioner positioner, BubbleEducationController educationController, @ShellMainThread ShellExecutor mainExecutor, @ShellBackgroundThread ShellExecutor bgExecutor) { - return new BubbleData(context, logger, positioner, educationController, mainExecutor, - bgExecutor); + return new BubbleData( + context, logger, positioner, educationController, mainExecutor, bgExecutor); } // Note: Handler needed for LauncherApps.register @WMSingleton @Provides - static BubbleController provideBubbleController(Context context, + static BubbleController provideBubbleController( + Context context, ShellInit shellInit, ShellCommandHandler shellCommandHandler, ShellController shellController, @@ -224,14 +221,38 @@ public abstract class WMShellModule { Transitions transitions, SyncTransactionQueue syncQueue, IWindowManager wmService) { - return new BubbleController(context, shellInit, shellCommandHandler, shellController, data, - null /* synchronizer */, floatingContentCoordinator, - new BubbleDataRepository(launcherApps, mainExecutor, bgExecutor, + return new BubbleController( + context, + shellInit, + shellCommandHandler, + shellController, + data, + null /* synchronizer */, + floatingContentCoordinator, + new BubbleDataRepository( + launcherApps, + mainExecutor, + bgExecutor, new BubblePersistentRepository(context)), - statusBarService, windowManager, windowManagerShellWrapper, userManager, - launcherApps, logger, taskStackListener, organizer, positioner, displayController, - oneHandedOptional, dragAndDropController, mainExecutor, mainHandler, bgExecutor, - taskViewTransitions, transitions, syncQueue, wmService, + statusBarService, + windowManager, + windowManagerShellWrapper, + userManager, + launcherApps, + logger, + taskStackListener, + organizer, + positioner, + displayController, + oneHandedOptional, + dragAndDropController, + mainExecutor, + mainHandler, + bgExecutor, + taskViewTransitions, + transitions, + syncQueue, + wmService, ProdBubbleProperties.INSTANCE); } @@ -318,9 +339,7 @@ public abstract class WMShellModule { @WMSingleton @Provides static AppToWebGenericLinksParser provideGenericLinksParser( - Context context, - @ShellMainThread ShellExecutor mainExecutor - ) { + Context context, @ShellMainThread ShellExecutor mainExecutor) { return new AppToWebGenericLinksParser(context, mainExecutor); } @@ -328,8 +347,7 @@ public abstract class WMShellModule { static AssistContentRequester provideAssistContentRequester( Context context, @ShellMainThread ShellExecutor shellExecutor, - @ShellBackgroundThread ShellExecutor bgExecutor - ) { + @ShellBackgroundThread ShellExecutor bgExecutor) { return new AssistContentRequester(context, shellExecutor, bgExecutor); } @@ -366,15 +384,20 @@ public abstract class WMShellModule { Optional<DesktopRepository> desktopRepository, Optional<DesktopTasksController> desktopTasksController, LaunchAdjacentController launchAdjacentController, - WindowDecorViewModel windowDecorViewModel) { + WindowDecorViewModel windowDecorViewModel, + Optional<TaskChangeListener> taskChangeListener) { // TODO(b/238217847): Temporarily add this check here until we can remove the dynamic // override for this controller from the base module - ShellInit init = FreeformComponents.isFreeformEnabled(context) - ? shellInit - : null; - return new FreeformTaskListener(context, init, shellTaskOrganizer, - desktopRepository, desktopTasksController, launchAdjacentController, - windowDecorViewModel); + ShellInit init = FreeformComponents.isFreeformEnabled(context) ? shellInit : null; + return new FreeformTaskListener( + context, + init, + shellTaskOrganizer, + desktopRepository, + desktopTasksController, + launchAdjacentController, + windowDecorViewModel, + taskChangeListener); } @WMSingleton @@ -385,10 +408,7 @@ public abstract class WMShellModule { @ShellMainThread ShellExecutor mainExecutor, @ShellAnimationThread ShellExecutor animExecutor) { return new FreeformTaskTransitionHandler( - transitions, - displayController, - mainExecutor, - animExecutor); + transitions, displayController, mainExecutor, animExecutor); } @WMSingleton @@ -402,8 +422,13 @@ public abstract class WMShellModule { Optional<TaskChangeListener> taskChangeListener, FocusTransitionObserver focusTransitionObserver) { return new FreeformTaskTransitionObserver( - context, shellInit, transitions, desktopImmersiveController, - windowDecorViewModel, taskChangeListener, focusTransitionObserver); + context, + shellInit, + transitions, + desktopImmersiveController, + windowDecorViewModel, + taskChangeListener, + focusTransitionObserver); } @WMSingleton @@ -419,8 +444,8 @@ public abstract class WMShellModule { } else { transitionStarter = freeformTaskTransitionHandler; } - return new FreeformTaskTransitionStarterInitializer(shellInit, windowDecorViewModel, - transitionStarter); + return new FreeformTaskTransitionStarterInitializer( + shellInit, windowDecorViewModel, transitionStarter); } // @@ -431,7 +456,8 @@ public abstract class WMShellModule { @WMSingleton @Provides @DynamicOverride - static OneHandedController provideOneHandedController(Context context, + static OneHandedController provideOneHandedController( + Context context, ShellInit shellInit, ShellCommandHandler shellCommandHandler, ShellController shellController, @@ -443,9 +469,19 @@ public abstract class WMShellModule { InteractionJankMonitor jankMonitor, @ShellMainThread ShellExecutor mainExecutor, @ShellMainThread Handler mainHandler) { - return OneHandedController.create(context, shellInit, shellCommandHandler, shellController, - windowManager, displayController, displayLayout, taskStackListener, jankMonitor, - uiEventLogger, mainExecutor, mainHandler); + return OneHandedController.create( + context, + shellInit, + shellCommandHandler, + shellController, + windowManager, + displayController, + displayLayout, + taskStackListener, + jankMonitor, + uiEventLogger, + mainExecutor, + mainHandler); } // @@ -477,12 +513,29 @@ public abstract class WMShellModule { MultiInstanceHelper multiInstanceHelper, @ShellMainThread ShellExecutor mainExecutor, @ShellMainThread Handler mainHandler) { - return new SplitScreenController(context, shellInit, shellCommandHandler, shellController, - shellTaskOrganizer, syncQueue, rootTaskDisplayAreaOrganizer, displayController, - displayImeController, displayInsetsController, dragAndDropController, transitions, - transactionPool, iconProvider, recentTasks, launchAdjacentController, - windowDecorViewModel, desktopTasksController, null /* stageCoordinator */, - multiInstanceHelper, mainExecutor, mainHandler); + return new SplitScreenController( + context, + shellInit, + shellCommandHandler, + shellController, + shellTaskOrganizer, + syncQueue, + rootTaskDisplayAreaOrganizer, + displayController, + displayImeController, + displayInsetsController, + dragAndDropController, + transitions, + transactionPool, + iconProvider, + recentTasks, + launchAdjacentController, + windowDecorViewModel, + desktopTasksController, + null /* stageCoordinator */, + multiInstanceHelper, + mainExecutor, + mainHandler); } // @@ -502,10 +555,16 @@ public abstract class WMShellModule { Optional<UnfoldTransitionHandler> unfoldHandler, Optional<ActivityEmbeddingController> activityEmbeddingController, Transitions transitions) { - return new DefaultMixedHandler(shellInit, transitions, splitScreenOptional, - pipTransitionController, recentsTransitionHandler, - keyguardTransitionHandler, desktopTasksController, - unfoldHandler, activityEmbeddingController); + return new DefaultMixedHandler( + shellInit, + transitions, + splitScreenOptional, + pipTransitionController, + recentsTransitionHandler, + keyguardTransitionHandler, + desktopTasksController, + unfoldHandler, + activityEmbeddingController); } @WMSingleton @@ -516,8 +575,12 @@ public abstract class WMShellModule { Transitions transitions, Optional<RecentTasksController> recentTasksController, HomeTransitionObserver homeTransitionObserver) { - return new RecentsTransitionHandler(shellInit, shellTaskOrganizer, transitions, - recentTasksController.orElse(null), homeTransitionObserver); + return new RecentsTransitionHandler( + shellInit, + shellTaskOrganizer, + transitions, + recentTasksController.orElse(null), + homeTransitionObserver); } // @@ -534,8 +597,7 @@ public abstract class WMShellModule { FullscreenUnfoldTaskAnimator fullscreenAnimator, Lazy<Optional<UnfoldTransitionHandler>> unfoldTransitionHandler, ShellInit shellInit, - @ShellMainThread ShellExecutor mainExecutor - ) { + @ShellMainThread ShellExecutor mainExecutor) { final List<UnfoldTaskAnimator> animators = new ArrayList<>(); animators.add(splitAnimator); animators.add(fullscreenAnimator); @@ -546,8 +608,7 @@ public abstract class WMShellModule { progressProvider.get(), animators, unfoldTransitionHandler, - mainExecutor - ); + mainExecutor); } @Provides @@ -555,10 +616,9 @@ public abstract class WMShellModule { Context context, UnfoldBackgroundController unfoldBackgroundController, ShellController shellController, - DisplayInsetsController displayInsetsController - ) { - return new FullscreenUnfoldTaskAnimator(context, unfoldBackgroundController, - shellController, displayInsetsController); + DisplayInsetsController displayInsetsController) { + return new FullscreenUnfoldTaskAnimator( + context, unfoldBackgroundController, shellController, displayInsetsController); } @Provides @@ -568,14 +628,18 @@ public abstract class WMShellModule { ShellController shellController, @ShellMainThread ShellExecutor executor, Lazy<Optional<SplitScreenController>> splitScreenOptional, - DisplayInsetsController displayInsetsController - ) { + DisplayInsetsController displayInsetsController) { // TODO(b/238217847): The lazy reference here causes some dependency issues since it // immediately registers a listener on that controller on init. We should reference the // controller directly once we refactor ShellTaskOrganizer to not depend on the unfold // animation controller directly. - return new SplitTaskUnfoldAnimator(context, executor, splitScreenOptional, - shellController, backgroundController, displayInsetsController); + return new SplitTaskUnfoldAnimator( + context, + executor, + splitScreenOptional, + shellController, + backgroundController, + displayInsetsController); } @WMSingleton @@ -602,8 +666,15 @@ public abstract class WMShellModule { @ShellMainThread ShellExecutor executor, @ShellMainThread Handler handler, ShellInit shellInit) { - return new UnfoldTransitionHandler(shellInit, progressProvider.get(), animator, - unfoldAnimator, transactionPool, executor, handler, transitions); + return new UnfoldTransitionHandler( + shellInit, + progressProvider.get(), + animator, + unfoldAnimator, + transactionPool, + executor, + handler, + transitions); } @WMSingleton @@ -652,18 +723,38 @@ public abstract class WMShellModule { FocusTransitionObserver focusTransitionObserver, DesktopModeEventLogger desktopModeEventLogger, DesktopTilingDecorViewModel desktopTilingDecorViewModel) { - return new DesktopTasksController(context, shellInit, shellCommandHandler, shellController, - displayController, shellTaskOrganizer, syncQueue, rootTaskDisplayAreaOrganizer, - dragAndDropController, transitions, keyguardManager, - returnToDragStartAnimator, enterDesktopTransitionHandler, - exitDesktopTransitionHandler, desktopModeDragAndDropTransitionHandler, + return new DesktopTasksController( + context, + shellInit, + shellCommandHandler, + shellController, + displayController, + shellTaskOrganizer, + syncQueue, + rootTaskDisplayAreaOrganizer, + dragAndDropController, + transitions, + keyguardManager, + returnToDragStartAnimator, + enterDesktopTransitionHandler, + exitDesktopTransitionHandler, + desktopModeDragAndDropTransitionHandler, toggleResizeDesktopTaskTransitionHandler, - dragToDesktopTransitionHandler, desktopImmersiveController.get(), + dragToDesktopTransitionHandler, + desktopImmersiveController.get(), desktopRepository, - desktopModeLoggerTransitionObserver, launchAdjacentController, - recentsTransitionHandler, multiInstanceHelper, mainExecutor, desktopTasksLimiter, - recentTasksController.orElse(null), interactionJankMonitor, mainHandler, - inputManager, focusTransitionObserver, desktopModeEventLogger, + desktopModeLoggerTransitionObserver, + launchAdjacentController, + recentsTransitionHandler, + multiInstanceHelper, + mainExecutor, + desktopTasksLimiter, + recentTasksController.orElse(null), + interactionJankMonitor, + mainHandler, + inputManager, + focusTransitionObserver, + desktopModeEventLogger, desktopTilingDecorViewModel); } @@ -693,10 +784,11 @@ public abstract class WMShellModule { @WMSingleton @Provides - static Optional<TaskChangeListener> provideDesktopTaskChangeListener(Context context) { - if (Flags.enableWindowingTransitionHandlersObservers() && - DesktopModeStatus.canEnterDesktopMode(context)) { - return Optional.of(new DesktopTaskChangeListener()); + static Optional<TaskChangeListener> provideDesktopTaskChangeListener( + Context context, @DynamicOverride DesktopRepository desktopRepository) { + if (ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS.isTrue() + && DesktopModeStatus.canEnterDesktopMode(context)) { + return Optional.of(new DesktopTaskChangeListener(desktopRepository)); } return Optional.empty(); } @@ -724,8 +816,7 @@ public abstract class WMShellModule { maxTaskLimit, interactionJankMonitor, context, - handler) - ); + handler)); } @WMSingleton @@ -739,10 +830,7 @@ public abstract class WMShellModule { if (DesktopModeStatus.canEnterDesktopMode(context)) { return Optional.of( new DesktopImmersiveController( - transitions, - desktopRepository, - displayController, - shellTaskOrganizer)); + transitions, desktopRepository, displayController, shellTaskOrganizer)); } return Optional.empty(); } @@ -754,7 +842,6 @@ public abstract class WMShellModule { return new ReturnToDragStartAnimator(context, interactionJankMonitor); } - @WMSingleton @Provides static DragToDesktopTransitionHandler provideDragToDesktopTransitionHandler( @@ -762,12 +849,12 @@ public abstract class WMShellModule { Transitions transitions, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, InteractionJankMonitor interactionJankMonitor) { - return (Flags.enableDesktopWindowingTransitions() || - ENABLE_DESKTOP_WINDOWING_ENTER_TRANSITIONS.isTrue()) - ? new SpringDragToDesktopTransitionHandler(context, transitions, - rootTaskDisplayAreaOrganizer, interactionJankMonitor) - : new DefaultDragToDesktopTransitionHandler(context, transitions, - rootTaskDisplayAreaOrganizer, interactionJankMonitor); + return (Flags.enableDesktopWindowingTransitions() + || ENABLE_DESKTOP_WINDOWING_ENTER_TRANSITIONS.isTrue()) + ? new SpringDragToDesktopTransitionHandler( + context, transitions, rootTaskDisplayAreaOrganizer, interactionJankMonitor) + : new DefaultDragToDesktopTransitionHandler( + context, transitions, rootTaskDisplayAreaOrganizer, interactionJankMonitor); } @WMSingleton @@ -802,31 +889,26 @@ public abstract class WMShellModule { static CloseDesktopTaskTransitionHandler provideCloseDesktopTaskTransitionHandler( Context context, @ShellMainThread ShellExecutor mainExecutor, - @ShellAnimationThread ShellExecutor animExecutor - ) { + @ShellAnimationThread ShellExecutor animExecutor) { return new CloseDesktopTaskTransitionHandler(context, mainExecutor, animExecutor); } @WMSingleton @Provides static DesktopModeDragAndDropTransitionHandler provideDesktopModeDragAndDropTransitionHandler( - Transitions transitions - ) { + Transitions transitions) { return new DesktopModeDragAndDropTransitionHandler(transitions); } @WMSingleton @Provides @DynamicOverride - static DesktopRepository provideDesktopRepository( Context context, ShellInit shellInit, DesktopPersistentRepository desktopPersistentRepository, - @ShellMainThread CoroutineScope mainScope - ) { - return new DesktopRepository(context, shellInit, desktopPersistentRepository, - mainScope); + @ShellMainThread CoroutineScope mainScope) { + return new DesktopRepository(context, shellInit, desktopPersistentRepository, mainScope); } @WMSingleton @@ -837,12 +919,16 @@ public abstract class WMShellModule { ShellTaskOrganizer shellTaskOrganizer, TaskStackListenerImpl taskStackListener, ToggleResizeDesktopTaskTransitionHandler toggleResizeDesktopTaskTransitionHandler, - @DynamicOverride DesktopRepository desktopRepository - ) { + @DynamicOverride DesktopRepository desktopRepository) { if (DesktopModeStatus.canEnterDesktopMode(context)) { - return Optional.of(new DesktopActivityOrientationChangeHandler( - context, shellInit, shellTaskOrganizer, taskStackListener, - toggleResizeDesktopTaskTransitionHandler, desktopRepository)); + return Optional.of( + new DesktopActivityOrientationChangeHandler( + context, + shellInit, + shellTaskOrganizer, + taskStackListener, + toggleResizeDesktopTaskTransitionHandler, + desktopRepository)); } return Optional.empty(); } @@ -854,12 +940,16 @@ public abstract class WMShellModule { Optional<DesktopRepository> desktopRepository, Transitions transitions, ShellTaskOrganizer shellTaskOrganizer, - ShellInit shellInit - ) { - return desktopRepository.flatMap(repository -> - Optional.of(new DesktopTasksTransitionObserver( - context, repository, transitions, shellTaskOrganizer, shellInit)) - ); + ShellInit shellInit) { + return desktopRepository.flatMap( + repository -> + Optional.of( + new DesktopTasksTransitionObserver( + context, + repository, + transitions, + shellTaskOrganizer, + shellInit))); } @WMSingleton @@ -871,8 +961,7 @@ public abstract class WMShellModule { FreeformTaskTransitionHandler freeformTaskTransitionHandler, CloseDesktopTaskTransitionHandler closeDesktopTaskTransitionHandler, InteractionJankMonitor interactionJankMonitor, - @ShellMainThread Handler handler - ) { + @ShellMainThread Handler handler) { if (!DesktopModeStatus.canEnterDesktopMode(context)) { return Optional.empty(); } @@ -929,12 +1018,11 @@ public abstract class WMShellModule { @Provides static DesktopWindowingEducationTooltipController provideDesktopWindowingEducationTooltipController( - Context context, - AdditionalSystemViewContainer.Factory additionalSystemViewContainerFactory, - DisplayController displayController - ) { - return new DesktopWindowingEducationTooltipController(context, - additionalSystemViewContainerFactory, displayController); + Context context, + AdditionalSystemViewContainer.Factory additionalSystemViewContainerFactory, + DisplayController displayController) { + return new DesktopWindowingEducationTooltipController( + context, additionalSystemViewContainerFactory, displayController); } @OptIn(markerClass = ExperimentalCoroutinesApi.class) @@ -946,19 +1034,22 @@ public abstract class WMShellModule { AppHandleEducationDatastoreRepository appHandleEducationDatastoreRepository, WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository, DesktopWindowingEducationTooltipController desktopWindowingEducationTooltipController, - @ShellMainThread CoroutineScope applicationScope, @ShellBackgroundThread - MainCoroutineDispatcher backgroundDispatcher) { - return new AppHandleEducationController(context, appHandleEducationFilter, - appHandleEducationDatastoreRepository, windowDecorCaptionHandleRepository, - desktopWindowingEducationTooltipController, applicationScope, + @ShellMainThread CoroutineScope applicationScope, + @ShellBackgroundThread MainCoroutineDispatcher backgroundDispatcher) { + return new AppHandleEducationController( + context, + appHandleEducationFilter, + appHandleEducationDatastoreRepository, + windowDecorCaptionHandleRepository, + desktopWindowingEducationTooltipController, + applicationScope, backgroundDispatcher); } @WMSingleton @Provides static DesktopPersistentRepository provideDesktopPersistentRepository( - Context context, - @ShellBackgroundThread CoroutineScope bgScope) { + Context context, @ShellBackgroundThread CoroutineScope bgScope) { return new DesktopPersistentRepository(context, bgScope); } @@ -969,14 +1060,14 @@ public abstract class WMShellModule { @WMSingleton @Provides static GlobalDragListener provideGlobalDragListener( - IWindowManager wmService, - @ShellMainThread ShellExecutor mainExecutor) { + IWindowManager wmService, @ShellMainThread ShellExecutor mainExecutor) { return new GlobalDragListener(wmService, mainExecutor); } @WMSingleton @Provides - static DragAndDropController provideDragAndDropController(Context context, + static DragAndDropController provideDragAndDropController( + Context context, ShellInit shellInit, ShellController shellController, ShellCommandHandler shellCommandHandler, @@ -987,9 +1078,18 @@ public abstract class WMShellModule { GlobalDragListener globalDragListener, Transitions transitions, @ShellMainThread ShellExecutor mainExecutor) { - return new DragAndDropController(context, shellInit, shellController, shellCommandHandler, - shellTaskOrganizer, displayController, uiEventLogger, iconProvider, - globalDragListener, transitions, mainExecutor); + return new DragAndDropController( + context, + shellInit, + shellController, + shellCommandHandler, + shellTaskOrganizer, + displayController, + uiEventLogger, + iconProvider, + globalDragListener, + transitions, + mainExecutor); } // @@ -1003,8 +1103,7 @@ public abstract class WMShellModule { @Provides static Object provideIndependentShellComponentsToCreate( DragAndDropController dragAndDropController, - Optional<DesktopTasksTransitionObserver> desktopTasksTransitionObserverOptional - ) { + Optional<DesktopTasksTransitionObserver> desktopTasksTransitionObserverOptional) { return new Object(); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt index 1ee2de958e55..237a465cccbb 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt @@ -17,21 +17,60 @@ package com.android.wm.shell.desktopmode import android.app.ActivityManager.RunningTaskInfo +import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM +import android.window.DesktopModeFlags import com.android.wm.shell.freeform.TaskChangeListener /** Manages tasks handling specific to Android Desktop Mode. */ -class DesktopTaskChangeListener: TaskChangeListener { +class DesktopTaskChangeListener( + private val desktopRepository: DesktopRepository, +) : TaskChangeListener { override fun onTaskOpening(taskInfo: RunningTaskInfo) { - // TODO: b/367268953 - Connect this with DesktopRepository. + if (!isFreeformTask(taskInfo) && desktopRepository.isActiveTask(taskInfo.taskId)) { + desktopRepository.removeFreeformTask(taskInfo.displayId, taskInfo.taskId) + return + } + if (isFreeformTask(taskInfo)) { + desktopRepository.addOrMoveFreeformTaskToTop(taskInfo.displayId, taskInfo.taskId) + if (taskInfo.isVisible) { + desktopRepository.addActiveTask(taskInfo.displayId, taskInfo.taskId) + desktopRepository.updateTaskVisibility(taskInfo.displayId, taskInfo.taskId, visible = true) + } + } } override fun onTaskChanging(taskInfo: RunningTaskInfo) { - // TODO: b/367268953 - Connect this with DesktopRepository. + if (!desktopRepository.isActiveTask(taskInfo.taskId)) return + + // Case 1: Freeform task is changed in Desktop Mode. + if (isFreeformTask(taskInfo)) { + if (taskInfo.isVisible) { + desktopRepository.addActiveTask(taskInfo.displayId, taskInfo.taskId) + } + desktopRepository.updateTaskVisibility( + taskInfo.displayId, taskInfo.taskId, taskInfo.isVisible) + } else { + // Case 2: Freeform task is changed outside Desktop Mode. + desktopRepository.removeFreeformTask(taskInfo.displayId, taskInfo.taskId) + } + } + + // This method should only be used for scenarios where the task info changes are not propagated to + // [DesktopTaskChangeListener#onTaskChanging] via [TransitionsObserver]. + // Any changes to [DesktopRepository] from this method should be made carefully to minimize risk + // of race conditions and possible duplications with [onTaskChanging]. + override fun onNonTransitionTaskChanging(taskInfo: RunningTaskInfo) { + // TODO: b/367268953 - Propapagate usages from FreeformTaskListener to this method. } override fun onTaskMovingToFront(taskInfo: RunningTaskInfo) { - // TODO: b/367268953 - Connect this with DesktopRepository. + if (!desktopRepository.isActiveTask(taskInfo.taskId)) return + if (!isFreeformTask(taskInfo)) { + desktopRepository.removeFreeformTask(taskInfo.displayId, taskInfo.taskId) + } + // TODO: b/367268953 - Connect this with DesktopRepository for handling + // task moving to front for tasks in windowing mode. } override fun onTaskMovingToBack(taskInfo: RunningTaskInfo) { @@ -39,6 +78,20 @@ class DesktopTaskChangeListener: TaskChangeListener { } override fun onTaskClosing(taskInfo: RunningTaskInfo) { - // TODO: b/367268953 - Connect this with DesktopRepository. + if (!desktopRepository.isActiveTask(taskInfo.taskId)) return + // TODO: b/370038902 - Handle Activity#finishAndRemoveTask. + if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue() || + desktopRepository.isClosingTask(taskInfo.taskId)) { + // A task that's vanishing should be removed: + // - If it's closed by the X button which means it's marked as a closing task. + desktopRepository.removeClosingTask(taskInfo.taskId) + desktopRepository.removeFreeformTask(taskInfo.displayId, taskInfo.taskId) + } else { + desktopRepository.updateTaskVisibility(taskInfo.displayId, taskInfo.taskId, visible = false) + desktopRepository.minimizeTask(taskInfo.displayId, taskInfo.taskId) + } } + + private fun isFreeformTask(taskInfo: RunningTaskInfo): Boolean = + taskInfo.windowingMode == WINDOWING_MODE_FREEFORM } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java index a16446fffa15..af87ab7eab5c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java @@ -17,7 +17,6 @@ package com.android.wm.shell.freeform; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; - import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_FREEFORM; import android.app.ActivityManager.RunningTaskInfo; @@ -54,6 +53,7 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener, private final Optional<DesktopTasksController> mDesktopTasksController; private final WindowDecorViewModel mWindowDecorationViewModel; private final LaunchAdjacentController mLaunchAdjacentController; + private final Optional<TaskChangeListener> mTaskChangeListener; private final SparseArray<State> mTasks = new SparseArray<>(); @@ -69,13 +69,15 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener, Optional<DesktopRepository> desktopRepository, Optional<DesktopTasksController> desktopTasksController, LaunchAdjacentController launchAdjacentController, - WindowDecorViewModel windowDecorationViewModel) { + WindowDecorViewModel windowDecorationViewModel, + Optional<TaskChangeListener> taskChangeListener) { mContext = context; mShellTaskOrganizer = shellTaskOrganizer; mWindowDecorationViewModel = windowDecorationViewModel; mDesktopRepository = desktopRepository; mDesktopTasksController = desktopTasksController; mLaunchAdjacentController = launchAdjacentController; + mTaskChangeListener = taskChangeListener; if (shellInit != null) { shellInit.addInitCallback(this::onInit, this); } @@ -100,7 +102,8 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener, state.mLeash = leash; mTasks.put(taskInfo.taskId, state); - if (DesktopModeStatus.canEnterDesktopMode(mContext)) { + if (!DesktopModeFlags.ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS.isTrue() && + DesktopModeStatus.canEnterDesktopMode(mContext)) { mDesktopRepository.ifPresent(repository -> { repository.addOrMoveFreeformTaskToTop(taskInfo.displayId, taskInfo.taskId); if (taskInfo.isVisible) { @@ -119,7 +122,8 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener, taskInfo.taskId); mTasks.remove(taskInfo.taskId); - if (DesktopModeStatus.canEnterDesktopMode(mContext)) { + if (!DesktopModeFlags.ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS.isTrue() && + DesktopModeStatus.canEnterDesktopMode(mContext)) { mDesktopRepository.ifPresent(repository -> { // TODO: b/370038902 - Handle Activity#finishAndRemoveTask. if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue() @@ -148,13 +152,20 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener, mWindowDecorationViewModel.onTaskInfoChanged(taskInfo); state.mTaskInfo = taskInfo; if (DesktopModeStatus.canEnterDesktopMode(mContext)) { - mDesktopRepository.ifPresent(repository -> { - if (taskInfo.isVisible) { - repository.addActiveTask(taskInfo.displayId, taskInfo.taskId); - } - repository.updateTaskVisibility(taskInfo.displayId, taskInfo.taskId, + if (DesktopModeFlags.ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS.isTrue()) { + // Pass task info changes to the [TaskChangeListener] since [TransitionsObserver] + // does not propagate all task info changes. + mTaskChangeListener.ifPresent(listener -> + listener.onNonTransitionTaskChanging(taskInfo)); + } else { + mDesktopRepository.ifPresent(repository -> { + if (taskInfo.isVisible) { + repository.addActiveTask(taskInfo.displayId, taskInfo.taskId); + } + repository.updateTaskVisibility(taskInfo.displayId, taskInfo.taskId, taskInfo.isVisible); - }); + }); + } } updateLaunchAdjacentController(); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java index 7631ece761b5..18f9cc758e38 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java @@ -42,9 +42,9 @@ import java.util.Map; import java.util.Optional; /** - * The {@link Transitions.TransitionHandler} that handles freeform task launches, closes, - * maximizing and restoring transitions. It also reports transitions so that window decorations can - * be a part of transitions. + * The {@link Transitions.TransitionHandler} that handles freeform task launches, closes, maximizing + * and restoring transitions. It also reports transitions so that window decorations can be a part + * of transitions. */ public class FreeformTaskTransitionObserver implements Transitions.TransitionObserver { private final Transitions mTransitions; @@ -89,8 +89,8 @@ public class FreeformTaskTransitionObserver implements Transitions.TransitionObs // TODO(b/367268953): Remove when DesktopTaskListener is introduced and the repository // is updated from there **before** the |mWindowDecorViewModel| methods are invoked. // Otherwise window decoration relayout won't run with the immersive state up to date. - mDesktopImmersiveController.ifPresent(h -> - h.onTransitionReady(transition, info, startT, finishT)); + mDesktopImmersiveController.ifPresent( + h -> h.onTransitionReady(transition, info, startT, finishT)); } // Update focus state first to ensure the correct state can be queried from listeners. // TODO(371503964): Remove this once the unified task repository is ready. @@ -147,33 +147,28 @@ public class FreeformTaskTransitionObserver implements Transitions.TransitionObs TransitionInfo.Change change, SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT) { - mTaskChangeListener.ifPresent( - listener -> listener.onTaskOpening(change.getTaskInfo())); + mTaskChangeListener.ifPresent(listener -> listener.onTaskOpening(change.getTaskInfo())); mWindowDecorViewModel.onTaskOpening( - change.getTaskInfo(), change.getLeash(), startT, finishT); + change.getTaskInfo(), change.getLeash(), startT, finishT); } private void onCloseTransitionReady( TransitionInfo.Change change, SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT) { - mTaskChangeListener.ifPresent( - listener -> listener.onTaskClosing(change.getTaskInfo())); + mTaskChangeListener.ifPresent(listener -> listener.onTaskClosing(change.getTaskInfo())); mWindowDecorViewModel.onTaskClosing(change.getTaskInfo(), startT, finishT); - } private void onChangeTransitionReady( TransitionInfo.Change change, SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT) { - mTaskChangeListener.ifPresent(listener -> - listener.onTaskChanging(change.getTaskInfo())); + mTaskChangeListener.ifPresent(listener -> listener.onTaskChanging(change.getTaskInfo())); mWindowDecorViewModel.onTaskChanging( change.getTaskInfo(), change.getLeash(), startT, finishT); } - private void onToFrontTransitionReady( TransitionInfo.Change change, SurfaceControl.Transaction startT, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/TaskChangeListener.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/TaskChangeListener.kt index f07c069bb420..fb86a9febf7d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/TaskChangeListener.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/TaskChangeListener.kt @@ -16,7 +16,7 @@ package com.android.wm.shell.freeform -import android.app.ActivityManager.RunningTaskInfo; +import android.app.ActivityManager.RunningTaskInfo /** * Interface used by [FreeformTaskTransitionObserver] to manage freeform tasks. @@ -24,18 +24,27 @@ import android.app.ActivityManager.RunningTaskInfo; * The implementations are responsible for handle all the task management. */ interface TaskChangeListener { - /** Notifies a task opening in freeform mode. */ - fun onTaskOpening(taskInfo: RunningTaskInfo) + /** Notifies a task opening in freeform mode. */ + fun onTaskOpening(taskInfo: RunningTaskInfo) - /** Notifies a task info update on the given task. */ - fun onTaskChanging(taskInfo: RunningTaskInfo) + /** Notifies a task info update on the given task from Shell Transitions framework. */ + fun onTaskChanging(taskInfo: RunningTaskInfo) - /** Notifies a task moving to the front. */ - fun onTaskMovingToFront(taskInfo: RunningTaskInfo) + /** + * Notifies a task info update on the given task from [FreeformTaskListener]. + * + * This is used to propagate task info changes since not all task changes are propagated from + * [TransitionObserver] in [onTaskChanging]. It is recommended to use [onTaskChanging] instead of + * this method where possible. + */ + fun onNonTransitionTaskChanging(taskInfo: RunningTaskInfo) - /** Notifies a task moving to the back. */ - fun onTaskMovingToBack(taskInfo: RunningTaskInfo) + /** Notifies a task moving to the front. */ + fun onTaskMovingToFront(taskInfo: RunningTaskInfo) - /** Notifies a task is closing. */ - fun onTaskClosing(taskInfo: RunningTaskInfo) -}
\ No newline at end of file + /** Notifies a task moving to the back. */ + fun onTaskMovingToBack(taskInfo: RunningTaskInfo) + + /** Notifies a task is closing. */ + fun onTaskClosing(taskInfo: RunningTaskInfo) +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt new file mode 100644 index 000000000000..8ae8b0fd7afc --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt @@ -0,0 +1,180 @@ +/* + * 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.wm.shell.desktopmode + +import android.platform.test.annotations.DisableFlags +import android.platform.test.annotations.EnableFlags +import android.platform.test.flag.junit.SetFlagsRule +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION +import com.android.wm.shell.ShellTestCase +import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask +import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFullscreenTask +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.mock +import org.mockito.kotlin.never +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever + +/** + * Tests for {@link DesktopTaskChangeListener} + * + * Build/Install/Run: atest WMShellUnitTests:DesktopTaskChangeListenerTest + */ +@SmallTest +@RunWith(AndroidTestingRunner::class) +class DesktopTaskChangeListenerTest : ShellTestCase() { + + @JvmField @Rule val setFlagsRule = SetFlagsRule() + + private lateinit var desktopTaskChangeListener: DesktopTaskChangeListener + + private val desktopRepository = mock<DesktopRepository>() + + @Before + fun setUp() { + desktopTaskChangeListener = DesktopTaskChangeListener(desktopRepository) + } + + @Test + fun onTaskOpening_fullscreenTask_notActiveDesktopTask_noop() { + val task = createFullscreenTask().apply { isVisible = true } + whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(false) + + desktopTaskChangeListener.onTaskOpening(task) + + verify(desktopRepository, never()).addOrMoveFreeformTaskToTop(task.displayId, task.taskId) + verify(desktopRepository, never()).removeFreeformTask(task.displayId, task.taskId) + } + + @Test + fun onTaskOpening_freeformTask_activeDesktopTask_removesTaskFromRepo() { + val task = createFullscreenTask().apply { isVisible = true } + whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(true) + + desktopTaskChangeListener.onTaskOpening(task) + + verify(desktopRepository).removeFreeformTask(task.displayId, task.taskId) + } + + @Test + fun onTaskOpening_freeformTask_visibleDesktopTask_addsTaskToRepository() { + val task = createFreeformTask().apply { isVisible = true } + whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(false) + + desktopTaskChangeListener.onTaskOpening(task) + + verify(desktopRepository).addOrMoveFreeformTaskToTop(task.displayId, task.taskId) + verify(desktopRepository).addActiveTask(task.displayId, task.taskId) + verify(desktopRepository).updateTaskVisibility(task.displayId, task.taskId, visible = true) + } + + @Test + fun onTaskOpening_freeformTask_nonVisibleDesktopTask_addsTaskToRepository() { + val task = createFreeformTask().apply { isVisible = false } + whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(true) + + desktopTaskChangeListener.onTaskOpening(task) + + verify(desktopRepository).addOrMoveFreeformTaskToTop(task.displayId, task.taskId) + } + + @Test + fun onTaskChanging_freeformTaskOutsideDesktop_removesTaskFromRepo() { + val task = createFullscreenTask().apply { isVisible = true } + whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(true) + + desktopTaskChangeListener.onTaskChanging(task) + + verify(desktopRepository).removeFreeformTask(task.displayId, task.taskId) + } + + @Test + fun onTaskChanging_visibleTaskInDesktop_updatesTaskVisibility() { + val task = createFreeformTask().apply { isVisible = true } + whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(true) + + desktopTaskChangeListener.onTaskChanging(task) + + verify(desktopRepository).addActiveTask(task.displayId, task.taskId) + verify(desktopRepository).updateTaskVisibility(task.displayId, task.taskId, task.isVisible) + } + + @Test + fun onTaskChanging_nonVisibleTask_updatesTaskVisibility() { + val task = createFreeformTask().apply { isVisible = false } + whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(true) + + desktopTaskChangeListener.onTaskChanging(task) + + verify(desktopRepository).updateTaskVisibility(task.displayId, task.taskId, task.isVisible) + } + + @Test + fun onTaskMovingToFront_freeformTaskOutsideDesktop_removesTaskFromRepo() { + val task = createFullscreenTask().apply { isVisible = true } + whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(true) + + desktopTaskChangeListener.onTaskMovingToFront(task) + + verify(desktopRepository).removeFreeformTask(task.displayId, task.taskId) + } + + @Test + @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION) + fun onTaskClosing_backNavEnabled_nonClosingTask_minimizesTaskInRepo() { + val task = createFreeformTask().apply { isVisible = true } + whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(true) + whenever(desktopRepository.isClosingTask(task.taskId)).thenReturn(false) + + desktopTaskChangeListener.onTaskClosing(task) + + verify(desktopRepository).updateTaskVisibility(task.displayId, task.taskId, visible = false) + verify(desktopRepository).minimizeTask(task.displayId, task.taskId) + } + + @Test + @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION) + fun onTaskClosing_backNavDisabled_closingTask_removesTaskInRepo() { + val task = createFreeformTask().apply { isVisible = true } + whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(true) + whenever(desktopRepository.isClosingTask(task.taskId)).thenReturn(true) + + desktopTaskChangeListener.onTaskClosing(task) + + verify(desktopRepository, never()).minimizeTask(task.displayId, task.taskId) + verify(desktopRepository).removeClosingTask(task.taskId) + verify(desktopRepository).removeFreeformTask(task.displayId, task.taskId) + } + + @Test + @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION) + fun onTaskClosing_backNavEnabled_closingTask_removesTaskFromRepo() { + val task = createFreeformTask().apply { isVisible = true } + whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(true) + whenever(desktopRepository.isClosingTask(task.taskId)).thenReturn(true) + + desktopTaskChangeListener.onTaskClosing(task) + + verify(desktopRepository).removeClosingTask(task.taskId) + verify(desktopRepository).removeFreeformTask(task.displayId, task.taskId) + } +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java index 8dd154566361..0a5397a89b77 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskListenerTests.java @@ -23,13 +23,17 @@ import static android.view.Display.INVALID_DISPLAY; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION; +import static com.android.window.flags.Flags.FLAG_ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS; +import static com.android.window.flags.Flags.FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.ActivityManager; +import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.SetFlagsRule; import android.view.SurfaceControl; @@ -59,9 +63,8 @@ import org.mockito.quality.Strictness; import java.util.Optional; /** - * Tests for {@link FreeformTaskListener} - * Build/Install/Run: - * atest WMShellUnitTests:FreeformTaskListenerTests + * Tests for {@link FreeformTaskListener} Build/Install/Run: atest + * WMShellUnitTests:FreeformTaskListenerTests */ @SmallTest @RunWith(AndroidJUnit4.class) @@ -84,41 +87,96 @@ public final class FreeformTaskListenerTests extends ShellTestCase { private DesktopTasksController mDesktopTasksController; @Mock private LaunchAdjacentController mLaunchAdjacentController; + @Mock + private TaskChangeListener mTaskChangeListener; + private FreeformTaskListener mFreeformTaskListener; private StaticMockitoSession mMockitoSession; @Before public void setup() { - mMockitoSession = mockitoSession().initMocks(this) - .strictness(Strictness.LENIENT).mockStatic(DesktopModeStatus.class).startMocking(); + mMockitoSession = + mockitoSession() + .initMocks(this) + .strictness(Strictness.LENIENT) + .mockStatic(DesktopModeStatus.class) + .startMocking(); doReturn(true).when(() -> DesktopModeStatus.canEnterDesktopMode(any())); - mFreeformTaskListener = new FreeformTaskListener( - mContext, - mShellInit, - mTaskOrganizer, - Optional.of(mDesktopRepository), - Optional.of(mDesktopTasksController), - mLaunchAdjacentController, - mWindowDecorViewModel); + mFreeformTaskListener = + new FreeformTaskListener( + mContext, + mShellInit, + mTaskOrganizer, + Optional.of(mDesktopRepository), + Optional.of(mDesktopTasksController), + mLaunchAdjacentController, + mWindowDecorViewModel, + Optional.of(mTaskChangeListener)); + } + + @Test + @DisableFlags(FLAG_ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS) + public void onTaskAppeared_noTransitionObservers_visibleTask_addsTaskToRepo() { + ActivityManager.RunningTaskInfo task = + new TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build(); + task.isVisible = true; + + mFreeformTaskListener.onTaskAppeared(task, mMockSurfaceControl); + + verify(mDesktopRepository).addOrMoveFreeformTaskToTop(task.displayId, task.taskId); + verify(mDesktopRepository).addActiveTask(task.displayId, task.taskId); + verify(mDesktopRepository) + .updateTaskVisibility(task.displayId, task.taskId, task.isVisible); + } + + @Test + @DisableFlags(FLAG_ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS) + public void onTaskAppeared_noTransitionObservers_nonVisibleTask_addsTaskToRepo() { + ActivityManager.RunningTaskInfo task = + new TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build(); + task.isVisible = false; + + mFreeformTaskListener.onTaskAppeared(task, mMockSurfaceControl); + + verify(mDesktopRepository).addOrMoveFreeformTaskToTop(task.displayId, task.taskId); + verify(mDesktopRepository, never()).addActiveTask(task.displayId, task.taskId); + verify(mDesktopRepository, never()) + .updateTaskVisibility(task.displayId, task.taskId, task.isVisible); + } + + @Test + @EnableFlags(FLAG_ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS) + public void onTaskAppeared_useTransitionObserver_noopInRepository() { + ActivityManager.RunningTaskInfo task = + new TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build(); + task.isVisible = true; + + mFreeformTaskListener.onTaskAppeared(task, mMockSurfaceControl); + + verify(mDesktopRepository, never()).addOrMoveFreeformTaskToTop(task.displayId, task.taskId); + verify(mDesktopRepository, never()).addActiveTask(task.displayId, task.taskId); + verify(mDesktopRepository, never()) + .updateTaskVisibility(task.displayId, task.taskId, task.isVisible); } @Test - public void testFocusTaskChanged_freeformTaskIsAddedToRepo() { - ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder() - .setWindowingMode(WINDOWING_MODE_FREEFORM).build(); + public void focusTaskChanged_addsFreeformTaskToRepo() { + ActivityManager.RunningTaskInfo task = + new TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build(); task.isFocused = true; mFreeformTaskListener.onFocusTaskChanged(task); - verify(mDesktopRepository) - .addOrMoveFreeformTaskToTop(task.displayId, task.taskId); + verify(mDesktopRepository).addOrMoveFreeformTaskToTop(task.displayId, task.taskId); } @Test - public void testFocusTaskChanged_fullscreenTaskIsNotAddedToRepo() { - ActivityManager.RunningTaskInfo fullscreenTask = new TestRunningTaskInfoBuilder() - .setWindowingMode(WINDOWING_MODE_FULLSCREEN).build(); + public void focusTaskChanged_fullscreenTaskNotAddedToRepo() { + ActivityManager.RunningTaskInfo fullscreenTask = + new TestRunningTaskInfoBuilder() + .setWindowingMode(WINDOWING_MODE_FULLSCREEN) + .build(); fullscreenTask.isFocused = true; mFreeformTaskListener.onFocusTaskChanged(fullscreenTask); @@ -128,9 +186,9 @@ public final class FreeformTaskListenerTests extends ShellTestCase { } @Test - public void testVisibilityTaskChanged_visible_setLaunchAdjacentDisabled() { - ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder() - .setWindowingMode(WINDOWING_MODE_FREEFORM).build(); + public void visibilityTaskChanged_visible_setLaunchAdjacentDisabled() { + ActivityManager.RunningTaskInfo task = + new TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build(); task.isVisible = true; mFreeformTaskListener.onTaskAppeared(task, mMockSurfaceControl); @@ -139,9 +197,9 @@ public final class FreeformTaskListenerTests extends ShellTestCase { } @Test - public void testVisibilityTaskChanged_NotVisible_setLaunchAdjacentEnabled() { - ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder() - .setWindowingMode(WINDOWING_MODE_FREEFORM).build(); + public void visibilityTaskChanged_notVisible_setLaunchAdjacentEnabled() { + ActivityManager.RunningTaskInfo task = + new TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build(); task.isVisible = true; mFreeformTaskListener.onTaskAppeared(task, mMockSurfaceControl); @@ -154,9 +212,10 @@ public final class FreeformTaskListenerTests extends ShellTestCase { @Test @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION) - public void onTaskVanished_nonClosingTask_isMinimized() { - ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder() - .setWindowingMode(WINDOWING_MODE_FREEFORM).build(); + @DisableFlags(FLAG_ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS) + public void onTaskVanished_nonClosingTask_noTransitionObservers_isMinimized() { + ActivityManager.RunningTaskInfo task = + new TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build(); task.isVisible = true; mFreeformTaskListener.onTaskAppeared(task, mMockSurfaceControl); @@ -169,10 +228,11 @@ public final class FreeformTaskListenerTests extends ShellTestCase { } @Test + @DisableFlags(FLAG_ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS) @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION) - public void onTaskVanished_closingTask_isNotMinimized() { - ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder() - .setWindowingMode(WINDOWING_MODE_FREEFORM).build(); + public void onTaskVanished_closingTask_noTransitionObservers_isNotMinimized() { + ActivityManager.RunningTaskInfo task = + new TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build(); task.isVisible = true; mFreeformTaskListener.onTaskAppeared(task, mMockSurfaceControl); @@ -188,9 +248,23 @@ public final class FreeformTaskListenerTests extends ShellTestCase { } @Test + @EnableFlags(FLAG_ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS) + public void onTaskVanished_usesTransitionObservers_noopInRepo() { + ActivityManager.RunningTaskInfo task = + new TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build(); + mFreeformTaskListener.onTaskAppeared(task, mMockSurfaceControl); + + mFreeformTaskListener.onTaskVanished(task); + + verify(mDesktopRepository, never()).minimizeTask(task.displayId, task.taskId); + verify(mDesktopRepository, never()).removeClosingTask(task.taskId); + verify(mDesktopRepository, never()).removeFreeformTask(task.displayId, task.taskId); + } + + @Test public void onTaskInfoChanged_withDesktopController_forwards() { - ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder() - .setWindowingMode(WINDOWING_MODE_FREEFORM).build(); + ActivityManager.RunningTaskInfo task = + new TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build(); task.isVisible = true; mFreeformTaskListener.onTaskAppeared(task, mMockSurfaceControl); @@ -199,6 +273,38 @@ public final class FreeformTaskListenerTests extends ShellTestCase { verify(mDesktopTasksController).onTaskInfoChanged(task); } + @Test + @DisableFlags(FLAG_ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS) + public void onTaskInfoChanged_noTransitionObservers_updatesTaskVisibility() { + ActivityManager.RunningTaskInfo task = + new TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build(); + task.isVisible = true; + mFreeformTaskListener.onTaskAppeared(task, mMockSurfaceControl); + + mFreeformTaskListener.onTaskInfoChanged(task); + + verify(mTaskChangeListener, never()).onTaskChanging(any()); + verify(mDesktopRepository, times(2)).addActiveTask(task.displayId, task.taskId); + verify(mDesktopRepository, times(2)) + .updateTaskVisibility(task.displayId, task.taskId, task.isVisible); + } + + @Test + @EnableFlags(FLAG_ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS) + @DisableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION) + public void onTaskInfoChanged_useTransitionObserver_noopInRepository() { + ActivityManager.RunningTaskInfo task = + new TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build(); + task.isVisible = true; + mFreeformTaskListener.onTaskAppeared(task, mMockSurfaceControl); + + mFreeformTaskListener.onTaskInfoChanged(task); + + verify(mTaskChangeListener).onNonTransitionTaskChanging(any()); + verify(mDesktopRepository, never()) + .updateTaskVisibility(task.displayId, task.taskId, task.isVisible); + } + @After public void tearDown() { mMockitoSession.finishMocking(); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java index 90ab2b8285cd..5aed4611cdc8 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java @@ -58,25 +58,17 @@ import org.mockito.MockitoAnnotations; import java.util.Optional; -/** - * Tests for {@link FreeformTaskTransitionObserver}. - */ +/** Tests for {@link FreeformTaskTransitionObserver}. */ @SmallTest public class FreeformTaskTransitionObserverTest { public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); - @Mock - private ShellInit mShellInit; - @Mock - private Transitions mTransitions; - @Mock - private DesktopImmersiveController mDesktopImmersiveController; - @Mock - private WindowDecorViewModel mWindowDecorViewModel; - @Mock - private TaskChangeListener mTaskChangeListener; - @Mock - private FocusTransitionObserver mFocusTransitionObserver; + @Mock private ShellInit mShellInit; + @Mock private Transitions mTransitions; + @Mock private DesktopImmersiveController mDesktopImmersiveController; + @Mock private WindowDecorViewModel mWindowDecorViewModel; + @Mock private TaskChangeListener mTaskChangeListener; + @Mock private FocusTransitionObserver mFocusTransitionObserver; private FreeformTaskTransitionObserver mTransitionObserver; @@ -85,20 +77,22 @@ public class FreeformTaskTransitionObserverTest { MockitoAnnotations.initMocks(this); PackageManager pm = mock(PackageManager.class); - doReturn(true).when(pm).hasSystemFeature( - PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT); + doReturn(true).when(pm).hasSystemFeature(PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT); final Context context = mock(Context.class); doReturn(pm).when(context).getPackageManager(); - mTransitionObserver = new FreeformTaskTransitionObserver( - context, mShellInit, mTransitions, - Optional.of(mDesktopImmersiveController), - mWindowDecorViewModel, Optional.of(mTaskChangeListener), mFocusTransitionObserver); - - final ArgumentCaptor<Runnable> initRunnableCaptor = ArgumentCaptor.forClass( - Runnable.class); - verify(mShellInit).addInitCallback(initRunnableCaptor.capture(), - same(mTransitionObserver)); + mTransitionObserver = + new FreeformTaskTransitionObserver( + context, + mShellInit, + mTransitions, + Optional.of(mDesktopImmersiveController), + mWindowDecorViewModel, + Optional.of(mTaskChangeListener), + mFocusTransitionObserver); + + final ArgumentCaptor<Runnable> initRunnableCaptor = ArgumentCaptor.forClass(Runnable.class); + verify(mShellInit).addInitCallback(initRunnableCaptor.capture(), same(mTransitionObserver)); initRunnableCaptor.getValue().run(); } @@ -109,10 +103,9 @@ public class FreeformTaskTransitionObserverTest { @Test public void openTransition_createsWindowDecor() { - final TransitionInfo.Change change = - createChange(TRANSIT_OPEN, 1, WINDOWING_MODE_FREEFORM); - final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN, 0) - .addChange(change).build(); + final TransitionInfo.Change change = createChange(TRANSIT_OPEN, 1, WINDOWING_MODE_FREEFORM); + final TransitionInfo info = + new TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(change).build(); final IBinder transition = mock(IBinder.class); final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class); @@ -120,16 +113,15 @@ public class FreeformTaskTransitionObserverTest { mTransitionObserver.onTransitionReady(transition, info, startT, finishT); mTransitionObserver.onTransitionStarting(transition); - verify(mWindowDecorViewModel).onTaskOpening( - change.getTaskInfo(), change.getLeash(), startT, finishT); + verify(mWindowDecorViewModel) + .onTaskOpening(change.getTaskInfo(), change.getLeash(), startT, finishT); } @Test public void openTransition_notifiesOnTaskOpening() { - final TransitionInfo.Change change = - createChange(TRANSIT_OPEN, 1, WINDOWING_MODE_FREEFORM); - final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN, 0) - .addChange(change).build(); + final TransitionInfo.Change change = createChange(TRANSIT_OPEN, 1, WINDOWING_MODE_FREEFORM); + final TransitionInfo info = + new TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(change).build(); final IBinder transition = mock(IBinder.class); final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class); @@ -144,8 +136,10 @@ public class FreeformTaskTransitionObserverTest { public void toFrontTransition_notifiesOnTaskMovingToFront() { final TransitionInfo.Change change = createChange(TRANSIT_TO_FRONT, /* taskId= */ 1, WINDOWING_MODE_FREEFORM); - final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_TO_FRONT, /* flags= */ 0) - .addChange(change).build(); + final TransitionInfo info = + new TransitionInfoBuilder(TRANSIT_TO_FRONT, /* flags= */ 0) + .addChange(change) + .build(); final IBinder transition = mock(IBinder.class); final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class); @@ -160,8 +154,10 @@ public class FreeformTaskTransitionObserverTest { public void toBackTransition_notifiesOnTaskMovingToBack() { final TransitionInfo.Change change = createChange(TRANSIT_TO_BACK, /* taskId= */ 1, WINDOWING_MODE_FREEFORM); - final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_TO_BACK, /* flags= */ 0) - .addChange(change).build(); + final TransitionInfo info = + new TransitionInfoBuilder(TRANSIT_TO_BACK, /* flags= */ 0) + .addChange(change) + .build(); final IBinder transition = mock(IBinder.class); final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class); @@ -173,11 +169,11 @@ public class FreeformTaskTransitionObserverTest { } @Test - public void changeTransition_notifiesOnTaskChanging() { + public void changeTransition_notifiesOnTaskChange() { final TransitionInfo.Change change = createChange(TRANSIT_CHANGE, /* taskId= */ 1, WINDOWING_MODE_FREEFORM); - final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_CHANGE, /* flags= */ 0) - .addChange(change).build(); + final TransitionInfo info = + new TransitionInfoBuilder(TRANSIT_CHANGE, /* flags= */ 0).addChange(change).build(); final IBinder transition = mock(IBinder.class); final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class); @@ -192,8 +188,8 @@ public class FreeformTaskTransitionObserverTest { public void closeTransition_preparesWindowDecor() { final TransitionInfo.Change change = createChange(TRANSIT_CLOSE, 1, WINDOWING_MODE_FREEFORM); - final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_CLOSE, 0) - .addChange(change).build(); + final TransitionInfo info = + new TransitionInfoBuilder(TRANSIT_CLOSE, 0).addChange(change).build(); final IBinder transition = mock(IBinder.class); final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class); @@ -201,16 +197,15 @@ public class FreeformTaskTransitionObserverTest { mTransitionObserver.onTransitionReady(transition, info, startT, finishT); mTransitionObserver.onTransitionStarting(transition); - verify(mWindowDecorViewModel).onTaskClosing( - change.getTaskInfo(), startT, finishT); + verify(mWindowDecorViewModel).onTaskClosing(change.getTaskInfo(), startT, finishT); } @Test public void closeTransition_notifiesOnTaskClosing() { final TransitionInfo.Change change = createChange(TRANSIT_CLOSE, 1, WINDOWING_MODE_FREEFORM); - final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_CLOSE, 0) - .addChange(change).build(); + final TransitionInfo info = + new TransitionInfoBuilder(TRANSIT_CLOSE, 0).addChange(change).build(); final IBinder transition = mock(IBinder.class); final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class); @@ -225,8 +220,8 @@ public class FreeformTaskTransitionObserverTest { public void closeTransition_doesntCloseWindowDecorDuringTransition() throws Exception { final TransitionInfo.Change change = createChange(TRANSIT_CLOSE, 1, WINDOWING_MODE_FREEFORM); - final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_CLOSE, 0) - .addChange(change).build(); + final TransitionInfo info = + new TransitionInfoBuilder(TRANSIT_CLOSE, 0).addChange(change).build(); final IBinder transition = mock(IBinder.class); final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class); @@ -241,8 +236,8 @@ public class FreeformTaskTransitionObserverTest { public void closeTransition_closesWindowDecorAfterTransition() throws Exception { final TransitionInfo.Change change = createChange(TRANSIT_CLOSE, 1, WINDOWING_MODE_FREEFORM); - final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_CLOSE, 0) - .addChange(change).build(); + final TransitionInfo info = + new TransitionInfoBuilder(TRANSIT_CLOSE, 0).addChange(change).build(); final AutoCloseable windowDecor = mock(AutoCloseable.class); @@ -261,8 +256,8 @@ public class FreeformTaskTransitionObserverTest { // The playing transition final TransitionInfo.Change change1 = createChange(TRANSIT_OPEN, 1, WINDOWING_MODE_FREEFORM); - final TransitionInfo info1 = new TransitionInfoBuilder(TRANSIT_OPEN, 0) - .addChange(change1).build(); + final TransitionInfo info1 = + new TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(change1).build(); final IBinder transition1 = mock(IBinder.class); final SurfaceControl.Transaction startT1 = mock(SurfaceControl.Transaction.class); @@ -273,8 +268,8 @@ public class FreeformTaskTransitionObserverTest { // The merged transition final TransitionInfo.Change change2 = createChange(TRANSIT_CLOSE, 2, WINDOWING_MODE_FREEFORM); - final TransitionInfo info2 = new TransitionInfoBuilder(TRANSIT_CLOSE, 0) - .addChange(change2).build(); + final TransitionInfo info2 = + new TransitionInfoBuilder(TRANSIT_CLOSE, 0).addChange(change2).build(); final IBinder transition2 = mock(IBinder.class); final SurfaceControl.Transaction startT2 = mock(SurfaceControl.Transaction.class); @@ -292,8 +287,8 @@ public class FreeformTaskTransitionObserverTest { // The playing transition final TransitionInfo.Change change1 = createChange(TRANSIT_CLOSE, 1, WINDOWING_MODE_FREEFORM); - final TransitionInfo info1 = new TransitionInfoBuilder(TRANSIT_CLOSE, 0) - .addChange(change1).build(); + final TransitionInfo info1 = + new TransitionInfoBuilder(TRANSIT_CLOSE, 0).addChange(change1).build(); final IBinder transition1 = mock(IBinder.class); final SurfaceControl.Transaction startT1 = mock(SurfaceControl.Transaction.class); @@ -304,8 +299,8 @@ public class FreeformTaskTransitionObserverTest { // The merged transition final TransitionInfo.Change change2 = createChange(TRANSIT_CLOSE, 2, WINDOWING_MODE_FREEFORM); - final TransitionInfo info2 = new TransitionInfoBuilder(TRANSIT_CLOSE, 0) - .addChange(change2).build(); + final TransitionInfo info2 = + new TransitionInfoBuilder(TRANSIT_CLOSE, 0).addChange(change2).build(); final IBinder transition2 = mock(IBinder.class); final SurfaceControl.Transaction startT2 = mock(SurfaceControl.Transaction.class); @@ -368,9 +363,10 @@ public class FreeformTaskTransitionObserverTest { taskInfo.taskId = taskId; taskInfo.configuration.windowConfiguration.setWindowingMode(windowingMode); - final TransitionInfo.Change change = new TransitionInfo.Change( - new WindowContainerToken(mock(IWindowContainerToken.class)), - mock(SurfaceControl.class)); + final TransitionInfo.Change change = + new TransitionInfo.Change( + new WindowContainerToken(mock(IWindowContainerToken.class)), + mock(SurfaceControl.class)); change.setMode(mode); change.setTaskInfo(taskInfo); return change; |