diff options
| author | 2024-11-26 23:07:53 +0000 | |
|---|---|---|
| committer | 2024-11-26 23:07:53 +0000 | |
| commit | 60b9c6ea9ab19a9cc026d6b715aa6e0e8bf643d7 (patch) | |
| tree | 93fc461327c291f7a3655ff0fac0dba07c08cef9 | |
| parent | dd56cbca41b8bf803186770a11a9a4472b7e8d73 (diff) | |
| parent | 5c5ec0c92e5cfc81588e79bf9ac016cddb6cd6f5 (diff) | |
Merge "Update Desktop Mode repositories to be user-aware." into main
49 files changed, 910 insertions, 406 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java index c99d9ba862c1..9d4b4bbb33de 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java @@ -54,6 +54,7 @@ import com.android.wm.shell.compatui.api.CompatUIEvent; import com.android.wm.shell.compatui.api.CompatUIHandler; import com.android.wm.shell.compatui.api.CompatUIInfo; import com.android.wm.shell.compatui.impl.CompatUIEvents.SizeCompatRestartButtonClicked; +import com.android.wm.shell.desktopmode.DesktopUserRepositories; import com.android.wm.shell.sysui.KeyguardChangeListener; import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; @@ -65,6 +66,7 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.HashSet; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.function.Consumer; import java.util.function.Function; @@ -194,7 +196,7 @@ public class CompatUIController implements OnDisplaysChangedListener, private final CompatUIStatusManager mCompatUIStatusManager; @NonNull - private final IntPredicate mInDesktopModePredicate; + private final Optional<DesktopUserRepositories> mDesktopUserRepositories; public CompatUIController(@NonNull Context context, @NonNull ShellInit shellInit, @@ -210,7 +212,7 @@ public class CompatUIController implements OnDisplaysChangedListener, @NonNull CompatUIShellCommandHandler compatUIShellCommandHandler, @NonNull AccessibilityManager accessibilityManager, @NonNull CompatUIStatusManager compatUIStatusManager, - @NonNull IntPredicate isDesktopModeEnablePredicate) { + @NonNull Optional<DesktopUserRepositories> desktopUserRepositories) { mContext = context; mShellController = shellController; mDisplayController = displayController; @@ -226,7 +228,7 @@ public class CompatUIController implements OnDisplaysChangedListener, mDisappearTimeSupplier = flags -> accessibilityManager.getRecommendedTimeoutMillis( DISAPPEAR_DELAY_MS, flags); mCompatUIStatusManager = compatUIStatusManager; - mInDesktopModePredicate = isDesktopModeEnablePredicate; + mDesktopUserRepositories = desktopUserRepositories; shellInit.addInitCallback(this::onInit, this); } @@ -267,7 +269,6 @@ public class CompatUIController implements OnDisplaysChangedListener, updateActiveTaskInfo(taskInfo); } - // We're showing the first reachability education so we ignore incoming TaskInfo // until the education flow has completed or we double tap. The double-tap // basically cancel all the onboarding flow. We don't have to ignore events in case @@ -865,7 +866,11 @@ public class CompatUIController implements OnDisplaysChangedListener, } private boolean isInDesktopMode(@Nullable TaskInfo taskInfo) { - return taskInfo != null && Flags.skipCompatUiEducationInDesktopMode() - && mInDesktopModePredicate.test(taskInfo.displayId); + if (mDesktopUserRepositories.isEmpty() || taskInfo == null) { + return false; + } + boolean isDesktopModeShowing = mDesktopUserRepositories.get().getCurrent() + .getVisibleTaskCount(taskInfo.displayId) > 0; + return Flags.skipCompatUiEducationInDesktopMode() && isDesktopModeShowing; } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java index cb9c20e9b7ec..47084e17d029 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java @@ -87,8 +87,8 @@ import com.android.wm.shell.compatui.impl.DefaultCompatUIHandler; import com.android.wm.shell.compatui.impl.DefaultCompatUIRepository; import com.android.wm.shell.compatui.impl.DefaultComponentIdGenerator; import com.android.wm.shell.desktopmode.DesktopMode; -import com.android.wm.shell.desktopmode.DesktopRepository; import com.android.wm.shell.desktopmode.DesktopTasksController; +import com.android.wm.shell.desktopmode.DesktopUserRepositories; import com.android.wm.shell.displayareahelper.DisplayAreaHelper; import com.android.wm.shell.displayareahelper.DisplayAreaHelperController; import com.android.wm.shell.freeform.FreeformComponents; @@ -138,7 +138,6 @@ import dagger.Module; import dagger.Provides; import java.util.Optional; -import java.util.function.IntPredicate; /** * Provides basic dependencies from {@link com.android.wm.shell}, these dependencies are only @@ -267,7 +266,7 @@ public abstract class WMShellBaseModule { Lazy<CompatUIShellCommandHandler> compatUIShellCommandHandler, Lazy<AccessibilityManager> accessibilityManager, CompatUIRepository compatUIRepository, - Optional<DesktopRepository> desktopRepository, + Optional<DesktopUserRepositories> desktopUserRepositories, @NonNull CompatUIState compatUIState, @NonNull CompatUIComponentIdGenerator componentIdGenerator, @NonNull CompatUIComponentFactory compatUIComponentFactory, @@ -280,10 +279,6 @@ public abstract class WMShellBaseModule { new DefaultCompatUIHandler(compatUIRepository, compatUIState, componentIdGenerator, compatUIComponentFactory, mainExecutor)); } - final IntPredicate inDesktopModePredicate = - desktopRepository.<IntPredicate>map(modeTaskRepository -> displayId -> - modeTaskRepository.getVisibleTaskCount(displayId) > 0) - .orElseGet(() -> displayId -> false); return Optional.of( new CompatUIController( context, @@ -300,7 +295,7 @@ public abstract class WMShellBaseModule { compatUIShellCommandHandler.get(), accessibilityManager.get(), compatUIStatusManager, - inDesktopModePredicate)); + desktopUserRepositories)); } @WMSingleton @@ -704,14 +699,14 @@ public abstract class WMShellBaseModule { ShellCommandHandler shellCommandHandler, TaskStackListenerImpl taskStackListener, ActivityTaskManager activityTaskManager, - Optional<DesktopRepository> desktopRepository, + Optional<DesktopUserRepositories> desktopUserRepositories, TaskStackTransitionObserver taskStackTransitionObserver, @ShellMainThread ShellExecutor mainExecutor ) { return Optional.ofNullable( RecentTasksController.create(context, shellInit, shellController, shellCommandHandler, taskStackListener, activityTaskManager, - desktopRepository, taskStackTransitionObserver, mainExecutor)); + desktopUserRepositories, taskStackTransitionObserver, mainExecutor)); } @BindsOptionalOf @@ -1002,16 +997,16 @@ public abstract class WMShellBaseModule { @BindsOptionalOf @DynamicOverride - abstract DesktopRepository optionalDesktopRepository(); + abstract DesktopUserRepositories optionalDesktopUserRepositories(); @WMSingleton @Provides - static Optional<DesktopRepository> provideDesktopRepository(Context context, - @DynamicOverride Optional<Lazy<DesktopRepository>> desktopRepository) { + static Optional<DesktopUserRepositories> provideDesktopUserRepositories(Context context, + @DynamicOverride Optional<Lazy<DesktopUserRepositories>> desktopUserRepositories) { // Use optional-of-lazy for the dependency that this provider relies on. // Lazy ensures that this provider will not be the cause the dependency is created // when it will not be returned due to the condition below. - return desktopRepository.flatMap((lazy) -> { + return desktopUserRepositories.flatMap((lazy) -> { if (DesktopModeStatus.canEnterDesktopMode(context)) { return Optional.of(lazy.get()); } 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 bdf598eec859..14cabe16416c 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 @@ -92,6 +92,7 @@ import com.android.wm.shell.desktopmode.DesktopTaskChangeListener; import com.android.wm.shell.desktopmode.DesktopTasksController; 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.DragToDesktopTransitionHandler; import com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler; import com.android.wm.shell.desktopmode.ExitDesktopTaskTransitionHandler; @@ -363,7 +364,7 @@ public abstract class WMShellModule { Context context, ShellInit shellInit, ShellTaskOrganizer shellTaskOrganizer, - Optional<DesktopRepository> desktopRepository, + Optional<DesktopUserRepositories> desktopUserRepositories, Optional<DesktopTasksController> desktopTasksController, LaunchAdjacentController launchAdjacentController, WindowDecorViewModel windowDecorViewModel, @@ -375,7 +376,7 @@ public abstract class WMShellModule { context, init, shellTaskOrganizer, - desktopRepository, + desktopUserRepositories, desktopTasksController, launchAdjacentController, windowDecorViewModel, @@ -691,7 +692,7 @@ public abstract class WMShellModule { DesktopModeDragAndDropTransitionHandler desktopModeDragAndDropTransitionHandler, ToggleResizeDesktopTaskTransitionHandler toggleResizeDesktopTaskTransitionHandler, DragToDesktopTransitionHandler dragToDesktopTransitionHandler, - @DynamicOverride DesktopRepository desktopRepository, + @DynamicOverride DesktopUserRepositories desktopUserRepositories, Optional<DesktopImmersiveController> desktopImmersiveController, DesktopModeLoggerTransitionObserver desktopModeLoggerTransitionObserver, LaunchAdjacentController launchAdjacentController, @@ -727,7 +728,7 @@ public abstract class WMShellModule { toggleResizeDesktopTaskTransitionHandler, dragToDesktopTransitionHandler, desktopImmersiveController.get(), - desktopRepository, + desktopUserRepositories, recentsTransitionHandler, multiInstanceHelper, mainExecutor, @@ -750,7 +751,7 @@ public abstract class WMShellModule { ShellTaskOrganizer shellTaskOrganizer, ToggleResizeDesktopTaskTransitionHandler toggleResizeDesktopTaskTransitionHandler, ReturnToDragStartAnimator returnToDragStartAnimator, - @DynamicOverride DesktopRepository desktopRepository, + @DynamicOverride DesktopUserRepositories desktopUserRepositories, DesktopModeEventLogger desktopModeEventLogger) { return new DesktopTilingDecorViewModel( context, @@ -761,7 +762,7 @@ public abstract class WMShellModule { shellTaskOrganizer, toggleResizeDesktopTaskTransitionHandler, returnToDragStartAnimator, - desktopRepository, + desktopUserRepositories, desktopModeEventLogger ); } @@ -769,10 +770,10 @@ public abstract class WMShellModule { @WMSingleton @Provides static Optional<TaskChangeListener> provideDesktopTaskChangeListener( - Context context, @DynamicOverride DesktopRepository desktopRepository) { + Context context, @DynamicOverride DesktopUserRepositories desktopUserRepositories) { if (ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS.isTrue() && DesktopModeStatus.canEnterDesktopMode(context)) { - return Optional.of(new DesktopTaskChangeListener(desktopRepository)); + return Optional.of(new DesktopTaskChangeListener(desktopUserRepositories)); } return Optional.empty(); } @@ -782,7 +783,7 @@ public abstract class WMShellModule { static Optional<DesktopTasksLimiter> provideDesktopTasksLimiter( Context context, Transitions transitions, - @DynamicOverride DesktopRepository desktopRepository, + @DynamicOverride DesktopUserRepositories desktopUserRepositories, ShellTaskOrganizer shellTaskOrganizer, InteractionJankMonitor interactionJankMonitor, @ShellMainThread Handler handler) { @@ -795,7 +796,7 @@ public abstract class WMShellModule { return Optional.of( new DesktopTasksLimiter( transitions, - desktopRepository, + desktopUserRepositories, shellTaskOrganizer, maxTaskLimit, interactionJankMonitor, @@ -809,7 +810,7 @@ public abstract class WMShellModule { Context context, ShellInit shellInit, Transitions transitions, - @DynamicOverride DesktopRepository desktopRepository, + @DynamicOverride DesktopUserRepositories desktopUserRepositories, DisplayController displayController, ShellTaskOrganizer shellTaskOrganizer, ShellCommandHandler shellCommandHandler) { @@ -818,7 +819,7 @@ public abstract class WMShellModule { new DesktopImmersiveController( shellInit, transitions, - desktopRepository, + desktopUserRepositories, displayController, shellTaskOrganizer, shellCommandHandler)); @@ -883,7 +884,7 @@ public abstract class WMShellModule { ShellCommandHandler shellCommandHandler, IWindowManager windowManager, ShellTaskOrganizer taskOrganizer, - @DynamicOverride DesktopRepository desktopRepository, + @DynamicOverride DesktopUserRepositories desktopUserRepositories, DisplayController displayController, ShellController shellController, DisplayInsetsController displayInsetsController, @@ -910,7 +911,7 @@ public abstract class WMShellModule { } return Optional.of(new DesktopModeWindowDecorViewModel(context, shellExecutor, mainHandler, mainChoreographer, bgExecutor, shellInit, shellCommandHandler, windowManager, - taskOrganizer, desktopRepository, displayController, shellController, + taskOrganizer, desktopUserRepositories, displayController, shellController, displayInsetsController, syncQueue, transitions, desktopTasksController, desktopImmersiveController.get(), rootTaskDisplayAreaOrganizer, interactionJankMonitor, genericLinksParser, @@ -928,7 +929,7 @@ public abstract class WMShellModule { @ShellAnimationThread ShellExecutor animExecutor, ShellInit shellInit, Transitions transitions, - @DynamicOverride DesktopRepository desktopRepository) { + @DynamicOverride DesktopUserRepositories desktopUserRepositories) { if (!DesktopModeStatus.canEnterDesktopMode(context) || !ENABLE_DESKTOP_WINDOWING_MODALS_POLICY.isTrue() || !Flags.enableDesktopSystemDialogsTransitions()) { @@ -937,7 +938,7 @@ public abstract class WMShellModule { return Optional.of( new SystemModalsTransitionHandler( context, mainExecutor, animExecutor, shellInit, transitions, - desktopRepository)); + desktopUserRepositories)); } @WMSingleton @@ -996,16 +997,17 @@ public abstract class WMShellModule { @WMSingleton @Provides @DynamicOverride - static DesktopRepository provideDesktopRepository( + static DesktopUserRepositories provideDesktopUserRepositories( Context context, ShellInit shellInit, DesktopPersistentRepository desktopPersistentRepository, DesktopRepositoryInitializer desktopRepositoryInitializer, - @ShellMainThread CoroutineScope mainScope + @ShellMainThread CoroutineScope mainScope, + UserManager userManager ) { - return new DesktopRepository(context, shellInit, desktopPersistentRepository, + return new DesktopUserRepositories(context, shellInit, desktopPersistentRepository, desktopRepositoryInitializer, - mainScope); + mainScope, userManager); } @WMSingleton @@ -1016,7 +1018,7 @@ public abstract class WMShellModule { ShellTaskOrganizer shellTaskOrganizer, TaskStackListenerImpl taskStackListener, ToggleResizeDesktopTaskTransitionHandler toggleResizeDesktopTaskTransitionHandler, - @DynamicOverride DesktopRepository desktopRepository) { + @DynamicOverride DesktopUserRepositories desktopUserRepositories) { if (DesktopModeStatus.canEnterDesktopMode(context)) { return Optional.of( new DesktopActivityOrientationChangeHandler( @@ -1025,7 +1027,7 @@ public abstract class WMShellModule { shellTaskOrganizer, taskStackListener, toggleResizeDesktopTaskTransitionHandler, - desktopRepository)); + desktopUserRepositories)); } return Optional.empty(); } @@ -1034,12 +1036,12 @@ public abstract class WMShellModule { @Provides static Optional<DesktopTasksTransitionObserver> provideDesktopTasksTransitionObserver( Context context, - Optional<DesktopRepository> desktopRepository, + Optional<DesktopUserRepositories> desktopUserRepositories, Transitions transitions, ShellTaskOrganizer shellTaskOrganizer, Optional<DesktopMixedTransitionHandler> desktopMixedTransitionHandler, ShellInit shellInit) { - return desktopRepository.flatMap( + return desktopUserRepositories.flatMap( repository -> Optional.of( new DesktopTasksTransitionObserver( @@ -1056,7 +1058,7 @@ public abstract class WMShellModule { static Optional<DesktopMixedTransitionHandler> provideDesktopMixedTransitionHandler( Context context, Transitions transitions, - @DynamicOverride DesktopRepository desktopRepository, + @DynamicOverride DesktopUserRepositories desktopUserRepositories, FreeformTaskTransitionHandler freeformTaskTransitionHandler, CloseDesktopTaskTransitionHandler closeDesktopTaskTransitionHandler, Optional<DesktopImmersiveController> desktopImmersiveController, @@ -1074,7 +1076,7 @@ public abstract class WMShellModule { new DesktopMixedTransitionHandler( context, transitions, - desktopRepository, + desktopUserRepositories, freeformTaskTransitionHandler, closeDesktopTaskTransitionHandler, desktopImmersiveController.get(), diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java index 3cd5df3121c1..cfdfe3d52011 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java @@ -42,7 +42,7 @@ import com.android.wm.shell.common.pip.PipUiEventLogger; import com.android.wm.shell.common.pip.SizeSpecSource; import com.android.wm.shell.dagger.WMShellBaseModule; import com.android.wm.shell.dagger.WMSingleton; -import com.android.wm.shell.desktopmode.DesktopRepository; +import com.android.wm.shell.desktopmode.DesktopUserRepositories; import com.android.wm.shell.onehanded.OneHandedController; import com.android.wm.shell.pip.PipAnimationController; import com.android.wm.shell.pip.PipParamsChangedForwarder; @@ -171,7 +171,7 @@ public abstract class Pip1Module { PipParamsChangedForwarder pipParamsChangedForwarder, Optional<SplitScreenController> splitScreenControllerOptional, Optional<PipPerfHintController> pipPerfHintControllerOptional, - Optional<DesktopRepository> desktopRepositoryOptional, + Optional<DesktopUserRepositories> desktopUserRepositoriesOptional, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, DisplayController displayController, PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer, @@ -181,7 +181,7 @@ public abstract class Pip1Module { pipBoundsAlgorithm, menuPhoneController, pipAnimationController, pipSurfaceTransactionHelper, pipTransitionController, pipParamsChangedForwarder, splitScreenControllerOptional, pipPerfHintControllerOptional, - desktopRepositoryOptional, rootTaskDisplayAreaOrganizer, displayController, + desktopUserRepositoriesOptional, rootTaskDisplayAreaOrganizer, displayController, pipUiEventLogger, shellTaskOrganizer, mainExecutor); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java index 7507e0458c48..3a9961917f79 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java @@ -39,7 +39,7 @@ import com.android.wm.shell.common.pip.PipUtils; import com.android.wm.shell.common.pip.SizeSpecSource; import com.android.wm.shell.dagger.WMShellBaseModule; import com.android.wm.shell.dagger.WMSingleton; -import com.android.wm.shell.desktopmode.DesktopRepository; +import com.android.wm.shell.desktopmode.DesktopUserRepositories; import com.android.wm.shell.pip2.phone.PhonePipMenuController; import com.android.wm.shell.pip2.phone.PipController; import com.android.wm.shell.pip2.phone.PipMotionHelper; @@ -131,10 +131,10 @@ public abstract class Pip2Module { PipBoundsState pipBoundsState, @ShellMainThread ShellExecutor mainExecutor, PipTransitionState pipTransitionState, - Optional<DesktopRepository> desktopRepositoryOptional, + Optional<DesktopUserRepositories> desktopUserRepositoriesOptional, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) { return new PipScheduler(context, pipBoundsState, mainExecutor, pipTransitionState, - desktopRepositoryOptional, rootTaskDisplayAreaOrganizer); + desktopUserRepositoriesOptional, rootTaskDisplayAreaOrganizer); } @WMSingleton diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandler.kt index 606aa6cd3353..c0bf40b9c461 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandler.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandler.kt @@ -39,7 +39,7 @@ class DesktopActivityOrientationChangeHandler( private val shellTaskOrganizer: ShellTaskOrganizer, private val taskStackListener: TaskStackListenerImpl, private val resizeHandler: ToggleResizeDesktopTaskTransitionHandler, - private val taskRepository: DesktopRepository, + private val desktopUserRepositories: DesktopUserRepositories, ) { init { @@ -81,7 +81,9 @@ class DesktopActivityOrientationChangeHandler( ) { if (!Flags.respectOrientationChangeForUnresizeable()) return val task = shellTaskOrganizer.getRunningTaskInfo(taskId) ?: return - if (!isDesktopModeShowing(task.displayId) || !task.isFreeform || task.isResizeable) return + val taskRepository = desktopUserRepositories.current + val isDesktopModeShowing = taskRepository.getVisibleTaskCount(task.displayId) > 0 + if (!isDesktopModeShowing || !task.isFreeform || task.isResizeable) return val taskBounds = task.configuration.windowConfiguration.bounds val taskHeight = taskBounds.height() @@ -106,7 +108,4 @@ class DesktopActivityOrientationChangeHandler( resizeHandler.startTransition(wct) } } - - private fun isDesktopModeShowing(displayId: Int): Boolean = - taskRepository.getVisibleTaskCount(displayId) > 0 }
\ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopImmersiveController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopImmersiveController.kt index dd95273dd4f3..79be698773da 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopImmersiveController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopImmersiveController.kt @@ -50,7 +50,7 @@ import java.io.PrintWriter class DesktopImmersiveController( shellInit: ShellInit, private val transitions: Transitions, - private val desktopRepository: DesktopRepository, + private val desktopUserRepositories: DesktopUserRepositories, private val displayController: DisplayController, private val shellTaskOrganizer: ShellTaskOrganizer, private val shellCommandHandler: ShellCommandHandler, @@ -60,14 +60,14 @@ class DesktopImmersiveController( constructor( shellInit: ShellInit, transitions: Transitions, - desktopRepository: DesktopRepository, + desktopUserRepositories: DesktopUserRepositories, displayController: DisplayController, shellTaskOrganizer: ShellTaskOrganizer, shellCommandHandler: ShellCommandHandler, ) : this( shellInit, transitions, - desktopRepository, + desktopUserRepositories, displayController, shellTaskOrganizer, shellCommandHandler, @@ -177,8 +177,9 @@ class DesktopImmersiveController( reason: ExitReason, ): ExitResult { if (!Flags.enableFullyImmersiveInDesktop()) return ExitResult.NoExit - val immersiveTask = desktopRepository.getTaskInFullImmersiveState(displayId) - ?: return ExitResult.NoExit + val immersiveTask = + desktopUserRepositories.current.getTaskInFullImmersiveState(displayId) + ?: return ExitResult.NoExit if (immersiveTask == excludeTaskId) { return ExitResult.NoExit } @@ -210,7 +211,7 @@ class DesktopImmersiveController( reason: ExitReason, ): ExitResult { if (!Flags.enableFullyImmersiveInDesktop()) return ExitResult.NoExit - if (desktopRepository.isTaskInFullImmersiveState(taskInfo.taskId)) { + if (desktopUserRepositories.current.isTaskInFullImmersiveState(taskInfo.taskId)) { // A full immersive task is being minimized, make sure the immersive state is broken // (i.e. resize back to max bounds). wct.setBounds(taskInfo.token, getExitDestinationBounds(taskInfo)) @@ -377,6 +378,7 @@ class DesktopImmersiveController( startTransaction: SurfaceControl.Transaction, finishTransaction: SurfaceControl.Transaction, ) { + val desktopRepository: DesktopRepository = desktopUserRepositories.current // Check if this is a pending external exit transition. val pendingExit = pendingExternalExitTransitions .firstOrNull { pendingExit -> pendingExit.transition == transition } @@ -412,6 +414,7 @@ class DesktopImmersiveController( } val startBounds = immersiveChange.startAbsBounds logV("Direct move for task#%d in %s direction verified", state.taskId, state.direction) + when (state.direction) { Direction.ENTER -> { desktopRepository.setTaskInFullImmersiveState( @@ -484,7 +487,8 @@ class DesktopImmersiveController( val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: error("Expected non-null display layout for displayId: ${taskInfo.displayId}") return if (Flags.enableRestoreToPreviousSizeFromDesktopImmersive()) { - desktopRepository.removeBoundsBeforeFullImmersive(taskInfo.taskId) + desktopUserRepositories.current + .removeBoundsBeforeFullImmersive(taskInfo.taskId) ?: if (ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS.isTrue()) { calculateInitialBounds(displayLayout, taskInfo) } else { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt index 82c2ebc7ec77..96bbd58949bd 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt @@ -49,7 +49,7 @@ import com.android.wm.shell.transition.Transitions.TransitionFinishCallback class DesktopMixedTransitionHandler( private val context: Context, private val transitions: Transitions, - private val desktopRepository: DesktopRepository, + private val desktopUserRepositories: DesktopUserRepositories, private val freeformTaskTransitionHandler: FreeformTaskTransitionHandler, private val closeDesktopTaskTransitionHandler: CloseDesktopTaskTransitionHandler, private val desktopImmersiveController: DesktopImmersiveController, @@ -405,7 +405,7 @@ class DesktopMixedTransitionHandler( private fun isLastDesktopTask(change: TransitionInfo.Change): Boolean = change.taskInfo?.let { - desktopRepository.getExpandedTaskCount(it.displayId) == 1 + desktopUserRepositories.getProfile(it.userId).getExpandedTaskCount(it.displayId) == 1 } ?: false private fun findCloseDesktopTaskChange(info: TransitionInfo): TransitionInfo.Change? { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt index 7fcb7678f6af..ca3dc2d5426e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt @@ -16,7 +16,7 @@ package com.android.wm.shell.desktopmode -import android.content.Context +import android.content.pm.UserInfo import android.graphics.Rect import android.graphics.Region import android.util.ArrayMap @@ -30,11 +30,8 @@ import androidx.core.util.keyIterator import androidx.core.util.valueIterator import com.android.internal.protolog.ProtoLog import com.android.wm.shell.desktopmode.persistence.DesktopPersistentRepository -import com.android.wm.shell.desktopmode.persistence.DesktopRepositoryInitializer import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE import com.android.wm.shell.shared.annotations.ShellMainThread -import com.android.wm.shell.shared.desktopmode.DesktopModeStatus -import com.android.wm.shell.sysui.ShellInit import java.io.PrintWriter import java.util.concurrent.Executor import java.util.function.Consumer @@ -43,13 +40,10 @@ import kotlinx.coroutines.launch /** Tracks desktop data for Android Desktop Windowing. */ class DesktopRepository ( - private val context: Context, - shellInit: ShellInit, private val persistentRepository: DesktopPersistentRepository, - private val repositoryInitializer: DesktopRepositoryInitializer, @ShellMainThread private val mainCoroutineScope: CoroutineScope, + val userId: Int, ){ - /** * Task data tracked per desktop. * @@ -117,16 +111,6 @@ class DesktopRepository ( this[displayId] ?: DesktopTaskData().also { this[displayId] = it } } - init { - if (DesktopModeStatus.canEnterDesktopMode(context)) { - shellInit.addInitCallback(::initRepoFromPersistentStorage, this) - } - } - - private fun initRepoFromPersistentStorage() { - repositoryInitializer.initialize(this) - } - /** Adds [activeTasksListener] to be notified of updates to active tasks. */ fun addActiveTaskListener(activeTasksListener: ActiveTasksListener) { activeTasksListeners.add(activeTasksListener) @@ -276,6 +260,8 @@ class DesktopRepository ( * the set of visible tasks on that display and notifies listeners. */ fun updateTask(displayId: Int, taskId: Int, isVisible: Boolean) { + logD("updateTask taskId=%d, displayId=%d, isVisible=%b", taskId, displayId, isVisible) + if (isVisible) { // If task is visible, remove it from any other display besides [displayId]. removeVisibleTask(taskId, excludedDisplayId = displayId) @@ -495,6 +481,7 @@ class DesktopRepository ( persistentRepository.addOrUpdateDesktop( // Use display id as desktop id for now since only once desktop per display // is supported. + userId = userId, desktopId = displayId, visibleTasks = desktopTaskDataByDisplayIdCopy.visibleTasks, minimizedTasks = desktopTaskDataByDisplayIdCopy.minimizedTasks, @@ -529,6 +516,7 @@ class DesktopRepository ( ) pw.println("${innerPrefix}minimizedTasks=${data.minimizedTasks.toDumpString()}") pw.println("${innerPrefix}fullImmersiveTaskId=${data.fullImmersiveTaskId}") + pw.println("${innerPrefix}wallpaperActivityToken=${wallpaperActivityToken}") } } 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 94ac2e665f61..80d8bfba99d2 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 @@ -23,10 +23,12 @@ import com.android.wm.shell.freeform.TaskChangeListener /** Manages tasks handling specific to Android Desktop Mode. */ class DesktopTaskChangeListener( - private val desktopRepository: DesktopRepository, + private val desktopUserRepositories: DesktopUserRepositories, ) : TaskChangeListener { override fun onTaskOpening(taskInfo: RunningTaskInfo) { + val desktopRepository: DesktopRepository = + desktopUserRepositories.getProfile(taskInfo.userId) if (!isFreeformTask(taskInfo) && desktopRepository.isActiveTask(taskInfo.taskId)) { desktopRepository.removeFreeformTask(taskInfo.displayId, taskInfo.taskId) return @@ -37,6 +39,8 @@ class DesktopTaskChangeListener( } override fun onTaskChanging(taskInfo: RunningTaskInfo) { + val desktopRepository: DesktopRepository = + desktopUserRepositories.getProfile(taskInfo.userId) if (!desktopRepository.isActiveTask(taskInfo.taskId)) return // Case 1: Freeform task is changed in Desktop Mode. @@ -61,6 +65,8 @@ class DesktopTaskChangeListener( } override fun onTaskMovingToFront(taskInfo: RunningTaskInfo) { + val desktopRepository: DesktopRepository = + desktopUserRepositories.getProfile(taskInfo.userId) if (!desktopRepository.isActiveTask(taskInfo.taskId)) return if (!isFreeformTask(taskInfo)) { desktopRepository.removeFreeformTask(taskInfo.displayId, taskInfo.taskId) @@ -74,6 +80,8 @@ class DesktopTaskChangeListener( } override fun onTaskClosing(taskInfo: RunningTaskInfo) { + val desktopRepository: DesktopRepository = + desktopUserRepositories.getProfile(taskInfo.userId) if (!desktopRepository.isActiveTask(taskInfo.taskId)) return // TODO: b/370038902 - Handle Activity#finishAndRemoveTask. if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue() || diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt index 5759a66c6566..5cb94f870a2d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt @@ -159,7 +159,7 @@ class DesktopTasksController( private val toggleResizeDesktopTaskTransitionHandler: ToggleResizeDesktopTaskTransitionHandler, private val dragToDesktopTransitionHandler: DragToDesktopTransitionHandler, private val desktopImmersiveController: DesktopImmersiveController, - private val taskRepository: DesktopRepository, + private val userRepositories: DesktopUserRepositories, private val recentsTransitionHandler: RecentsTransitionHandler, private val multiInstanceHelper: MultiInstanceHelper, @ShellMainThread private val mainExecutor: ShellExecutor, @@ -177,6 +177,7 @@ class DesktopTasksController( UserChangeListener { private val desktopMode: DesktopModeImpl + private var taskRepository: DesktopRepository private var visualIndicator: DesktopModeVisualIndicator? = null private var userId: Int private val desktopModeShellCommandHandler: DesktopModeShellCommandHandler = @@ -229,6 +230,7 @@ class DesktopTasksController( shellInit.addInitCallback({ onInit() }, this) } userId = ActivityManager.getCurrentUser() + taskRepository = userRepositories.getProfile(userId) } private fun onInit() { @@ -1239,7 +1241,7 @@ class DesktopTasksController( /* requestCode= */ 0, intent, PendingIntent.FLAG_IMMUTABLE, - /* bundle= */ null, + /* options= */ null, userHandle ) wct.sendPendingIntent(pendingIntent, intent, options.toBundle()) @@ -1724,8 +1726,7 @@ class DesktopTasksController( /** Handle task closing by removing wallpaper activity if it's the last active task */ private fun handleTaskClosing(task: RunningTaskInfo, transition: IBinder, requestType: Int): WindowContainerTransaction? { logV("handleTaskClosing") - if (!isDesktopModeShowing(task.displayId)) - return null + if (!isDesktopModeShowing(task.displayId)) return null val wct = WindowContainerTransaction() performDesktopExitCleanupIfNeeded(task.taskId, wct) @@ -1742,6 +1743,7 @@ class DesktopTasksController( ) ) } + taskbarDesktopTaskListener?.onTaskbarCornerRoundingUpdate( doesAnyTaskRequireTaskbarRounding( task.displayId, @@ -2327,7 +2329,9 @@ class DesktopTasksController( // TODO(b/366397912): Support full multi-user mode in Windowing. override fun onUserChanged(newUserId: Int, userContext: Context) { + logV("onUserChanged previousUserId=%d, newUserId=%d", userId, newUserId) userId = newUserId + taskRepository = userRepositories.getProfile(userId) desktopTilingDecorViewModel.onUserChange() } @@ -2350,6 +2354,7 @@ class DesktopTasksController( val innerPrefix = "$prefix " pw.println("${prefix}DesktopTasksController") DesktopModeStatus.dump(pw, innerPrefix, context) + pw.println("${prefix}userId=$userId") taskRepository.dump(pw, innerPrefix) } @@ -2378,6 +2383,7 @@ class DesktopTasksController( displayId: Int, transitionSource: DesktopModeTransitionSource ) { + logV("moveFocusedTaskToDesktop") mainExecutor.execute { this@DesktopTasksController.moveFocusedTaskToDesktop(displayId, transitionSource) } @@ -2387,12 +2393,14 @@ class DesktopTasksController( displayId: Int, transitionSource: DesktopModeTransitionSource ) { + logV("moveFocusedTaskToFullscreen") mainExecutor.execute { this@DesktopTasksController.enterFullscreen(displayId, transitionSource) } } override fun moveFocusedTaskToStageSplit(displayId: Int, leftOrTop: Boolean) { + logV("moveFocusedTaskToStageSplit") mainExecutor.execute { this@DesktopTasksController.enterSplit(displayId, leftOrTop) } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt index 77af627a948a..62b200a6174e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt @@ -16,6 +16,7 @@ package com.android.wm.shell.desktopmode +import android.app.ActivityManager import android.content.Context import android.os.Handler import android.os.IBinder @@ -31,6 +32,7 @@ import com.android.internal.protolog.ProtoLog import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE import com.android.wm.shell.shared.annotations.ShellMainThread +import com.android.wm.shell.sysui.UserChangeListener; import com.android.wm.shell.transition.Transitions import com.android.wm.shell.transition.Transitions.TransitionObserver @@ -43,7 +45,7 @@ import com.android.wm.shell.transition.Transitions.TransitionObserver */ class DesktopTasksLimiter ( transitions: Transitions, - private val taskRepository: DesktopRepository, + private val desktopUserRepositories: DesktopUserRepositories, private val shellTaskOrganizer: ShellTaskOrganizer, private val maxTasksLimit: Int, private val interactionJankMonitor: InteractionJankMonitor, @@ -54,12 +56,15 @@ class DesktopTasksLimiter ( @VisibleForTesting val leftoverMinimizedTasksRemover = LeftoverMinimizedTasksRemover() + private var userId: Int + init { require(maxTasksLimit > 0) { "DesktopTasksLimiter: maxTasksLimit should be greater than 0. Current value: $maxTasksLimit." } transitions.registerObserver(minimizeTransitionObserver) - taskRepository.addActiveTaskListener(leftoverMinimizedTasksRemover) + userId = ActivityManager.getCurrentUser() + desktopUserRepositories.current.addActiveTaskListener(leftoverMinimizedTasksRemover) logV("Starting limiter with a maximum of %d tasks", maxTasksLimit) } @@ -84,6 +89,7 @@ class DesktopTasksLimiter ( startTransaction: SurfaceControl.Transaction, finishTransaction: SurfaceControl.Transaction ) { + val taskRepository = desktopUserRepositories.current val taskToMinimize = pendingTransitionTokensAndTasks.remove(transition) ?: return if (!taskRepository.isActiveTask(taskToMinimize.taskId)) return if (!isTaskReadyForMinimize(info, taskToMinimize)) { @@ -114,6 +120,7 @@ class DesktopTasksLimiter ( ): Boolean { val taskChange = info.changes.find { change -> change.taskInfo?.taskId == taskDetails.taskId } + val taskRepository = desktopUserRepositories.current if (taskChange == null) return !taskRepository.isVisibleTask(taskDetails.taskId) return taskChange.mode == TRANSIT_TO_BACK } @@ -151,7 +158,8 @@ class DesktopTasksLimiter ( } @VisibleForTesting - inner class LeftoverMinimizedTasksRemover : DesktopRepository.ActiveTasksListener { + inner class LeftoverMinimizedTasksRemover + : DesktopRepository.ActiveTasksListener, UserChangeListener { override fun onActiveTasksChanged(displayId: Int) { // If back navigation is enabled, we shouldn't remove the leftover tasks if (DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue()) return @@ -161,6 +169,7 @@ class DesktopTasksLimiter ( } fun removeLeftoverMinimizedTasks(displayId: Int, wct: WindowContainerTransaction) { + val taskRepository = desktopUserRepositories.current if (taskRepository.getExpandedTasksOrdered(displayId).isNotEmpty()) return val remainingMinimizedTasks = taskRepository.getMinimizedTasks(displayId) if (remainingMinimizedTasks.isEmpty()) return @@ -173,6 +182,15 @@ class DesktopTasksLimiter ( } } } + + override fun onUserChanged(newUserId: Int, userContext: Context) { + // Removes active task listener for the previous repository + desktopUserRepositories.getProfile(userId).removeActiveTasksListener(this); + + // Sets active listener for the current repository. + userId = newUserId + desktopUserRepositories.getProfile(newUserId).addActiveTaskListener(this); + } } /** @@ -183,6 +201,7 @@ class DesktopTasksLimiter ( */ private fun minimizeTask(displayId: Int, taskId: Int) { logV("Minimize taskId=%d, displayId=%d", taskId, displayId) + val taskRepository = desktopUserRepositories.current taskRepository.minimizeTask(displayId, taskId) } @@ -196,7 +215,7 @@ class DesktopTasksLimiter ( newFrontTaskId: Int, ): Int? { logV("addAndGetMinimizeTaskChanges, newFrontTask=%d", newFrontTaskId) - + val taskRepository = desktopUserRepositories.current val taskIdToMinimize = getTaskIdToMinimize( taskRepository.getExpandedTasksOrdered(displayId), diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt index c39c715e685c..d6bb7f95c196 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt @@ -16,6 +16,7 @@ package com.android.wm.shell.desktopmode +import android.app.ActivityManager import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM import android.content.Context import android.os.IBinder @@ -43,7 +44,7 @@ import com.android.wm.shell.transition.Transitions */ class DesktopTasksTransitionObserver( private val context: Context, - private val desktopRepository: DesktopRepository, + private val desktopUserRepositories: DesktopUserRepositories, private val transitions: Transitions, private val shellTaskOrganizer: ShellTaskOrganizer, private val desktopMixedTransitionHandler: DesktopMixedTransitionHandler, @@ -51,11 +52,13 @@ class DesktopTasksTransitionObserver( ) : Transitions.TransitionObserver { private var transitionToCloseWallpaper: IBinder? = null + private var currentProfileId: Int init { if (DesktopModeStatus.canEnterDesktopMode(context)) { shellInit.addInitCallback(::onInit, this) } + currentProfileId = ActivityManager.getCurrentUser() } fun onInit() { @@ -89,6 +92,7 @@ class DesktopTasksTransitionObserver( val taskInfo = change.taskInfo if (taskInfo == null || taskInfo.taskId == -1) continue + val desktopRepository = desktopUserRepositories.getProfile(taskInfo.userId) if (desktopRepository.isActiveTask(taskInfo.taskId) && taskInfo.windowingMode != WINDOWING_MODE_FREEFORM) { desktopRepository.removeFreeformTask(taskInfo.displayId, taskInfo.taskId) @@ -105,7 +109,7 @@ class DesktopTasksTransitionObserver( if (taskInfo == null || taskInfo.taskId == -1) { continue } - + val desktopRepository = desktopUserRepositories.getProfile(taskInfo.userId) val visibleTaskCount = desktopRepository.getVisibleTaskCount(taskInfo.displayId) if (visibleTaskCount > 0 && change.mode == TRANSIT_TO_BACK && @@ -128,12 +132,13 @@ class DesktopTasksTransitionObserver( if (taskInfo == null || taskInfo.taskId == -1) { continue } - + val desktopRepository = desktopUserRepositories.getProfile(taskInfo.userId) if (desktopRepository.getVisibleTaskCount(taskInfo.displayId) == 1 && change.mode == TRANSIT_CLOSE && taskInfo.windowingMode == WINDOWING_MODE_FREEFORM && desktopRepository.wallpaperActivityToken != null) { transitionToCloseWallpaper = transition + currentProfileId = taskInfo.userId } } } @@ -150,6 +155,7 @@ class DesktopTasksTransitionObserver( // TODO: b/332682201 Update repository state if (transitionToCloseWallpaper == transition) { // TODO: b/362469671 - Handle merging the animation when desktop is also closing. + val desktopRepository = desktopUserRepositories.getProfile(currentProfileId) desktopRepository.wallpaperActivityToken?.let { wallpaperActivityToken -> transitions.startTransition( TRANSIT_CLOSE, @@ -167,6 +173,7 @@ class DesktopTasksTransitionObserver( info.changes.forEach { change -> change.taskInfo?.let { taskInfo -> if (DesktopWallpaperActivity.isWallpaperTask(taskInfo)) { + val desktopRepository = desktopUserRepositories.getProfile(taskInfo.userId) when (change.mode) { WindowManager.TRANSIT_OPEN -> { desktopRepository.wallpaperActivityToken = taskInfo.token diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopUserRepositories.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopUserRepositories.kt new file mode 100644 index 000000000000..1e5a1b274729 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopUserRepositories.kt @@ -0,0 +1,109 @@ +/* + * 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.app.ActivityManager +import android.content.Context +import android.content.pm.UserInfo +import android.os.UserManager +import android.util.SparseArray +import com.android.window.flags.Flags +import com.android.internal.protolog.ProtoLog +import com.android.wm.shell.desktopmode.persistence.DesktopPersistentRepository +import com.android.wm.shell.desktopmode.persistence.DesktopRepositoryInitializer +import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE +import com.android.wm.shell.shared.annotations.ShellMainThread +import com.android.wm.shell.shared.desktopmode.DesktopModeStatus +import com.android.wm.shell.sysui.ShellInit +import com.android.wm.shell.sysui.UserChangeListener +import kotlinx.coroutines.CoroutineScope + +/** Manages per-user DesktopRepository instances. */ +class DesktopUserRepositories( + context: Context, + shellInit: ShellInit, + private val persistentRepository: DesktopPersistentRepository, + private val repositoryInitializer: DesktopRepositoryInitializer, + @ShellMainThread private val mainCoroutineScope: CoroutineScope, + userManager: UserManager, +) : UserChangeListener { + private var userId: Int + private var userIdToProfileIdsMap: MutableMap<Int, List<Int>> = mutableMapOf() + + // TODO(b/357060209): Add caching for this logic to improve efficiency. + val current: DesktopRepository + get() = desktopRepoByUserId.getOrCreate(userId) + + private val desktopRepoByUserId = + object : SparseArray<DesktopRepository>() { + /** Gets [DesktopRepository] for existing [userId] or creates a new one. */ + fun getOrCreate(userId: Int): DesktopRepository = + this[userId] + ?: DesktopRepository( + persistentRepository, + mainCoroutineScope, + userId) + .also { this[userId] = it } + } + + init { + userId = ActivityManager.getCurrentUser() + if (DesktopModeStatus.canEnterDesktopMode(context)) { + shellInit.addInitCallback(::initRepoFromPersistentStorage, this) + } + if (Flags.enableDesktopWindowingHsum()) { + userIdToProfileIdsMap[userId] = userManager.getProfiles(userId).map { it.id } + } + } + + private fun initRepoFromPersistentStorage() { + repositoryInitializer.initialize(this) + } + + /** Returns [DesktopRepository] for the parent user id. */ + fun getProfile(profileId: Int): DesktopRepository { + if (Flags.enableDesktopWindowingHsum()) { + for ((uid, profileIds) in userIdToProfileIdsMap) { + if (profileId in profileIds) { + return desktopRepoByUserId.getOrCreate(uid) + } + } + } + return desktopRepoByUserId.getOrCreate(profileId) + } + + override fun onUserChanged(newUserId: Int, userContext: Context) { + logD("onUserChanged previousUserId=%d, newUserId=%d", userId, newUserId) + userId = newUserId + } + + override fun onUserProfilesChanged(profiles: MutableList<UserInfo>) { + logD("onUserProfilesChanged profiles=%s", profiles.toString()) + if (Flags.enableDesktopWindowingHsum()) { + // TODO(b/366397912): Remove all persisted profile data when the profile changes. + userIdToProfileIdsMap[userId] = profiles.map { it.id } + } + } + + private fun logD(msg: String, vararg arguments: Any?) { + ProtoLog.d(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments) + } + + companion object { + private const val TAG = "DesktopUserRepositories" + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandler.kt index 826de08557bd..a428ce18a49e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandler.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandler.kt @@ -29,7 +29,7 @@ import com.android.app.animation.Interpolators import com.android.internal.protolog.ProtoLog import com.android.wm.shell.common.ShellExecutor import com.android.wm.shell.compatui.isTopActivityExemptFromDesktopWindowing -import com.android.wm.shell.desktopmode.DesktopRepository +import com.android.wm.shell.desktopmode.DesktopUserRepositories import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE import com.android.wm.shell.shared.TransitionUtil.isClosingMode import com.android.wm.shell.shared.TransitionUtil.isClosingType @@ -46,7 +46,7 @@ class SystemModalsTransitionHandler( private val animExecutor: ShellExecutor, private val shellInit: ShellInit, private val transitions: Transitions, - private val desktopRepository: DesktopRepository, + private val desktopUserRepositories: DesktopUserRepositories, ) : TransitionHandler { private val showingSystemModalsIds = mutableSetOf<Int>() @@ -156,7 +156,7 @@ class SystemModalsTransitionHandler( } private fun isDesktopModeShowing(displayId: Int): Boolean = - desktopRepository.getVisibleTaskCount(displayId) > 0 + desktopUserRepositories.current.getVisibleTaskCount(displayId) > 0 override fun handleRequest( transition: IBinder, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopPersistentRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopPersistentRepository.kt index 9e646f430c98..b7de1f86601c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopPersistentRepository.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopPersistentRepository.kt @@ -73,8 +73,8 @@ class DesktopPersistentRepository( * Reads and returns the [DesktopRepositoryState] proto object from the DataStore for a user. If * the DataStore is empty or there's an error reading, it returns the default value of Proto. */ - private suspend fun getDesktopRepositoryState( - userId: Int = DEFAULT_USER_ID + suspend fun getDesktopRepositoryState( + userId: Int ): DesktopRepositoryState? = try { dataStoreFlow @@ -85,12 +85,20 @@ class DesktopPersistentRepository( null } + suspend fun getUserDesktopRepositoryMap(): Map<Int, DesktopRepositoryState>? = + try { + dataStoreFlow.first().desktopRepoByUserMap + } catch (e: Exception) { + Log.e(TAG, "Unable to read from datastore", e) + null + } + /** * Reads the [Desktop] of a desktop filtering by the [userId] and [desktopId]. Executes the * [callback] using the [mainCoroutineScope]. */ suspend fun readDesktop( - userId: Int = DEFAULT_USER_ID, + userId: Int, desktopId: Int = DEFAULT_DESKTOP_ID, ): Desktop? = try { @@ -103,7 +111,7 @@ class DesktopPersistentRepository( /** Adds or updates a desktop stored in the datastore */ suspend fun addOrUpdateDesktop( - userId: Int = DEFAULT_USER_ID, + userId: Int, desktopId: Int = 0, visibleTasks: ArraySet<Int> = ArraySet(), minimizedTasks: ArraySet<Int> = ArraySet(), @@ -111,9 +119,9 @@ class DesktopPersistentRepository( ) { // TODO: b/367609270 - Improve the API to support multi-user try { - dataStore.updateData { desktopPersistentRepositories: DesktopPersistentRepositories -> + dataStore.updateData { persistentRepositories: DesktopPersistentRepositories -> val currentRepository = - desktopPersistentRepositories.getDesktopRepoByUserOrDefault( + persistentRepositories.getDesktopRepoByUserOrDefault( userId, DesktopRepositoryState.getDefaultInstance()) val desktop = getDesktop(currentRepository, desktopId) @@ -125,7 +133,7 @@ class DesktopPersistentRepository( ) .updateZOrder(freeformTasksInZOrder) - desktopPersistentRepositories + persistentRepositories .toBuilder() .putDesktopRepoByUser( userId, @@ -135,7 +143,7 @@ class DesktopPersistentRepository( .build()) .build() } - } catch (exception: IOException) { + } catch (exception: Exception) { Log.e( TAG, "Error in updating desktop mode related data, data is " + @@ -154,7 +162,6 @@ class DesktopPersistentRepository( private const val TAG = "DesktopPersistenceRepo" private const val DESKTOP_REPOSITORIES_DATASTORE_FILE = "desktop_persistent_repositories.pb" - private const val DEFAULT_USER_ID = 1000 private const val DEFAULT_DESKTOP_ID = 0 object DesktopPersistentRepositoriesSerializer : Serializer<DesktopPersistentRepositories> { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializer.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializer.kt index 771c3d1cb9a1..a26ebbf4c99a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializer.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializer.kt @@ -16,9 +16,9 @@ package com.android.wm.shell.desktopmode.persistence -import com.android.wm.shell.desktopmode.DesktopRepository +import com.android.wm.shell.desktopmode.DesktopUserRepositories -/** Interface for initializing the [DesktopRepository]. */ +/** Interface for initializing the [DesktopUserRepositories]. */ fun interface DesktopRepositoryInitializer { - fun initialize(repository: DesktopRepository) + fun initialize(userRepositories: DesktopUserRepositories) } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerImpl.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerImpl.kt index d8156561ff19..9539cbe0e677 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerImpl.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerImpl.kt @@ -19,6 +19,7 @@ package com.android.wm.shell.desktopmode.persistence import android.content.Context import android.window.DesktopModeFlags import com.android.wm.shell.desktopmode.DesktopRepository +import com.android.wm.shell.desktopmode.DesktopUserRepositories import com.android.wm.shell.shared.annotations.ShellMainThread import com.android.wm.shell.shared.desktopmode.DesktopModeStatus import kotlinx.coroutines.CoroutineScope @@ -35,32 +36,52 @@ class DesktopRepositoryInitializerImpl( private val persistentRepository: DesktopPersistentRepository, @ShellMainThread private val mainCoroutineScope: CoroutineScope, ) : DesktopRepositoryInitializer { - override fun initialize(repository: DesktopRepository) { + override fun initialize(userRepositories: DesktopUserRepositories) { if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PERSISTENCE.isTrue()) return // TODO: b/365962554 - Handle the case that user moves to desktop before it's initialized mainCoroutineScope.launch { - val desktop = persistentRepository.readDesktop() ?: return@launch - - val maxTasks = - DesktopModeStatus.getMaxTaskLimit(context).takeIf { it > 0 } - ?: desktop.zOrderedTasksCount - - var visibleTasksCount = 0 - desktop.zOrderedTasksList - // Reverse it so we initialize the repo from bottom to top. - .reversed() - .mapNotNull { taskId -> desktop.tasksByTaskIdMap[taskId] } - .forEach { task -> - if (task.desktopTaskState == DesktopTaskState.VISIBLE - && visibleTasksCount < maxTasks - ) { - visibleTasksCount++ - repository.addTask(desktop.displayId, task.taskId, isVisible = false) - } else { - repository.addTask(desktop.displayId, task.taskId, isVisible = false) - repository.minimizeTask(desktop.displayId, task.taskId) + val desktopUserPersistentRepositoryMap = + persistentRepository.getUserDesktopRepositoryMap() ?: return@launch + for (userId in desktopUserPersistentRepositoryMap.keys) { + val repository = userRepositories.getProfile(userId) + val desktopRepositoryState = + persistentRepository.getDesktopRepositoryState(userId) ?: continue + val desktopByDesktopIdMap = desktopRepositoryState.desktopMap + for (desktopId in desktopByDesktopIdMap.keys) { + val persistentDesktop = + persistentRepository.readDesktop(userId, desktopId) ?: continue + val maxTasks = + DesktopModeStatus.getMaxTaskLimit(context).takeIf { it > 0 } + ?: persistentDesktop.zOrderedTasksCount + var visibleTasksCount = 0 + persistentDesktop.zOrderedTasksList + // Reverse it so we initialize the repo from bottom to top. + .reversed() + .mapNotNull { taskId -> persistentDesktop.tasksByTaskIdMap[taskId] } + .forEach { task -> + if (task.desktopTaskState == DesktopTaskState.VISIBLE + && visibleTasksCount < maxTasks) { + visibleTasksCount++ + repository.addTask( + persistentDesktop.displayId, + task.taskId, + isVisible = false + ) + } else { + repository.addTask( + persistentDesktop.displayId, + task.taskId, + isVisible = false + ) + repository.minimizeTask( + persistentDesktop.displayId, + task.taskId + ) + } + } } } } + } } 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 cd20d97c7964..a17d55fdc2fe 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 @@ -30,6 +30,7 @@ import com.android.internal.protolog.ProtoLog; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.LaunchAdjacentController; import com.android.wm.shell.desktopmode.DesktopRepository; +import com.android.wm.shell.desktopmode.DesktopUserRepositories; import com.android.wm.shell.desktopmode.DesktopTasksController; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; @@ -49,7 +50,7 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener, private final Context mContext; private final ShellTaskOrganizer mShellTaskOrganizer; - private final Optional<DesktopRepository> mDesktopRepository; + private final Optional<DesktopUserRepositories> mDesktopUserRepositories; private final Optional<DesktopTasksController> mDesktopTasksController; private final WindowDecorViewModel mWindowDecorationViewModel; private final LaunchAdjacentController mLaunchAdjacentController; @@ -61,7 +62,7 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener, Context context, ShellInit shellInit, ShellTaskOrganizer shellTaskOrganizer, - Optional<DesktopRepository> desktopRepository, + Optional<DesktopUserRepositories> desktopUserRepositories, Optional<DesktopTasksController> desktopTasksController, LaunchAdjacentController launchAdjacentController, WindowDecorViewModel windowDecorationViewModel, @@ -69,7 +70,7 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener, mContext = context; mShellTaskOrganizer = shellTaskOrganizer; mWindowDecorationViewModel = windowDecorationViewModel; - mDesktopRepository = desktopRepository; + mDesktopUserRepositories = desktopUserRepositories; mDesktopTasksController = desktopTasksController; mLaunchAdjacentController = launchAdjacentController; mTaskChangeListener = taskChangeListener; @@ -99,8 +100,9 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener, if (!DesktopModeFlags.ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS.isTrue() && DesktopModeStatus.canEnterDesktopMode(mContext)) { - mDesktopRepository.ifPresent(repository -> { - repository.addTask(taskInfo.displayId, taskInfo.taskId, taskInfo.isVisible); + mDesktopUserRepositories.ifPresent(userRepositories -> { + DesktopRepository currentRepo = userRepositories.getProfile(taskInfo.userId); + currentRepo.addTask(taskInfo.displayId, taskInfo.taskId, taskInfo.isVisible); }); } updateLaunchAdjacentController(); @@ -113,21 +115,22 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener, mTasks.remove(taskInfo.taskId); 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() - || repository.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. - repository.removeClosingTask(taskInfo.taskId); - repository.removeFreeformTask(taskInfo.displayId, taskInfo.taskId); - } else { - repository.updateTask(taskInfo.displayId, taskInfo.taskId, /* isVisible= */ - false); - repository.minimizeTask(taskInfo.displayId, taskInfo.taskId); - } - }); + DesktopModeStatus.canEnterDesktopMode(mContext) + && mDesktopUserRepositories.isPresent()) { + DesktopRepository repository = + mDesktopUserRepositories.get().getProfile(taskInfo.userId); + // TODO: b/370038902 - Handle Activity#finishAndRemoveTask. + if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue() + || repository.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. + repository.removeClosingTask(taskInfo.taskId); + repository.removeFreeformTask(taskInfo.displayId, taskInfo.taskId); + } else { + repository.updateTask(taskInfo.displayId, taskInfo.taskId, /* isVisible= */ + false); + repository.minimizeTask(taskInfo.displayId, taskInfo.taskId); + } } mWindowDecorationViewModel.onTaskVanished(taskInfo); updateLaunchAdjacentController(); @@ -148,11 +151,11 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener, // does not propagate all task info changes. mTaskChangeListener.ifPresent(listener -> listener.onNonTransitionTaskChanging(taskInfo)); - } else { - mDesktopRepository.ifPresent(repository -> { - repository.updateTask(taskInfo.displayId, taskInfo.taskId, - taskInfo.isVisible); - }); + } else if (mDesktopUserRepositories.isPresent()) { + DesktopRepository currentRepo = + mDesktopUserRepositories.get().getProfile(taskInfo.userId); + currentRepo.updateTask(taskInfo.displayId, taskInfo.taskId, + taskInfo.isVisible); } } updateLaunchAdjacentController(); @@ -176,10 +179,11 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener, ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Freeform Task Focus Changed: #%d focused=%b", taskInfo.taskId, taskInfo.isFocused); - if (DesktopModeStatus.canEnterDesktopMode(mContext) && taskInfo.isFocused) { - mDesktopRepository.ifPresent(repository -> { - repository.addTask(taskInfo.displayId, taskInfo.taskId, taskInfo.isVisible); - }); + if (DesktopModeStatus.canEnterDesktopMode(mContext) && taskInfo.isFocused + && mDesktopUserRepositories.isPresent()) { + DesktopRepository repository = + mDesktopUserRepositories.get().getProfile(taskInfo.userId); + repository.addTask(taskInfo.displayId, taskInfo.taskId, taskInfo.isVisible); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java index fb4afe41e193..af187682d379 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java @@ -94,6 +94,7 @@ import com.android.wm.shell.common.pip.PipPerfHintController; import com.android.wm.shell.common.pip.PipUiEventLogger; import com.android.wm.shell.common.pip.PipUtils; import com.android.wm.shell.desktopmode.DesktopRepository; +import com.android.wm.shell.desktopmode.DesktopUserRepositories; import com.android.wm.shell.pip.phone.PipMotionHelper; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.shared.animation.Interpolators; @@ -152,7 +153,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, private final PipSurfaceTransactionHelper mSurfaceTransactionHelper; private final Optional<SplitScreenController> mSplitScreenOptional; @Nullable private final PipPerfHintController mPipPerfHintController; - private final Optional<DesktopRepository> mDesktopRepositoryOptional; + private final Optional<DesktopUserRepositories> mDesktopUserRepositoriesOptional; private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer; private final DisplayController mDisplayController; protected final ShellTaskOrganizer mTaskOrganizer; @@ -398,7 +399,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, @NonNull PipParamsChangedForwarder pipParamsChangedForwarder, Optional<SplitScreenController> splitScreenOptional, Optional<PipPerfHintController> pipPerfHintControllerOptional, - Optional<DesktopRepository> desktopRepositoryOptional, + Optional<DesktopUserRepositories> desktopUserRepositoriesOptional, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, @NonNull DisplayController displayController, @NonNull PipUiEventLogger pipUiEventLogger, @@ -426,7 +427,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, new PipSurfaceTransactionHelper.VsyncSurfaceControlTransactionFactory(); mSplitScreenOptional = splitScreenOptional; mPipPerfHintController = pipPerfHintControllerOptional.orElse(null); - mDesktopRepositoryOptional = desktopRepositoryOptional; + mDesktopUserRepositoriesOptional = desktopUserRepositoriesOptional; mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer; mDisplayController = displayController; mTaskOrganizer = shellTaskOrganizer; @@ -764,7 +765,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, // previous freeform bounds that is saved in DesktopRepository. // 2) If PiP was entered through other means (e.g. user swipe up), exit to initial // freeform bounds. Note that this case has a flicker at the moment (b/379984108). - Rect freeformBounds = mDesktopRepositoryOptional.get().removeBoundsBeforeMinimize( + Rect freeformBounds = getCurrentRepo().removeBoundsBeforeMinimize( mTaskInfo.taskId); return freeformBounds != null ? freeformBounds @@ -779,11 +780,17 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, /** Returns whether PiP is exiting while we're in desktop mode. */ // TODO(b/377581840): Update this check to include non-minimized cases, e.g. split to PiP etc. private boolean isPipExitingToDesktopMode() { - return Flags.enableDesktopWindowingPip() && mDesktopRepositoryOptional.isPresent() - && (mDesktopRepositoryOptional.get().getVisibleTaskCount(mTaskInfo.displayId) > 0 + DesktopRepository currentRepo = getCurrentRepo(); + return Flags.enableDesktopWindowingPip() && currentRepo != null + && (currentRepo.getVisibleTaskCount(mTaskInfo.displayId) > 0 || isDisplayInFreeform()); } + private DesktopRepository getCurrentRepo() { + return mDesktopUserRepositoriesOptional.map(DesktopUserRepositories::getCurrent).orElse( + null); + } + private void exitLaunchIntoPipTask(WindowContainerTransaction wct) { wct.startTask(mTaskInfo.launchIntoPipHostTaskId, null /* ActivityOptions */); mTaskOrganizer.applyTransaction(wct); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java index 7145e0699765..4461a5c6a70c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java @@ -39,7 +39,7 @@ import com.android.window.flags.Flags; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.pip.PipBoundsState; -import com.android.wm.shell.desktopmode.DesktopRepository; +import com.android.wm.shell.desktopmode.DesktopUserRepositories; import com.android.wm.shell.pip.PipTransitionController; import com.android.wm.shell.pip2.PipSurfaceTransactionHelper; import com.android.wm.shell.pip2.animation.PipAlphaAnimator; @@ -58,7 +58,7 @@ public class PipScheduler { private final PipBoundsState mPipBoundsState; private final ShellExecutor mMainExecutor; private final PipTransitionState mPipTransitionState; - private final Optional<DesktopRepository> mDesktopRepositoryOptional; + private final Optional<DesktopUserRepositories> mDesktopUserRepositoriesOptional; private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer; private PipTransitionController mPipTransitionController; private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory @@ -72,13 +72,13 @@ public class PipScheduler { PipBoundsState pipBoundsState, ShellExecutor mainExecutor, PipTransitionState pipTransitionState, - Optional<DesktopRepository> desktopRepositoryOptional, + Optional<DesktopUserRepositories> desktopUserRepositoriesOptional, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) { mContext = context; mPipBoundsState = pipBoundsState; mMainExecutor = mainExecutor; mPipTransitionState = pipTransitionState; - mDesktopRepositoryOptional = desktopRepositoryOptional; + mDesktopUserRepositoriesOptional = desktopUserRepositoriesOptional; mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer; mSurfaceControlTransactionFactory = @@ -268,8 +268,8 @@ public class PipScheduler { /** Returns whether PiP is exiting while we're in desktop mode. */ private boolean isPipExitingToDesktopMode() { - return Flags.enableDesktopWindowingPip() && mDesktopRepositoryOptional.isPresent() - && (mDesktopRepositoryOptional.get().getVisibleTaskCount( + return Flags.enableDesktopWindowingPip() && mDesktopUserRepositoriesOptional.isPresent() + && (mDesktopUserRepositoriesOptional.get().getCurrent().getVisibleTaskCount( Objects.requireNonNull(mPipTransitionState.getPipTaskInfo()).displayId) > 0 || isDisplayInFreeform()); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java index 363c95fcf010..441f96728d0c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java @@ -63,6 +63,7 @@ import com.android.wm.shell.common.SingleInstanceRemoteListener; import com.android.wm.shell.common.TaskStackListenerCallback; import com.android.wm.shell.common.TaskStackListenerImpl; import com.android.wm.shell.desktopmode.DesktopRepository; +import com.android.wm.shell.desktopmode.DesktopUserRepositories; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.shared.GroupedTaskInfo; import com.android.wm.shell.shared.annotations.ExternalThread; @@ -72,6 +73,7 @@ import com.android.wm.shell.shared.split.SplitBounds; import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; +import com.android.wm.shell.sysui.UserChangeListener; import java.io.PrintWriter; import java.util.ArrayList; @@ -89,13 +91,14 @@ import java.util.function.Consumer; */ public class RecentTasksController implements TaskStackListenerCallback, RemoteCallable<RecentTasksController>, DesktopRepository.ActiveTasksListener, - TaskStackTransitionObserver.TaskStackTransitionObserverListener { + TaskStackTransitionObserver.TaskStackTransitionObserverListener, UserChangeListener { private static final String TAG = RecentTasksController.class.getSimpleName(); private final Context mContext; private final ShellController mShellController; private final ShellCommandHandler mShellCommandHandler; - private final Optional<DesktopRepository> mDesktopRepository; + private final Optional<DesktopUserRepositories> mDesktopUserRepositories; + private final ShellExecutor mMainExecutor; private final TaskStackListenerImpl mTaskStackListener; private final RecentTasksImpl mImpl = new RecentTasksImpl(); @@ -108,6 +111,8 @@ public class RecentTasksController implements TaskStackListenerCallback, // Mapping of split task ids, mappings are symmetrical (ie. if t1 is the taskid of a task in a // pair, then mSplitTasks[t1] = t2, and mSplitTasks[t2] = t1) private final SparseIntArray mSplitTasks = new SparseIntArray(); + + private int mUserId; /** * Maps taskId to {@link SplitBounds} for both taskIDs. * Meaning there will be two taskId integers mapping to the same object. @@ -133,7 +138,7 @@ public class RecentTasksController implements TaskStackListenerCallback, ShellCommandHandler shellCommandHandler, TaskStackListenerImpl taskStackListener, ActivityTaskManager activityTaskManager, - Optional<DesktopRepository> desktopRepository, + Optional<DesktopUserRepositories> desktopUserRepositories, TaskStackTransitionObserver taskStackTransitionObserver, @ShellMainThread ShellExecutor mainExecutor ) { @@ -141,7 +146,7 @@ public class RecentTasksController implements TaskStackListenerCallback, return null; } return new RecentTasksController(context, shellInit, shellController, shellCommandHandler, - taskStackListener, activityTaskManager, desktopRepository, + taskStackListener, activityTaskManager, desktopUserRepositories, taskStackTransitionObserver, mainExecutor); } @@ -151,7 +156,7 @@ public class RecentTasksController implements TaskStackListenerCallback, ShellCommandHandler shellCommandHandler, TaskStackListenerImpl taskStackListener, ActivityTaskManager activityTaskManager, - Optional<DesktopRepository> desktopRepository, + Optional<DesktopUserRepositories> desktopUserRepositories, TaskStackTransitionObserver taskStackTransitionObserver, ShellExecutor mainExecutor) { mContext = context; @@ -160,7 +165,7 @@ public class RecentTasksController implements TaskStackListenerCallback, mActivityTaskManager = activityTaskManager; mPcFeatureEnabled = mContext.getPackageManager().hasSystemFeature(FEATURE_PC); mTaskStackListener = taskStackListener; - mDesktopRepository = desktopRepository; + mDesktopUserRepositories = desktopUserRepositories; mTaskStackTransitionObserver = taskStackTransitionObserver; mMainExecutor = mainExecutor; shellInit.addInitCallback(this::onInit, this); @@ -175,12 +180,15 @@ public class RecentTasksController implements TaskStackListenerCallback, } @RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE) - private void onInit() { + void onInit() { mShellController.addExternalInterface(KEY_EXTRA_SHELL_RECENT_TASKS, this::createExternalInterface, this); mShellCommandHandler.addDumpCallback(this::dump, this); + mUserId = ActivityManager.getCurrentUser(); + mDesktopUserRepositories.ifPresent( + desktopUserRepositories -> + desktopUserRepositories.getCurrent().addActiveTaskListener(this)); mTaskStackListener.addListener(this); - mDesktopRepository.ifPresent(it -> it.addActiveTaskListener(this)); mTaskStackTransitionObserver.addTaskStackTransitionObserverListener(this, mMainExecutor); mContext.getSystemService(KeyguardManager.class).addKeyguardLockedStateListener( @@ -291,9 +299,9 @@ public class RecentTasksController implements TaskStackListenerCallback, */ @Override public void onRecentTaskRemovedForAddTask(int taskId) { - mDesktopRepository.ifPresent( - repo -> repo.removeFreeformTask(INVALID_DISPLAY, taskId) - ); + mDesktopUserRepositories.ifPresent( + desktopUserRepositories -> desktopUserRepositories.getCurrent().removeFreeformTask( + INVALID_DISPLAY, taskId)); } public void onTaskAdded(RunningTaskInfo taskInfo) { @@ -512,10 +520,9 @@ public class RecentTasksController implements TaskStackListenerCallback, // If it's not in the mapping, then it was already paired with another task continue; } - - if (DesktopModeStatus.canEnterDesktopMode(mContext) - && mDesktopRepository.isPresent() - && mDesktopRepository.get().isActiveTask(taskInfo.taskId)) { + if (DesktopModeStatus.canEnterDesktopMode(mContext) && + mDesktopUserRepositories.isPresent() + && mDesktopUserRepositories.get().getCurrent().isActiveTask(taskInfo.taskId)) { // Freeform tasks will be added as a separate entry if (mostRecentFreeformTaskIndex == Integer.MAX_VALUE) { mostRecentFreeformTaskIndex = groupedTasks.size(); @@ -531,7 +538,7 @@ public class RecentTasksController implements TaskStackListenerCallback, taskInfo.lastNonFullscreenBounds.top); } freeformTasks.add(taskInfo); - if (mDesktopRepository.get().isMinimizedTask(taskInfo.taskId)) { + if (mDesktopUserRepositories.get().getCurrent().isMinimizedTask(taskInfo.taskId)) { minimizedFreeformTasks.add(taskInfo.taskId); } continue; @@ -703,6 +710,21 @@ public class RecentTasksController implements TaskStackListenerCallback, } } + @Override + public void onUserChanged(int newUserId, @NonNull Context userContext) { + if (mDesktopUserRepositories.isEmpty()) return; + + DesktopRepository previousUserRepository = + mDesktopUserRepositories.get().getProfile(mUserId); + mUserId = newUserId; + DesktopRepository currentUserRepository = + mDesktopUserRepositories.get().getProfile(newUserId); + + // No-op if both profile ids map to the same user. + if (previousUserRepository.getUserId() == currentUserRepository.getUserId()) return; + previousUserRepository.removeActiveTasksListener(this); + currentUserRepository.addActiveTaskListener(this); + } /** * The interface for calls from outside the host process. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenu.kt index 101467df03ac..ff52a45c94e2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenu.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenu.kt @@ -32,7 +32,7 @@ import com.android.internal.annotations.VisibleForTesting import com.android.window.flags.Flags import com.android.wm.shell.RootTaskDisplayAreaOrganizer import com.android.wm.shell.common.DisplayController -import com.android.wm.shell.desktopmode.DesktopRepository +import com.android.wm.shell.desktopmode.DesktopUserRepositories import com.android.wm.shell.shared.multiinstance.ManageWindowsViewContainer import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewContainer @@ -51,7 +51,7 @@ class DesktopHeaderManageWindowsMenu( private val displayController: DisplayController, private val rootTdaOrganizer: RootTaskDisplayAreaOrganizer, context: Context, - private val desktopRepository: DesktopRepository, + private val desktopUserRepositories: DesktopUserRepositories, private val surfaceControlBuilderSupplier: Supplier<SurfaceControl.Builder>, private val surfaceControlTransactionSupplier: Supplier<SurfaceControl.Transaction>, snapshotList: List<Pair<Int, TaskSnapshot>>, @@ -76,6 +76,7 @@ class DesktopHeaderManageWindowsMenu( val flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH or WindowManager.LayoutParams.FLAG_SPLIT_TOUCH + val desktopRepository = desktopUserRepositories.getProfile(callerTaskInfo.userId) menuViewContainer = if (Flags.enableFullyImmersiveInDesktop() && desktopRepository.isTaskInFullImmersiveState(callerTaskInfo.taskId)) { // Use system view container so that forcibly shown system bars take effect in diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java index 17b299d745f1..0c077da0a5e8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java @@ -117,6 +117,7 @@ import com.android.wm.shell.desktopmode.DesktopRepository; import com.android.wm.shell.desktopmode.DesktopTasksController; import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition; import com.android.wm.shell.desktopmode.DesktopTasksLimiter; +import com.android.wm.shell.desktopmode.DesktopUserRepositories; import com.android.wm.shell.desktopmode.DesktopWallpaperActivity; import com.android.wm.shell.desktopmode.WindowDecorCaptionHandleRepository; import com.android.wm.shell.desktopmode.common.ToggleTaskSizeInteraction; @@ -169,7 +170,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, private final ActivityTaskManager mActivityTaskManager; private final ShellCommandHandler mShellCommandHandler; private final ShellTaskOrganizer mTaskOrganizer; - private final DesktopRepository mDesktopRepository; + private final DesktopUserRepositories mDesktopUserRepositories; private final ShellController mShellController; private final Context mContext; private final @ShellMainThread Handler mMainHandler; @@ -247,7 +248,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, ShellCommandHandler shellCommandHandler, IWindowManager windowManager, ShellTaskOrganizer taskOrganizer, - DesktopRepository desktopRepository, + DesktopUserRepositories desktopUserRepositories, DisplayController displayController, ShellController shellController, DisplayInsetsController displayInsetsController, @@ -278,7 +279,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, shellCommandHandler, windowManager, taskOrganizer, - desktopRepository, + desktopUserRepositories, displayController, shellController, displayInsetsController, @@ -318,7 +319,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, ShellCommandHandler shellCommandHandler, IWindowManager windowManager, ShellTaskOrganizer taskOrganizer, - DesktopRepository desktopRepository, + DesktopUserRepositories desktopUserRepositories, DisplayController displayController, ShellController shellController, DisplayInsetsController displayInsetsController, @@ -352,7 +353,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, mBgExecutor = bgExecutor; mActivityTaskManager = mContext.getSystemService(ActivityTaskManager.class); mTaskOrganizer = taskOrganizer; - mDesktopRepository = desktopRepository; + mDesktopUserRepositories = desktopUserRepositories; mShellController = shellController; mDisplayController = displayController; mDisplayInsetsController = displayInsetsController; @@ -628,12 +629,14 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, ); } - private void onEnterOrExitImmersive(int taskId) { - final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId); + private void onEnterOrExitImmersive(RunningTaskInfo taskInfo) { + final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskInfo.taskId); if (decoration == null) { return; } - if (mDesktopRepository.isTaskInFullImmersiveState(taskId)) { + final DesktopRepository desktopRepository = mDesktopUserRepositories.getProfile( + taskInfo.userId); + if (desktopRepository.isTaskInFullImmersiveState(taskInfo.taskId)) { mDesktopModeUiEventLogger.log(decoration.mTaskInfo, DesktopUiEventEnum.DESKTOP_WINDOW_MAXIMIZE_BUTTON_MENU_TAP_TO_RESTORE); mDesktopImmersiveController.moveTaskToNonImmersive( @@ -894,7 +897,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, && TaskInfoKt.getRequestingImmersive(decoration.mTaskInfo)) { // Task is requesting immersive, so it should either enter or exit immersive, // depending on immersive state. - onEnterOrExitImmersive(decoration.mTaskInfo.taskId); + onEnterOrExitImmersive(decoration.mTaskInfo); } else { // Full immersive is disabled or task doesn't request/support it, so just // toggle between maximize/restore states. @@ -1084,8 +1087,10 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, } final boolean touchingButton = (id == R.id.close_window || id == R.id.maximize_window || id == R.id.open_menu_button || id == R.id.minimize_window); + final DesktopRepository desktopRepository = mDesktopUserRepositories.getProfile( + taskInfo.userId); final boolean dragAllowed = - !mDesktopRepository.isTaskInFullImmersiveState(taskInfo.taskId); + !desktopRepository.isTaskInFullImmersiveState(taskInfo.taskId); switch (e.getActionMasked()) { case MotionEvent.ACTION_DOWN: { if (dragAllowed) { @@ -1195,7 +1200,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, && action != MotionEvent.ACTION_CANCEL)) { return false; } - if (mDesktopRepository.isTaskInFullImmersiveState(mTaskId)) { + final DesktopRepository desktopRepository = mDesktopUserRepositories.getCurrent(); + if (desktopRepository.isTaskInFullImmersiveState(mTaskId)) { // Disallow double-tap to resize when in full immersive. return false; } @@ -1608,7 +1614,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, mContext.createContextAsUser(UserHandle.of(taskInfo.userId), 0 /* flags */), mDisplayController, mSplitScreenController, - mDesktopRepository, + mDesktopUserRepositories, mTaskOrganizer, taskInfo, taskSurface, @@ -1645,7 +1651,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, return Unit.INSTANCE; }); windowDecoration.setOnImmersiveOrRestoreClickListener(() -> { - onEnterOrExitImmersive(taskInfo.taskId); + onEnterOrExitImmersive(taskInfo); return Unit.INSTANCE; }); windowDecoration.setOnLeftSnapClickListener(() -> { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java index 5eb031218ee1..9cf90a4e7b58 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java @@ -99,7 +99,7 @@ import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.desktopmode.CaptionState; import com.android.wm.shell.desktopmode.DesktopModeEventLogger; -import com.android.wm.shell.desktopmode.DesktopRepository; +import com.android.wm.shell.desktopmode.DesktopUserRepositories; import com.android.wm.shell.desktopmode.WindowDecorCaptionHandleRepository; import com.android.wm.shell.shared.annotations.ShellBackgroundThread; import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; @@ -206,14 +206,14 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin private final Runnable mCapturedLinkExpiredRunnable = this::onCapturedLinkExpired; private final MultiInstanceHelper mMultiInstanceHelper; private final WindowDecorCaptionHandleRepository mWindowDecorCaptionHandleRepository; - private final DesktopRepository mDesktopRepository; + private final DesktopUserRepositories mDesktopUserRepositories; public DesktopModeWindowDecoration( Context context, @NonNull Context userContext, DisplayController displayController, SplitScreenController splitScreenController, - DesktopRepository desktopRepository, + DesktopUserRepositories desktopUserRepositories, ShellTaskOrganizer taskOrganizer, ActivityManager.RunningTaskInfo taskInfo, SurfaceControl taskSurface, @@ -228,10 +228,10 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin MultiInstanceHelper multiInstanceHelper, WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository, DesktopModeEventLogger desktopModeEventLogger) { - this (context, userContext, displayController, splitScreenController, desktopRepository, - taskOrganizer, taskInfo, taskSurface, handler, bgExecutor, choreographer, syncQueue, - appHeaderViewHolderFactory, rootTaskDisplayAreaOrganizer, genericLinksParser, - assistContentRequester, + this (context, userContext, displayController, splitScreenController, + desktopUserRepositories, taskOrganizer, taskInfo, taskSurface, handler, + bgExecutor, choreographer, syncQueue, appHeaderViewHolderFactory, + rootTaskDisplayAreaOrganizer, genericLinksParser, assistContentRequester, SurfaceControl.Builder::new, SurfaceControl.Transaction::new, WindowContainerTransaction::new, SurfaceControl::new, new WindowManagerWrapper( context.getSystemService(WindowManager.class)), @@ -246,7 +246,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin @NonNull Context userContext, DisplayController displayController, SplitScreenController splitScreenController, - DesktopRepository desktopRepository, + DesktopUserRepositories desktopUserRepositories, ShellTaskOrganizer taskOrganizer, ActivityManager.RunningTaskInfo taskInfo, SurfaceControl taskSurface, @@ -287,7 +287,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mMultiInstanceHelper = multiInstanceHelper; mWindowManagerWrapper = windowManagerWrapper; mWindowDecorCaptionHandleRepository = windowDecorCaptionHandleRepository; - mDesktopRepository = desktopRepository; + mDesktopUserRepositories = desktopUserRepositories; } /** @@ -437,7 +437,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin public void updateDisabledResizingEdge( DragResizeWindowGeometry.DisabledEdge disabledResizingEdge, boolean shouldDelayUpdate) { mDisabledResizingEdge = disabledResizingEdge; - final boolean inFullImmersive = mDesktopRepository + final boolean inFullImmersive = mDesktopUserRepositories.getCurrent() .isTaskInFullImmersiveState(mTaskInfo.taskId); if (shouldDelayUpdate) { return; @@ -541,7 +541,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mOpenByDefaultDialog.relayout(taskInfo); } - final boolean inFullImmersive = mDesktopRepository + final boolean inFullImmersive = mDesktopUserRepositories.getProfile(taskInfo.userId) .isTaskInFullImmersiveState(taskInfo.taskId); updateRelayoutParams(mRelayoutParams, mContext, taskInfo, applyStartTransactionOnDraw, shouldSetTaskVisibilityPositionAndCrop, mIsStatusBarVisible, @@ -1302,9 +1302,11 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mMaximizeMenu = mMaximizeMenuFactory.create(mSyncQueue, mRootTaskDisplayAreaOrganizer, mDisplayController, mTaskInfo, mContext, calculateMaximizeMenuPosition(menuWidth), mSurfaceControlTransactionSupplier); + mMaximizeMenu.show( /* isTaskInImmersiveMode= */ Flags.enableFullyImmersiveInDesktop() - && mDesktopRepository.isTaskInFullImmersiveState(mTaskInfo.taskId), + && mDesktopUserRepositories.getProfile(mTaskInfo.userId) + .isTaskInFullImmersiveState(mTaskInfo.taskId), /* menuWidth= */ menuWidth, /* showImmersiveOption= */ Flags.enableFullyImmersiveInDesktop() && TaskInfoKt.getRequestingImmersive(mTaskInfo), @@ -1394,7 +1396,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin && mMinimumInstancesFound; final boolean shouldShowChangeAspectRatioButton = HandleMenu.Companion .shouldShowChangeAspectRatioButton(mTaskInfo); - final boolean inDesktopImmersive = mDesktopRepository + final boolean inDesktopImmersive = mDesktopUserRepositories.getProfile(mTaskInfo.userId) .isTaskInFullImmersiveState(mTaskInfo.taskId); final boolean isBrowserApp = isBrowserApp(); mHandleMenu = mHandleMenuFactory.create( @@ -1474,7 +1476,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mDisplayController, mRootTaskDisplayAreaOrganizer, mContext, - mDesktopRepository, + mDesktopUserRepositories, mSurfaceControlBuilderSupplier, mSurfaceControlTransactionSupplier, snapshotList, @@ -1770,7 +1772,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin void setAnimatingTaskResizeOrReposition(boolean animatingTaskResizeOrReposition) { if (mRelayoutParams.mLayoutResId == R.layout.desktop_mode_app_handle) return; final boolean inFullImmersive = - mDesktopRepository.isTaskInFullImmersiveState(mTaskInfo.taskId); + mDesktopUserRepositories.getProfile(mTaskInfo.userId) + .isTaskInFullImmersiveState(mTaskInfo.taskId); asAppHeader(mWindowDecorViewHolder).bindData(new AppHeaderViewHolder.HeaderData( mTaskInfo, TaskInfoKt.getRequestingImmersive(mTaskInfo), @@ -1798,8 +1801,9 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin return !animatingTaskResizeOrReposition; } final boolean inImmersiveAndRequesting = - mDesktopRepository.isTaskInFullImmersiveState(mTaskInfo.taskId) - && TaskInfoKt.getRequestingImmersive(mTaskInfo); + mDesktopUserRepositories.getProfile(mTaskInfo.userId) + .isTaskInFullImmersiveState(mTaskInfo.taskId) + && TaskInfoKt.getRequestingImmersive(mTaskInfo); return !animatingTaskResizeOrReposition && !inImmersiveAndRequesting; } @@ -1820,7 +1824,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin @NonNull Context userContext, DisplayController displayController, SplitScreenController splitScreenController, - DesktopRepository desktopRepository, + DesktopUserRepositories desktopUserRepositories, ShellTaskOrganizer taskOrganizer, ActivityManager.RunningTaskInfo taskInfo, SurfaceControl taskSurface, @@ -1840,7 +1844,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin userContext, displayController, splitScreenController, - desktopRepository, + desktopUserRepositories, taskOrganizer, taskInfo, taskSurface, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModel.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModel.kt index 0e40a5350a43..9db69d5c1bc5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModel.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModel.kt @@ -33,6 +33,7 @@ import com.android.wm.shell.common.SyncTransactionQueue import com.android.wm.shell.desktopmode.DesktopModeEventLogger import com.android.wm.shell.desktopmode.DesktopRepository import com.android.wm.shell.desktopmode.DesktopTasksController +import com.android.wm.shell.desktopmode.DesktopUserRepositories import com.android.wm.shell.desktopmode.ReturnToDragStartAnimator import com.android.wm.shell.desktopmode.ToggleResizeDesktopTaskTransitionHandler import com.android.wm.shell.transition.Transitions @@ -48,7 +49,7 @@ class DesktopTilingDecorViewModel( private val shellTaskOrganizer: ShellTaskOrganizer, private val toggleResizeDesktopTaskTransitionHandler: ToggleResizeDesktopTaskTransitionHandler, private val returnToDragStartAnimator: ReturnToDragStartAnimator, - private val taskRepository: DesktopRepository, + private val desktopUserRepositories: DesktopUserRepositories, private val desktopModeEventLogger: DesktopModeEventLogger, ) : DisplayChangeController.OnDisplayChangingListener { @VisibleForTesting @@ -81,7 +82,7 @@ class DesktopTilingDecorViewModel( shellTaskOrganizer, toggleResizeDesktopTaskTransitionHandler, returnToDragStartAnimator, - taskRepository, + desktopUserRepositories, desktopModeEventLogger, ) tilingTransitionHandlerByDisplayId.put(displayId, newHandler) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt index 3b5c6ca2e58a..7ceac52dd2a1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt @@ -49,6 +49,7 @@ import com.android.wm.shell.desktopmode.DesktopModeEventLogger import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger import com.android.wm.shell.desktopmode.DesktopRepository import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition +import com.android.wm.shell.desktopmode.DesktopUserRepositories import com.android.wm.shell.desktopmode.ReturnToDragStartAnimator import com.android.wm.shell.desktopmode.ToggleResizeDesktopTaskTransitionHandler import com.android.wm.shell.transition.Transitions @@ -72,7 +73,7 @@ class DesktopTilingWindowDecoration( private val shellTaskOrganizer: ShellTaskOrganizer, private val toggleResizeDesktopTaskTransitionHandler: ToggleResizeDesktopTaskTransitionHandler, private val returnToDragStartAnimator: ReturnToDragStartAnimator, - private val taskRepository: DesktopRepository, + private val desktopUserRepositories: DesktopUserRepositories, private val desktopModeEventLogger: DesktopModeEventLogger, private val transactionSupplier: Supplier<Transaction> = Supplier { Transaction() }, ) : @@ -630,6 +631,7 @@ class DesktopTilingWindowDecoration( private fun allTiledTasksVisible(): Boolean { val leftTiledTask = leftTaskResizingHelper ?: return false val rightTiledTask = rightTaskResizingHelper ?: return false + val taskRepository = desktopUserRepositories.current return taskRepository.isVisibleTask(leftTiledTask.taskInfo.taskId) && taskRepository.isVisibleTask(rightTiledTask.taskInfo.taskId) } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java index d5287e742c2c..67573dabf2ec 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java @@ -30,6 +30,7 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.app.ActivityManager.RunningTaskInfo; import android.app.TaskInfo; @@ -61,12 +62,16 @@ import com.android.wm.shell.common.DockStateReader; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.compatui.api.CompatUIInfo; +import com.android.wm.shell.desktopmode.DesktopRepository; +import com.android.wm.shell.desktopmode.DesktopUserRepositories; import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.Transitions; import dagger.Lazy; +import java.util.Optional; + import org.junit.Assert; import org.junit.Before; import org.junit.Rule; @@ -130,6 +135,10 @@ public class CompatUIControllerTest extends ShellTestCase { private CompatUIShellCommandHandler mCompatUIShellCommandHandler; @Mock private AccessibilityManager mAccessibilityManager; + @Mock + private DesktopUserRepositories mDesktopUserRepositories; + @Mock + private DesktopRepository mDesktopRepository; @Captor ArgumentCaptor<OnInsetsChangedListener> mOnInsetsChangedListenerCaptor; @@ -137,7 +146,6 @@ public class CompatUIControllerTest extends ShellTestCase { @NonNull private CompatUIStatusManager mCompatUIStatusManager; - private boolean mInDesktopModePredicateResult; @Before public void setUp() { @@ -152,6 +160,8 @@ public class CompatUIControllerTest extends ShellTestCase { doReturn(TASK_ID).when(mMockLetterboxEduLayout).getTaskId(); doReturn(true).when(mMockLetterboxEduLayout).createLayout(anyBoolean()); doReturn(true).when(mMockLetterboxEduLayout).updateCompatInfo(any(), any(), anyBoolean()); + doReturn(mDesktopRepository).when(mDesktopUserRepositories).getCurrent(); + doReturn(mDesktopRepository).when(mDesktopUserRepositories).getProfile(anyInt()); doReturn(DISPLAY_ID).when(mMockRestartDialogLayout).getDisplayId(); doReturn(TASK_ID).when(mMockRestartDialogLayout).getTaskId(); @@ -164,7 +174,7 @@ public class CompatUIControllerTest extends ShellTestCase { mMockDisplayController, mMockDisplayInsetsController, mMockImeController, mMockSyncQueue, mMockExecutor, mMockTransitionsLazy, mDockStateReader, mCompatUIConfiguration, mCompatUIShellCommandHandler, mAccessibilityManager, - mCompatUIStatusManager, i -> mInDesktopModePredicateResult) { + mCompatUIStatusManager, Optional.of(mDesktopUserRepositories)) { @Override CompatUIWindowManager createCompatUiWindowManager(Context context, TaskInfo taskInfo, ShellTaskOrganizer.TaskListener taskListener) { @@ -707,13 +717,17 @@ public class CompatUIControllerTest extends ShellTestCase { @RequiresFlagsDisabled(Flags.FLAG_APP_COMPAT_UI_FRAMEWORK) @EnableFlags(Flags.FLAG_SKIP_COMPAT_UI_EDUCATION_IN_DESKTOP_MODE) public void testUpdateActiveTaskInfo_removeAllComponentWhenInDesktopModeFlagEnabled() { - mInDesktopModePredicateResult = false; TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true); + when(mDesktopUserRepositories.getCurrent().getVisibleTaskCount(DISPLAY_ID)).thenReturn(0); + mController.onCompatInfoChanged(new CompatUIInfo(taskInfo, mMockTaskListener)); + verify(mController, never()).removeLayouts(taskInfo.taskId); - mInDesktopModePredicateResult = true; + when(mDesktopUserRepositories.getCurrent().getVisibleTaskCount(DISPLAY_ID)).thenReturn(2); + mController.onCompatInfoChanged(new CompatUIInfo(taskInfo, mMockTaskListener)); + verify(mController).removeLayouts(taskInfo.taskId); } @@ -721,13 +735,17 @@ public class CompatUIControllerTest extends ShellTestCase { @RequiresFlagsDisabled(Flags.FLAG_APP_COMPAT_UI_FRAMEWORK) @DisableFlags(Flags.FLAG_SKIP_COMPAT_UI_EDUCATION_IN_DESKTOP_MODE) public void testUpdateActiveTaskInfo_removeAllComponentWhenInDesktopModeFlagDisabled() { - mInDesktopModePredicateResult = false; + when(mDesktopUserRepositories.getCurrent().getVisibleTaskCount(DISPLAY_ID)).thenReturn(0); TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true); + mController.onCompatInfoChanged(new CompatUIInfo(taskInfo, mMockTaskListener)); + verify(mController, never()).removeLayouts(taskInfo.taskId); - mInDesktopModePredicateResult = true; + when(mDesktopUserRepositories.getCurrent().getVisibleTaskCount(DISPLAY_ID)).thenReturn(2); + mController.onCompatInfoChanged(new CompatUIInfo(taskInfo, mMockTaskListener)); + verify(mController, never()).removeLayouts(taskInfo.taskId); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt index 2ea0379e3bf7..41a594a3347a 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt @@ -23,6 +23,7 @@ import android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT import android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT import android.graphics.Rect import android.os.Binder +import android.os.UserManager import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.SetFlagsRule import android.testing.AndroidTestingRunner @@ -96,11 +97,12 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { @Mock lateinit var taskStackListener: TaskStackListenerImpl @Mock lateinit var persistentRepository: DesktopPersistentRepository @Mock lateinit var repositoryInitializer: DesktopRepositoryInitializer + @Mock lateinit var userManager: UserManager private lateinit var mockitoSession: StaticMockitoSession private lateinit var handler: DesktopActivityOrientationChangeHandler private lateinit var shellInit: ShellInit - private lateinit var taskRepository: DesktopRepository + private lateinit var userRepositories: DesktopUserRepositories private lateinit var testScope: CoroutineScope // Mock running tasks are registered here so we can get the list from mock shell task organizer. private val runningTasks = mutableListOf<RunningTaskInfo>() @@ -117,13 +119,14 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { testScope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob()) shellInit = spy(ShellInit(testExecutor)) - taskRepository = - DesktopRepository( + userRepositories = + DesktopUserRepositories( context, shellInit, persistentRepository, repositoryInitializer, - testScope + testScope, + userManager ) whenever(shellTaskOrganizer.getRunningTasks(anyInt())).thenAnswer { runningTasks } whenever(transitions.startTransition(anyInt(), any(), isNull())).thenAnswer { Binder() } @@ -132,7 +135,7 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { ) handler = DesktopActivityOrientationChangeHandler(context, shellInit, shellTaskOrganizer, - taskStackListener, resizeTransitionHandler, taskRepository) + taskStackListener, resizeTransitionHandler, userRepositories) shellInit.init() } @@ -156,7 +159,7 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { clearInvocations(shellInit) handler = DesktopActivityOrientationChangeHandler(context, shellInit, shellTaskOrganizer, - taskStackListener, resizeTransitionHandler, taskRepository) + taskStackListener, resizeTransitionHandler, userRepositories) verify(shellInit, never()).addInitCallback(any(), any<DesktopActivityOrientationChangeHandler>()) @@ -180,7 +183,7 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { activityInfo.screenOrientation = SCREEN_ORIENTATION_PORTRAIT task.topActivityInfo = activityInfo whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task) - taskRepository.addTask(DEFAULT_DISPLAY, task.taskId, isVisible = true) + userRepositories.current.addTask(DEFAULT_DISPLAY, task.taskId, isVisible = true) runningTasks.add(task) taskStackListener.onActivityRequestedOrientationChanged(task.taskId, @@ -203,7 +206,7 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { @Test fun handleActivityOrientationChange_notInDesktopMode_doNothing() { val task = setUpFreeformTask(isResizeable = false) - taskRepository.updateTask(task.displayId, task.taskId, isVisible = false) + userRepositories.current.updateTask(task.displayId, task.taskId, isVisible = false) taskStackListener.onActivityRequestedOrientationChanged(task.taskId, SCREEN_ORIENTATION_LANDSCAPE) @@ -268,7 +271,7 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() { task.topActivityInfo = activityInfo task.isResizeable = isResizeable whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task) - taskRepository.addTask(displayId, task.taskId, isVisible = true) + userRepositories.current.addTask(displayId, task.taskId, isVisible = true) runningTasks.add(task) return task } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopImmersiveControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopImmersiveControllerTest.kt index b57c55c4c45a..db4c7465ae48 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopImmersiveControllerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopImmersiveControllerTest.kt @@ -76,18 +76,19 @@ class DesktopImmersiveControllerTest : ShellTestCase() { @JvmField @Rule val animatorTestRule = AnimatorTestRule(this) @Mock private lateinit var mockTransitions: Transitions - private lateinit var desktopRepository: DesktopRepository + private lateinit var userRepositories: DesktopUserRepositories @Mock private lateinit var mockDisplayController: DisplayController @Mock private lateinit var mockShellTaskOrganizer: ShellTaskOrganizer @Mock private lateinit var mockDisplayLayout: DisplayLayout private val transactionSupplier = { StubTransaction() } private lateinit var controller: DesktopImmersiveController + private lateinit var desktopRepository: DesktopRepository @Before fun setUp() { - desktopRepository = DesktopRepository( - context, ShellInit(TestShellExecutor()), mock(), mock(), mock() + userRepositories = DesktopUserRepositories( + context, ShellInit(TestShellExecutor()), mock(), mock(), mock(), mock() ) whenever(mockDisplayController.getDisplayLayout(DEFAULT_DISPLAY)) .thenReturn(mockDisplayLayout) @@ -97,12 +98,13 @@ class DesktopImmersiveControllerTest : ShellTestCase() { controller = DesktopImmersiveController( shellInit = mock(), transitions = mockTransitions, - desktopRepository = desktopRepository, + desktopUserRepositories = userRepositories, displayController = mockDisplayController, shellTaskOrganizer = mockShellTaskOrganizer, shellCommandHandler = mock(), transactionSupplier = transactionSupplier, ) + desktopRepository = userRepositories.current } @Test diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt index 62717a32d99f..2d5544527436 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt @@ -60,6 +60,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mock +import org.mockito.Mockito import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.kotlin.any @@ -84,7 +85,7 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() { @Mock lateinit var transitions: Transitions @Mock - lateinit var desktopRepository: DesktopRepository + lateinit var userRepositories: DesktopUserRepositories @Mock lateinit var freeformTaskTransitionHandler: FreeformTaskTransitionHandler @Mock @@ -103,16 +104,21 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() { lateinit var shellInit: ShellInit @Mock lateinit var rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer + @Mock + private lateinit var desktopRepository: DesktopRepository private lateinit var mixedHandler: DesktopMixedTransitionHandler + @Before fun setUp() { + whenever(userRepositories.current).thenReturn(desktopRepository) + whenever(userRepositories.getProfile(Mockito.anyInt())).thenReturn(desktopRepository) mixedHandler = DesktopMixedTransitionHandler( context, transitions, - desktopRepository, + userRepositories, freeformTaskTransitionHandler, closeDesktopTaskTransitionHandler, desktopImmersiveController, diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt index 7f790d574a7e..9059d7d5342c 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt @@ -30,7 +30,6 @@ import com.android.wm.shell.TestShellExecutor import com.android.wm.shell.common.ShellExecutor import com.android.wm.shell.desktopmode.persistence.Desktop import com.android.wm.shell.desktopmode.persistence.DesktopPersistentRepository -import com.android.wm.shell.desktopmode.persistence.DesktopRepositoryInitializer import com.android.wm.shell.sysui.ShellInit import com.google.common.truth.Truth.assertThat import junit.framework.Assert.fail @@ -70,7 +69,6 @@ class DesktopRepositoryTest : ShellTestCase() { @Mock private lateinit var testExecutor: ShellExecutor @Mock private lateinit var persistentRepository: DesktopPersistentRepository - @Mock lateinit var repositoryInitializer: DesktopRepositoryInitializer @Before fun setUp() { @@ -80,11 +78,9 @@ class DesktopRepositoryTest : ShellTestCase() { repo = DesktopRepository( - context, - shellInit, persistentRepository, - repositoryInitializer, - datastoreScope + datastoreScope, + DEFAULT_USER_ID ) whenever(runBlocking { persistentRepository.readDesktop(any(), any()) }).thenReturn( Desktop.getDefaultInstance() 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 index 8e323acc4e66..b4daa6637f83 100644 --- 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 @@ -22,6 +22,7 @@ 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.desktopmode.DesktopUserRepositories import com.android.wm.shell.ShellTestCase import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFullscreenTask @@ -29,6 +30,7 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.anyInt import org.mockito.kotlin.mock import org.mockito.kotlin.never import org.mockito.kotlin.verify @@ -47,131 +49,163 @@ class DesktopTaskChangeListenerTest : ShellTestCase() { private lateinit var desktopTaskChangeListener: DesktopTaskChangeListener + private val desktopUserRepositories = mock<DesktopUserRepositories>() private val desktopRepository = mock<DesktopRepository>() @Before fun setUp() { - desktopTaskChangeListener = DesktopTaskChangeListener(desktopRepository) + desktopTaskChangeListener = DesktopTaskChangeListener(desktopUserRepositories) + + whenever(desktopUserRepositories.current).thenReturn(desktopRepository) + whenever(desktopUserRepositories.getProfile(anyInt())).thenReturn(desktopRepository) } @Test fun onTaskOpening_fullscreenTask_notActiveDesktopTask_noop() { val task = createFullscreenTask().apply { isVisible = true } - whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(false) + whenever(desktopUserRepositories.current.isActiveTask(task.taskId)) + .thenReturn(false) desktopTaskChangeListener.onTaskOpening(task) - verify(desktopRepository, never()).addTask(task.displayId, task.taskId, task.isVisible) - verify(desktopRepository, never()).removeFreeformTask(task.displayId, task.taskId) + verify(desktopUserRepositories.current, never()) + .addTask(task.displayId, task.taskId, task.isVisible) + verify(desktopUserRepositories.current, 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) + whenever(desktopUserRepositories.current.isActiveTask(task.taskId)) + .thenReturn(true) desktopTaskChangeListener.onTaskOpening(task) - verify(desktopRepository).removeFreeformTask(task.displayId, task.taskId) + verify(desktopUserRepositories.current).removeFreeformTask(task.displayId, task.taskId) } @Test fun onTaskOpening_freeformTask_visibleDesktopTask_addsTaskToRepository() { val task = createFreeformTask().apply { isVisible = true } - whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(false) + whenever(desktopUserRepositories.current.isActiveTask(task.taskId)) + .thenReturn(false) desktopTaskChangeListener.onTaskOpening(task) - verify(desktopRepository).addTask(task.displayId, task.taskId, task.isVisible) + verify(desktopUserRepositories.current) + .addTask(task.displayId, task.taskId, task.isVisible) } @Test fun onTaskOpening_freeformTask_nonVisibleDesktopTask_addsTaskToRepository() { val task = createFreeformTask().apply { isVisible = false } - whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(true) + whenever(desktopUserRepositories.current.isActiveTask(task.taskId)) + .thenReturn(true) desktopTaskChangeListener.onTaskOpening(task) - verify(desktopRepository).addTask(task.displayId, task.taskId, task.isVisible) + verify(desktopUserRepositories.current) + .addTask(task.displayId, task.taskId, task.isVisible) } @Test fun onTaskChanging_freeformTaskOutsideDesktop_removesTaskFromRepo() { val task = createFullscreenTask().apply { isVisible = true } - whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(true) + whenever(desktopUserRepositories.current.isActiveTask(task.taskId)) + .thenReturn(true) desktopTaskChangeListener.onTaskChanging(task) - verify(desktopRepository).removeFreeformTask(task.displayId, task.taskId) + verify(desktopUserRepositories.current) + .removeFreeformTask(task.displayId, task.taskId) } @Test fun onTaskChanging_visibleTaskInDesktop_updatesTaskVisibility() { val task = createFreeformTask().apply { isVisible = true } - whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(true) + whenever(desktopUserRepositories.current.isActiveTask(task.taskId)) + .thenReturn(true) desktopTaskChangeListener.onTaskChanging(task) - verify(desktopRepository).updateTask(task.displayId, task.taskId, task.isVisible) + verify(desktopUserRepositories.current) + .updateTask(task.displayId, task.taskId, task.isVisible) } @Test fun onTaskChanging_nonVisibleTask_updatesTaskVisibility() { val task = createFreeformTask().apply { isVisible = false } - whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(true) + whenever(desktopUserRepositories.current.isActiveTask(task.taskId)) + .thenReturn(true) desktopTaskChangeListener.onTaskChanging(task) - verify(desktopRepository).updateTask(task.displayId, task.taskId, task.isVisible) + verify(desktopUserRepositories.current) + .updateTask(task.displayId, task.taskId, task.isVisible) } @Test fun onTaskMovingToFront_freeformTaskOutsideDesktop_removesTaskFromRepo() { val task = createFullscreenTask().apply { isVisible = true } - whenever(desktopRepository.isActiveTask(task.taskId)).thenReturn(true) + whenever(desktopUserRepositories.current.isActiveTask(task.taskId)) + .thenReturn(true) desktopTaskChangeListener.onTaskMovingToFront(task) - verify(desktopRepository).removeFreeformTask(task.displayId, task.taskId) + verify(desktopUserRepositories.current) + .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) + whenever(desktopUserRepositories.current.isActiveTask(task.taskId)) + .thenReturn(true) + whenever(desktopUserRepositories.current.isClosingTask(task.taskId)) + .thenReturn(false) desktopTaskChangeListener.onTaskClosing(task) - verify(desktopRepository).updateTask(task.displayId, task.taskId, isVisible = false) - verify(desktopRepository).minimizeTask(task.displayId, task.taskId) + verify(desktopUserRepositories.current) + .updateTask(task.displayId, task.taskId, isVisible = false) + verify(desktopUserRepositories.current) + .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) + whenever(desktopUserRepositories.current.isActiveTask(task.taskId)) + .thenReturn(true) + whenever(desktopUserRepositories.current.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) + verify(desktopUserRepositories.current, never()) + .minimizeTask(task.displayId, task.taskId) + verify(desktopUserRepositories.current) + .removeClosingTask(task.taskId) + verify(desktopUserRepositories.current) + .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) + whenever(desktopUserRepositories.current.isActiveTask(task.taskId)) + .thenReturn(true) + whenever(desktopUserRepositories.current.isClosingTask(task.taskId)) + .thenReturn(true) desktopTaskChangeListener.onTaskClosing(task) - verify(desktopRepository).removeClosingTask(task.taskId) - verify(desktopRepository).removeFreeformTask(task.displayId, task.taskId) + verify(desktopUserRepositories.current).removeClosingTask(task.taskId) + verify(desktopUserRepositories.current) + .removeFreeformTask(task.displayId, task.taskId) } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt index 547a7b48a67b..c10434aa6d6f 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt @@ -44,6 +44,7 @@ import android.os.Binder import android.os.Bundle import android.os.Handler import android.os.IBinder +import android.os.UserManager import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.SetFlagsRule @@ -234,9 +235,11 @@ class DesktopTasksControllerTest : ShellTestCase() { @Mock private lateinit var resources: Resources @Mock lateinit var desktopModeEnterExitTransitionListener: DesktopModeEntryExitTransitionListener + @Mock private lateinit var userManager: UserManager private lateinit var controller: DesktopTasksController private lateinit var shellInit: ShellInit private lateinit var taskRepository: DesktopRepository + private lateinit var userRepositories: DesktopUserRepositories private lateinit var desktopTasksLimiter: DesktopTasksLimiter private lateinit var recentsTransitionStateListener: RecentsTransitionStateListener private lateinit var testScope: CoroutineScope @@ -268,12 +271,18 @@ class DesktopTasksControllerTest : ShellTestCase() { testScope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob()) shellInit = spy(ShellInit(testExecutor)) - taskRepository = - DesktopRepository(context, shellInit, persistentRepository, repositoryInitializer, testScope) + userRepositories = + DesktopUserRepositories( + context, + shellInit, + persistentRepository, + repositoryInitializer, + testScope, + userManager) desktopTasksLimiter = DesktopTasksLimiter( transitions, - taskRepository, + userRepositories, shellTaskOrganizer, MAX_TASK_LIMIT, mockInteractionJankMonitor, @@ -316,6 +325,8 @@ class DesktopTasksControllerTest : ShellTestCase() { controller.taskbarDesktopTaskListener = taskbarDesktopTaskListener assumeTrue(ENABLE_SHELL_TRANSITIONS) + + taskRepository = userRepositories.current } private fun createController(): DesktopTasksController { @@ -339,7 +350,7 @@ class DesktopTasksControllerTest : ShellTestCase() { toggleResizeDesktopTaskTransitionHandler, dragToDesktopTransitionHandler, mMockDesktopImmersiveController, - taskRepository, + userRepositories, recentsTransitionHandler, multiInstanceHelper, shellExecutor, diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt index 797b12505ef2..0712d58166bb 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt @@ -20,6 +20,7 @@ import android.app.ActivityManager.RunningTaskInfo import android.graphics.Rect import android.os.Binder import android.os.Handler +import android.os.UserManager import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.SetFlagsRule @@ -73,7 +74,6 @@ import org.mockito.kotlin.eq import org.mockito.kotlin.verify import org.mockito.quality.Strictness - /** * Test class for {@link DesktopTasksLimiter} * @@ -95,9 +95,11 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Mock lateinit var testExecutor: ShellExecutor @Mock lateinit var persistentRepository: DesktopPersistentRepository @Mock lateinit var repositoryInitializer: DesktopRepositoryInitializer + @Mock lateinit var userManager: UserManager private lateinit var mockitoSession: StaticMockitoSession private lateinit var desktopTasksLimiter: DesktopTasksLimiter + private lateinit var userRepositories: DesktopUserRepositories private lateinit var desktopTaskRepo: DesktopRepository private lateinit var shellInit: ShellInit private lateinit var testScope: CoroutineScope @@ -111,16 +113,18 @@ class DesktopTasksLimiterTest : ShellTestCase() { Dispatchers.setMain(StandardTestDispatcher()) testScope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob()) - desktopTaskRepo = - DesktopRepository( + userRepositories = + DesktopUserRepositories( context, shellInit, persistentRepository, repositoryInitializer, - testScope + testScope, + userManager ) + desktopTaskRepo = userRepositories.current desktopTasksLimiter = - DesktopTasksLimiter(transitions, desktopTaskRepo, shellTaskOrganizer, MAX_TASK_LIMIT, + DesktopTasksLimiter(transitions, userRepositories, shellTaskOrganizer, MAX_TASK_LIMIT, interactionJankMonitor, mContext, handler) } @@ -133,7 +137,7 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Test fun createDesktopTasksLimiter_withZeroLimit_shouldThrow() { assertFailsWith<IllegalArgumentException> { - DesktopTasksLimiter(transitions, desktopTaskRepo, shellTaskOrganizer, 0, + DesktopTasksLimiter(transitions, userRepositories, shellTaskOrganizer, 0, interactionJankMonitor, mContext, handler) } } @@ -141,7 +145,7 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Test fun createDesktopTasksLimiter_withNegativeLimit_shouldThrow() { assertFailsWith<IllegalArgumentException> { - DesktopTasksLimiter(transitions, desktopTaskRepo, shellTaskOrganizer, -5, + DesktopTasksLimiter(transitions, userRepositories, shellTaskOrganizer, -5, interactionJankMonitor, mContext, handler) } } @@ -411,7 +415,7 @@ class DesktopTasksLimiterTest : ShellTestCase() { @Test fun getTaskToMinimize_tasksAboveLimit_otherLimit_returnsBackTask() { desktopTasksLimiter = - DesktopTasksLimiter(transitions, desktopTaskRepo, shellTaskOrganizer, MAX_TASK_LIMIT2, + DesktopTasksLimiter(transitions, userRepositories, shellTaskOrganizer, MAX_TASK_LIMIT2, interactionJankMonitor, mContext, handler) val tasks = (1..MAX_TASK_LIMIT2 + 1).map { setUpFreeformTask() } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt index 7f1c1db3207a..238483da537c 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt @@ -50,6 +50,7 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.mockito.ArgumentCaptor +import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.eq import org.mockito.ArgumentMatchers.isA import org.mockito.Mockito @@ -75,6 +76,7 @@ class DesktopTasksTransitionObserverTest { private val transitions = mock<Transitions>() private val context = mock<Context>() private val shellTaskOrganizer = mock<ShellTaskOrganizer>() + private val userRepositories = mock<DesktopUserRepositories>() private val taskRepository = mock<DesktopRepository>() private val mixedHandler = mock<DesktopMixedTransitionHandler>() @@ -86,9 +88,12 @@ class DesktopTasksTransitionObserverTest { whenever(DesktopModeStatus.canEnterDesktopMode(any())).thenReturn(true) shellInit = spy(ShellInit(testExecutor)) + whenever(userRepositories.current).thenReturn(taskRepository) + whenever(userRepositories.getProfile(anyInt())).thenReturn(taskRepository) + transitionObserver = DesktopTasksTransitionObserver( - context, taskRepository, transitions, shellTaskOrganizer, mixedHandler, shellInit + context, userRepositories, transitions, shellTaskOrganizer, mixedHandler, shellInit ) } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandlerTest.kt index 226e974d2875..b9d7bbf567b7 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandlerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/compatui/SystemModalsTransitionHandlerTest.kt @@ -25,10 +25,11 @@ import android.view.WindowManager.TRANSIT_OPEN import androidx.test.filters.SmallTest import com.android.wm.shell.ShellTestCase import com.android.wm.shell.common.ShellExecutor -import com.android.wm.shell.desktopmode.DesktopRepository import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFullscreenTask import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFullscreenTaskBuilder import com.android.wm.shell.desktopmode.DesktopTestHelpers.createSystemModalTask +import com.android.wm.shell.desktopmode.DesktopRepository +import com.android.wm.shell.desktopmode.DesktopUserRepositories import com.android.wm.shell.sysui.ShellInit import com.android.wm.shell.transition.TransitionInfoBuilder import com.android.wm.shell.transition.Transitions @@ -49,6 +50,7 @@ class SystemModalsTransitionHandlerTest : ShellTestCase() { private val animExecutor = mock<ShellExecutor>() private val shellInit = mock<ShellInit>() private val transitions = mock<Transitions>() + private val desktopUserRepositories = mock<DesktopUserRepositories>() private val desktopRepository = mock<DesktopRepository>() private val startT = mock<SurfaceControl.Transaction>() private val finishT = mock<SurfaceControl.Transaction>() @@ -58,6 +60,7 @@ class SystemModalsTransitionHandlerTest : ShellTestCase() { @Before fun setUp() { // Simulate having one Desktop task so that we see Desktop Mode as active + whenever(desktopUserRepositories.current).thenReturn(desktopRepository) whenever(desktopRepository.getVisibleTaskCount(anyInt())).thenReturn(1) transitionHandler = createTransitionHandler() } @@ -69,7 +72,7 @@ class SystemModalsTransitionHandlerTest : ShellTestCase() { animExecutor, shellInit, transitions, - desktopRepository, + desktopUserRepositories, ) @Test @@ -79,7 +82,7 @@ class SystemModalsTransitionHandlerTest : ShellTestCase() { @Test fun startAnimation_desktopNotActive_doesNotAnimate() { - whenever(desktopRepository.getVisibleTaskCount(anyInt())).thenReturn(1) + whenever(desktopUserRepositories.current.getVisibleTaskCount(anyInt())).thenReturn(1) val info = TransitionInfoBuilder(TRANSIT_OPEN) .addChange(TRANSIT_OPEN, createSystemModalTask()) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/persistence/DesktopPersistentRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/persistence/DesktopPersistentRepositoryTest.kt index 8495580f42a5..4f7e80cf8330 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/persistence/DesktopPersistentRepositoryTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/persistence/DesktopPersistentRepositoryTest.kt @@ -112,7 +112,8 @@ class DesktopPersistentRepositoryTest : ShellTestCase() { datastoreRepository.addOrUpdateDesktop( visibleTasks = visibleTasks, minimizedTasks = minimizedTasks, - freeformTasksInZOrder = freeformTasksInZOrder) + freeformTasksInZOrder = freeformTasksInZOrder, + userId = DEFAULT_USER_ID) val actualDesktop = datastoreRepository.readDesktop(DEFAULT_USER_ID, DEFAULT_DESKTOP_ID) assertThat(actualDesktop?.tasksByTaskIdMap).hasSize(2) @@ -135,7 +136,8 @@ class DesktopPersistentRepositoryTest : ShellTestCase() { datastoreRepository.addOrUpdateDesktop( visibleTasks = visibleTasks, minimizedTasks = minimizedTasks, - freeformTasksInZOrder = freeformTasksInZOrder) + freeformTasksInZOrder = freeformTasksInZOrder, + userId = DEFAULT_USER_ID) val actualDesktop = datastoreRepository.readDesktop(DEFAULT_USER_ID, DEFAULT_DESKTOP_ID) assertThat(actualDesktop?.tasksByTaskIdMap?.get(task.taskId)?.desktopTaskState) @@ -158,7 +160,8 @@ class DesktopPersistentRepositoryTest : ShellTestCase() { datastoreRepository.addOrUpdateDesktop( visibleTasks = visibleTasks, minimizedTasks = minimizedTasks, - freeformTasksInZOrder = freeformTasksInZOrder) + freeformTasksInZOrder = freeformTasksInZOrder, + userId = DEFAULT_USER_ID) val actualDesktop = datastoreRepository.readDesktop(DEFAULT_USER_ID, DEFAULT_DESKTOP_ID) assertThat(actualDesktop?.tasksByTaskIdMap).isEmpty() diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerTest.kt index 975342902814..1c88a290d677 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/persistence/DesktopRepositoryInitializerTest.kt @@ -16,14 +16,17 @@ package com.android.wm.shell.desktopmode.persistence +import android.os.UserManager import android.platform.test.annotations.EnableFlags +import android.platform.test.flag.junit.SetFlagsRule import android.testing.AndroidTestingRunner import android.view.Display.DEFAULT_DISPLAY import androidx.test.filters.SmallTest +import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_HSUM import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_PERSISTENCE import com.android.wm.shell.ShellTestCase import com.android.wm.shell.common.ShellExecutor -import com.android.wm.shell.desktopmode.DesktopRepository +import com.android.wm.shell.desktopmode.DesktopUserRepositories import com.android.wm.shell.sysui.ShellInit import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.CoroutineScope @@ -36,26 +39,30 @@ import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.setMain import org.junit.After import org.junit.Before +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith -import org.mockito.Mockito.inOrder import org.mockito.Mockito.spy -import org.mockito.kotlin.any import org.mockito.kotlin.mock -import org.mockito.kotlin.verify import org.mockito.kotlin.whenever + @SmallTest @RunWith(AndroidTestingRunner::class) @ExperimentalCoroutinesApi class DesktopRepositoryInitializerTest : ShellTestCase() { + @JvmField + @Rule + val setFlagsRule = SetFlagsRule() + private lateinit var repositoryInitializer: DesktopRepositoryInitializer private lateinit var shellInit: ShellInit private lateinit var datastoreScope: CoroutineScope - private lateinit var desktopRepository: DesktopRepository + private lateinit var desktopUserRepositories: DesktopUserRepositories private val persistentRepository = mock<DesktopPersistentRepository>() + private val userManager = mock<UserManager>() private val testExecutor = mock<ShellExecutor>() @Before @@ -65,55 +72,193 @@ class DesktopRepositoryInitializerTest : ShellTestCase() { datastoreScope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob()) repositoryInitializer = DesktopRepositoryInitializerImpl(context, persistentRepository, datastoreScope) - desktopRepository = - DesktopRepository( - context, shellInit, persistentRepository, repositoryInitializer, datastoreScope) + desktopUserRepositories = + DesktopUserRepositories( + context, shellInit, persistentRepository, repositoryInitializer, datastoreScope, + userManager + ) } @Test + @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_PERSISTENCE, FLAG_ENABLE_DESKTOP_WINDOWING_HSUM) + fun initWithPersistence_multipleUsers_addedCorrectly() = + runTest(StandardTestDispatcher()) { + whenever(persistentRepository.getUserDesktopRepositoryMap()).thenReturn( + mapOf( + USER_ID_1 to desktopRepositoryState1, + USER_ID_2 to desktopRepositoryState2 + ) + ) + whenever(persistentRepository.getDesktopRepositoryState(USER_ID_1)) + .thenReturn(desktopRepositoryState1) + whenever(persistentRepository.getDesktopRepositoryState(USER_ID_2)) + .thenReturn(desktopRepositoryState2) + whenever(persistentRepository.readDesktop(USER_ID_1, DESKTOP_ID_1)) + .thenReturn(desktop1) + whenever(persistentRepository.readDesktop(USER_ID_1, DESKTOP_ID_2)) + .thenReturn(desktop2) + whenever(persistentRepository.readDesktop(USER_ID_2, DESKTOP_ID_3)) + .thenReturn(desktop3) + + repositoryInitializer.initialize(desktopUserRepositories) + + // Desktop Repository currently returns all tasks across desktops for a specific user + // since the repository currently doesn't handle desktops. This test logic should be updated + // once the repository handles multiple desktops. + assertThat( + desktopUserRepositories.getProfile(USER_ID_1) + .getActiveTasks(DEFAULT_DISPLAY) + ) + .containsExactly(1, 3, 4, 5) + .inOrder() + assertThat( + desktopUserRepositories.getProfile(USER_ID_1) + .getExpandedTasksOrdered(DEFAULT_DISPLAY) + ) + .containsExactly(5, 1) + .inOrder() + assertThat( + desktopUserRepositories.getProfile(USER_ID_1) + .getMinimizedTasks(DEFAULT_DISPLAY) + ) + .containsExactly(3, 4) + .inOrder() + + assertThat( + desktopUserRepositories.getProfile(USER_ID_2) + .getActiveTasks(DEFAULT_DISPLAY) + ) + .containsExactly(7, 8) + .inOrder() + assertThat( + desktopUserRepositories.getProfile(USER_ID_2) + .getExpandedTasksOrdered(DEFAULT_DISPLAY) + ) + .contains(7) + assertThat( + desktopUserRepositories.getProfile(USER_ID_2) + .getMinimizedTasks(DEFAULT_DISPLAY) + ).containsExactly(8) + } + + @Test @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_PERSISTENCE) - fun initWithPersistence_multipleTasks_addedCorrectly() = + fun initWithPersistence_singleUser_addedCorrectly() = runTest(StandardTestDispatcher()) { - val freeformTasksInZOrder = listOf(1, 2, 3) - whenever(persistentRepository.readDesktop(any(), any())) - .thenReturn( - Desktop.newBuilder() - .setDesktopId(1) - .addAllZOrderedTasks(freeformTasksInZOrder) - .putTasksByTaskId( - 1, - DesktopTask.newBuilder() - .setTaskId(1) - .setDesktopTaskState(DesktopTaskState.VISIBLE) - .build()) - .putTasksByTaskId( - 2, - DesktopTask.newBuilder() - .setTaskId(2) - .setDesktopTaskState(DesktopTaskState.VISIBLE) - .build()) - .putTasksByTaskId( - 3, - DesktopTask.newBuilder() - .setTaskId(3) - .setDesktopTaskState(DesktopTaskState.MINIMIZED) - .build()) - .build()) - - repositoryInitializer.initialize(desktopRepository) - - verify(persistentRepository).readDesktop(any(), any()) - assertThat(desktopRepository.getActiveTasks(DEFAULT_DISPLAY)) - .containsExactly(1, 2, 3) + whenever(persistentRepository.getUserDesktopRepositoryMap()).thenReturn( + mapOf( + USER_ID_1 to desktopRepositoryState1, + ) + ) + whenever(persistentRepository.getDesktopRepositoryState(USER_ID_1)) + .thenReturn(desktopRepositoryState1) + whenever(persistentRepository.readDesktop(USER_ID_1, DESKTOP_ID_1)) + .thenReturn(desktop1) + whenever(persistentRepository.readDesktop(USER_ID_1, DESKTOP_ID_2)) + .thenReturn(desktop2) + + repositoryInitializer.initialize(desktopUserRepositories) + + // Desktop Repository currently returns all tasks across desktops for a specific user + // since the repository currently doesn't handle desktops. This test logic should be updated + // once the repository handles multiple desktops. + assertThat( + desktopUserRepositories.getProfile(USER_ID_1) + .getActiveTasks(DEFAULT_DISPLAY) + ) + .containsExactly(1, 3, 4, 5) + .inOrder() + assertThat( + desktopUserRepositories.getProfile(USER_ID_1) + .getExpandedTasksOrdered(DEFAULT_DISPLAY) + ) + .containsExactly(5, 1) .inOrder() - assertThat(desktopRepository.getExpandedTasksOrdered(DEFAULT_DISPLAY)) - .containsExactly(1, 2) + assertThat( + desktopUserRepositories.getProfile(USER_ID_1) + .getMinimizedTasks(DEFAULT_DISPLAY) + ) + .containsExactly(3, 4) .inOrder() - assertThat(desktopRepository.getMinimizedTasks(DEFAULT_DISPLAY)).containsExactly(3) } @After fun tearDown() { datastoreScope.cancel() } + + private companion object { + const val USER_ID_1 = 5 + const val USER_ID_2 = 6 + const val DESKTOP_ID_1 = 2 + const val DESKTOP_ID_2 = 3 + const val DESKTOP_ID_3 = 4 + + val freeformTasksInZOrder1 = listOf(1, 3) + val desktop1: Desktop = Desktop.newBuilder() + .setDesktopId(DESKTOP_ID_1) + .addAllZOrderedTasks(freeformTasksInZOrder1) + .putTasksByTaskId( + 1, + DesktopTask.newBuilder() + .setTaskId(1) + .setDesktopTaskState(DesktopTaskState.VISIBLE) + .build() + ) + .putTasksByTaskId( + 3, + DesktopTask.newBuilder() + .setTaskId(3) + .setDesktopTaskState(DesktopTaskState.MINIMIZED) + .build() + ) + .build() + + val freeformTasksInZOrder2 = listOf(4, 5) + val desktop2: Desktop = Desktop.newBuilder() + .setDesktopId(DESKTOP_ID_2) + .addAllZOrderedTasks(freeformTasksInZOrder2) + .putTasksByTaskId( + 4, + DesktopTask.newBuilder() + .setTaskId(4) + .setDesktopTaskState(DesktopTaskState.MINIMIZED) + .build() + ) + .putTasksByTaskId( + 5, + DesktopTask.newBuilder() + .setTaskId(5) + .setDesktopTaskState(DesktopTaskState.VISIBLE) + .build() + ) + .build() + + val freeformTasksInZOrder3 = listOf(7, 8) + val desktop3: Desktop = Desktop.newBuilder() + .setDesktopId(DESKTOP_ID_3) + .addAllZOrderedTasks(freeformTasksInZOrder3) + .putTasksByTaskId( + 7, + DesktopTask.newBuilder() + .setTaskId(7) + .setDesktopTaskState(DesktopTaskState.VISIBLE) + .build() + ) + .putTasksByTaskId( + 8, + DesktopTask.newBuilder() + .setTaskId(8) + .setDesktopTaskState(DesktopTaskState.MINIMIZED) + .build() + ) + .build() + val desktopRepositoryState1: DesktopRepositoryState = DesktopRepositoryState.newBuilder() + .putDesktop(DESKTOP_ID_1, desktop1) + .putDesktop(DESKTOP_ID_2, desktop2) + .build() + val desktopRepositoryState2: DesktopRepositoryState = DesktopRepositoryState.newBuilder() + .putDesktop(DESKTOP_ID_3, desktop3) + .build() + } } 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 b504a88e71fc..794ba48e2581 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 @@ -27,6 +27,7 @@ import static com.android.window.flags.Flags.FLAG_ENABLE_WINDOWING_TRANSITION_HA import static com.android.window.flags.Flags.FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -46,6 +47,7 @@ import com.android.wm.shell.ShellTestCase; import com.android.wm.shell.TestRunningTaskInfoBuilder; import com.android.wm.shell.common.LaunchAdjacentController; import com.android.wm.shell.desktopmode.DesktopRepository; +import com.android.wm.shell.desktopmode.DesktopUserRepositories; import com.android.wm.shell.desktopmode.DesktopTasksController; import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; import com.android.wm.shell.sysui.ShellInit; @@ -81,6 +83,8 @@ public final class FreeformTaskListenerTests extends ShellTestCase { @Mock private SurfaceControl mMockSurfaceControl; @Mock + private DesktopUserRepositories mDesktopUserRepositories; + @Mock private DesktopRepository mDesktopRepository; @Mock private DesktopTasksController mDesktopTasksController; @@ -101,13 +105,14 @@ public final class FreeformTaskListenerTests extends ShellTestCase { .mockStatic(DesktopModeStatus.class) .startMocking(); doReturn(true).when(() -> DesktopModeStatus.canEnterDesktopMode(any())); - + when(mDesktopUserRepositories.getCurrent()).thenReturn(mDesktopRepository); + when(mDesktopUserRepositories.getProfile(anyInt())).thenReturn(mDesktopRepository); mFreeformTaskListener = new FreeformTaskListener( mContext, mShellInit, mTaskOrganizer, - Optional.of(mDesktopRepository), + Optional.of(mDesktopUserRepositories), Optional.of(mDesktopTasksController), mLaunchAdjacentController, mWindowDecorViewModel, @@ -123,7 +128,8 @@ public final class FreeformTaskListenerTests extends ShellTestCase { mFreeformTaskListener.onTaskAppeared(task, mMockSurfaceControl); - verify(mDesktopRepository).addTask(task.displayId, task.taskId, task.isVisible = true); + verify(mDesktopUserRepositories.getCurrent()) + .addTask(task.displayId, task.taskId, task.isVisible = true); } @Test @@ -135,7 +141,8 @@ public final class FreeformTaskListenerTests extends ShellTestCase { mFreeformTaskListener.onTaskAppeared(task, mMockSurfaceControl); - verify(mDesktopRepository).addTask(task.displayId, task.taskId, task.isVisible); + verify(mDesktopUserRepositories.getCurrent()) + .addTask(task.displayId, task.taskId, task.isVisible); } @Test @@ -147,7 +154,8 @@ public final class FreeformTaskListenerTests extends ShellTestCase { mFreeformTaskListener.onTaskAppeared(task, mMockSurfaceControl); - verify(mDesktopRepository, never()).addTask(task.displayId, task.taskId, task.isVisible); + verify(mDesktopUserRepositories.getCurrent(), never()) + .addTask(task.displayId, task.taskId, task.isVisible); } @Test @@ -158,7 +166,8 @@ public final class FreeformTaskListenerTests extends ShellTestCase { mFreeformTaskListener.onFocusTaskChanged(task); - verify(mDesktopRepository).addTask(task.displayId, task.taskId, task.isVisible); + verify(mDesktopUserRepositories.getCurrent()) + .addTask(task.displayId, task.taskId, task.isVisible); } @Test @@ -171,7 +180,7 @@ public final class FreeformTaskListenerTests extends ShellTestCase { mFreeformTaskListener.onFocusTaskChanged(fullscreenTask); - verify(mDesktopRepository, never()) + verify(mDesktopUserRepositories.getCurrent(), never()) .addTask(fullscreenTask.displayId, fullscreenTask.taskId, fullscreenTask.isVisible); } @@ -214,7 +223,7 @@ public final class FreeformTaskListenerTests extends ShellTestCase { task.displayId = INVALID_DISPLAY; mFreeformTaskListener.onTaskVanished(task); - verify(mDesktopRepository).minimizeTask(task.displayId, task.taskId); + verify(mDesktopUserRepositories.getCurrent()).minimizeTask(task.displayId, task.taskId); } @Test @@ -227,14 +236,17 @@ public final class FreeformTaskListenerTests extends ShellTestCase { mFreeformTaskListener.onTaskAppeared(task, mMockSurfaceControl); - when(mDesktopRepository.isClosingTask(task.taskId)).thenReturn(true); + when(mDesktopUserRepositories.getCurrent() + .isClosingTask(task.taskId)).thenReturn(true); task.isVisible = false; task.displayId = INVALID_DISPLAY; mFreeformTaskListener.onTaskVanished(task); - verify(mDesktopRepository, never()).minimizeTask(task.displayId, task.taskId); - verify(mDesktopRepository).removeClosingTask(task.taskId); - verify(mDesktopRepository).removeFreeformTask(task.displayId, task.taskId); + verify(mDesktopUserRepositories.getCurrent(), never()) + .minimizeTask(task.displayId, task.taskId); + verify(mDesktopUserRepositories.getCurrent()).removeClosingTask(task.taskId); + verify(mDesktopUserRepositories.getCurrent()) + .removeFreeformTask(task.displayId, task.taskId); } @Test @@ -246,9 +258,12 @@ public final class FreeformTaskListenerTests extends ShellTestCase { 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); + verify(mDesktopUserRepositories.getCurrent(), never()) + .minimizeTask(task.displayId, task.taskId); + verify(mDesktopUserRepositories.getCurrent(), never()) + .removeClosingTask(task.taskId); + verify(mDesktopUserRepositories.getCurrent(), never()) + .removeFreeformTask(task.displayId, task.taskId); } @Test @@ -274,7 +289,8 @@ public final class FreeformTaskListenerTests extends ShellTestCase { mFreeformTaskListener.onTaskInfoChanged(task); verify(mTaskChangeListener, never()).onTaskChanging(any()); - verify(mDesktopRepository).updateTask(task.displayId, task.taskId, task.isVisible); + verify(mDesktopUserRepositories.getCurrent()) + .updateTask(task.displayId, task.taskId, task.isVisible); } @Test @@ -289,7 +305,7 @@ public final class FreeformTaskListenerTests extends ShellTestCase { mFreeformTaskListener.onTaskInfoChanged(task); verify(mTaskChangeListener).onNonTransitionTaskChanging(any()); - verify(mDesktopRepository, never()) + verify(mDesktopUserRepositories.getCurrent(), never()) .updateTask(task.displayId, task.taskId, task.isVisible); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java index 289fd2d838fd..2eb2c3b8e2f7 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java @@ -65,7 +65,7 @@ import com.android.wm.shell.common.pip.PipKeepClearAlgorithmInterface; import com.android.wm.shell.common.pip.PipSnapAlgorithm; import com.android.wm.shell.common.pip.PipUiEventLogger; import com.android.wm.shell.common.pip.SizeSpecSource; -import com.android.wm.shell.desktopmode.DesktopRepository; +import com.android.wm.shell.desktopmode.DesktopUserRepositories; import com.android.wm.shell.pip.phone.PhonePipMenuController; import com.android.wm.shell.splitscreen.SplitScreenController; @@ -103,7 +103,7 @@ public class PipTaskOrganizerTest extends ShellTestCase { @Mock private PipSurfaceTransactionHelper mMockPipSurfaceTransactionHelper; @Mock private PipUiEventLogger mMockPipUiEventLogger; @Mock private Optional<SplitScreenController> mMockOptionalSplitScreen; - @Mock private Optional<DesktopRepository> mMockOptionalDesktopRepository; + @Mock private Optional<DesktopUserRepositories> mMockOptionalDesktopUserRepositories; @Mock private RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer; @Mock private ShellTaskOrganizer mMockShellTaskOrganizer; @Mock private PipParamsChangedForwarder mMockPipParamsChangedForwarder; @@ -136,7 +136,7 @@ public class PipTaskOrganizerTest extends ShellTestCase { mMockPipSurfaceTransactionHelper, mMockPipTransitionController, mMockPipParamsChangedForwarder, mMockOptionalSplitScreen, Optional.empty() /* pipPerfHintControllerOptional */, - mMockOptionalDesktopRepository, mRootTaskDisplayAreaOrganizer, + mMockOptionalDesktopUserRepositories, mRootTaskDisplayAreaOrganizer, mMockDisplayController, mMockPipUiEventLogger, mMockShellTaskOrganizer, mMainExecutor); mMainExecutor.flushAll(); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java index 57b6d7f0ac2f..3fe8c109807a 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java @@ -45,7 +45,7 @@ import androidx.test.filters.SmallTest; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.pip.PipBoundsState; -import com.android.wm.shell.desktopmode.DesktopRepository; +import com.android.wm.shell.desktopmode.DesktopUserRepositories; import com.android.wm.shell.pip.PipTransitionController; import com.android.wm.shell.pip2.PipSurfaceTransactionHelper; import com.android.wm.shell.pip2.animation.PipAlphaAnimator; @@ -83,7 +83,7 @@ public class PipSchedulerTest { @Mock private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory mMockFactory; @Mock private SurfaceControl.Transaction mMockTransaction; @Mock private PipAlphaAnimator mMockAlphaAnimator; - @Mock private Optional<DesktopRepository> mMockOptionalDesktopRepository; + @Mock private Optional<DesktopUserRepositories> mMockOptionalDesktopUserRepositories; @Mock private RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer; @Captor private ArgumentCaptor<Runnable> mRunnableArgumentCaptor; @@ -102,7 +102,7 @@ public class PipSchedulerTest { .thenReturn(mMockTransaction); mPipScheduler = new PipScheduler(mMockContext, mMockPipBoundsState, mMockMainExecutor, - mMockPipTransitionState, mMockOptionalDesktopRepository, + mMockPipTransitionState, mMockOptionalDesktopUserRepositories, mRootTaskDisplayAreaOrganizer); mPipScheduler.setPipTransitionController(mMockPipTransitionController); mPipScheduler.setSurfaceControlTransactionFactory(mMockFactory); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java index 68c8aab8849d..95f371f7000a 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java @@ -26,6 +26,8 @@ import static com.android.launcher3.Flags.FLAG_ENABLE_REFACTOR_TASK_THUMBNAIL; import static com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_PERSISTENCE; import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_50_50; +import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -57,6 +59,7 @@ import android.content.pm.PackageManager; import android.graphics.Point; import android.graphics.Rect; import android.os.Bundle; +import android.os.UserManager; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.SetFlagsRule; @@ -74,6 +77,7 @@ import com.android.wm.shell.TestShellExecutor; import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.TaskStackListenerImpl; import com.android.wm.shell.desktopmode.DesktopRepository; +import com.android.wm.shell.desktopmode.DesktopUserRepositories; import com.android.wm.shell.desktopmode.DesktopWallpaperActivity; import com.android.wm.shell.shared.GroupedTaskInfo; import com.android.wm.shell.shared.ShellSharedConstants; @@ -113,8 +117,6 @@ public class RecentTasksControllerTest extends ShellTestCase { @Mock private ShellCommandHandler mShellCommandHandler; @Mock - private DesktopRepository mDesktopRepository; - @Mock private ActivityTaskManager mActivityTaskManager; @Mock private DisplayInsetsController mDisplayInsetsController; @@ -122,6 +124,10 @@ public class RecentTasksControllerTest extends ShellTestCase { private IRecentTasksListener mRecentTasksListener; @Mock private TaskStackTransitionObserver mTaskStackTransitionObserver; + @Mock + private DesktopUserRepositories mDesktopUserRepositories; + @Mock + private DesktopRepository mDesktopRepository; @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); @@ -142,6 +148,8 @@ public class RecentTasksControllerTest extends ShellTestCase { .when(() -> DesktopModeStatus.canEnterDesktopMode(any())); mMainExecutor = new TestShellExecutor(); + when(mDesktopUserRepositories.getCurrent()).thenReturn(mDesktopRepository); + when(mDesktopUserRepositories.getProfile(anyInt())).thenReturn(mDesktopRepository); when(mContext.getPackageManager()).thenReturn(mock(PackageManager.class)); when(mContext.getSystemService(KeyguardManager.class)) .thenReturn(mock(KeyguardManager.class)); @@ -150,7 +158,7 @@ public class RecentTasksControllerTest extends ShellTestCase { mDisplayInsetsController, mMainExecutor)); mRecentTasksControllerReal = new RecentTasksController(mContext, mShellInit, mShellController, mShellCommandHandler, mTaskStackListener, mActivityTaskManager, - Optional.of(mDesktopRepository), mTaskStackTransitionObserver, + Optional.of(mDesktopUserRepositories), mTaskStackTransitionObserver, mMainExecutor); mRecentTasksController = spy(mRecentTasksControllerReal); mShellTaskOrganizer = new ShellTaskOrganizer(mShellInit, mShellCommandHandler, @@ -182,6 +190,12 @@ public class RecentTasksControllerTest extends ShellTestCase { } @Test + public void instantiateController_initializesRepository() { + verify(mDesktopUserRepositories, times(1)).getCurrent(); + verify(mDesktopRepository, times(1)).addActiveTaskListener(any()); + } + + @Test public void testInvalidateExternalInterface_unregistersListener() { // Note: We have to use the real instance of the controller here since that is the instance // that is passed to ShellController internally, and the instance that the listener will be @@ -323,8 +337,8 @@ public class RecentTasksControllerTest extends ShellTestCase { RecentTaskInfo t4 = makeTaskInfo(4); setRawList(t1, t2, t3, t4); - when(mDesktopRepository.isActiveTask(1)).thenReturn(true); - when(mDesktopRepository.isActiveTask(3)).thenReturn(true); + when(mDesktopUserRepositories.getCurrent().isActiveTask(1)).thenReturn(true); + when(mDesktopUserRepositories.getCurrent().isActiveTask(3)).thenReturn(true); ArrayList<GroupedTaskInfo> recentTasks = mRecentTasksController.getRecentTasks(MAX_VALUE, RECENT_IGNORE_UNAVAILABLE, 0); @@ -362,8 +376,8 @@ public class RecentTasksControllerTest extends ShellTestCase { new SplitBounds(new Rect(), new Rect(), 1, 2, SNAP_TO_2_50_50); mRecentTasksController.addSplitPair(t1.taskId, t2.taskId, pair1Bounds); - when(mDesktopRepository.isActiveTask(3)).thenReturn(true); - when(mDesktopRepository.isActiveTask(5)).thenReturn(true); + when(mDesktopUserRepositories.getCurrent().isActiveTask(3)).thenReturn(true); + when(mDesktopUserRepositories.getCurrent().isActiveTask(5)).thenReturn(true); ArrayList<GroupedTaskInfo> recentTasks = mRecentTasksController.getRecentTasks(MAX_VALUE, RECENT_IGNORE_UNAVAILABLE, 0); @@ -402,8 +416,8 @@ public class RecentTasksControllerTest extends ShellTestCase { RecentTaskInfo t4 = makeTaskInfo(4); setRawList(t1, t2, t3, t4); - when(mDesktopRepository.isActiveTask(1)).thenReturn(true); - when(mDesktopRepository.isActiveTask(3)).thenReturn(true); + when(mDesktopUserRepositories.getCurrent().isActiveTask(1)).thenReturn(true); + when(mDesktopUserRepositories.getCurrent().isActiveTask(3)).thenReturn(true); ArrayList<GroupedTaskInfo> recentTasks = mRecentTasksController.getRecentTasks(MAX_VALUE, RECENT_IGNORE_UNAVAILABLE, 0); @@ -431,7 +445,9 @@ public class RecentTasksControllerTest extends ShellTestCase { setRawList(t1, t2, t3, t4, t5); when(mDesktopRepository.isActiveTask(1)).thenReturn(true); + when(mDesktopRepository.isActiveTask(2)).thenReturn(false); when(mDesktopRepository.isActiveTask(3)).thenReturn(true); + when(mDesktopRepository.isActiveTask(4)).thenReturn(false); when(mDesktopRepository.isActiveTask(5)).thenReturn(true); when(mDesktopRepository.isMinimizedTask(3)).thenReturn(true); @@ -470,8 +486,8 @@ public class RecentTasksControllerTest extends ShellTestCase { t2.lastNonFullscreenBounds = new Rect(150, 250, 350, 450); setRawList(t1, t2); - when(mDesktopRepository.isActiveTask(1)).thenReturn(true); - when(mDesktopRepository.isActiveTask(2)).thenReturn(true); + when(mDesktopUserRepositories.getCurrent().isActiveTask(1)).thenReturn(true); + when(mDesktopUserRepositories.getCurrent().isActiveTask(2)).thenReturn(true); ArrayList<GroupedTaskInfo> recentTasks = mRecentTasksController.getRecentTasks(MAX_VALUE, RECENT_IGNORE_UNAVAILABLE, 0); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentsTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentsTransitionHandlerTest.java index f0f5fe159069..894d238b7e15 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentsTransitionHandlerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentsTransitionHandlerTest.java @@ -65,6 +65,7 @@ import com.android.wm.shell.TestShellExecutor; import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.TaskStackListenerImpl; import com.android.wm.shell.desktopmode.DesktopRepository; +import com.android.wm.shell.desktopmode.DesktopUserRepositories; import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellController; @@ -100,7 +101,7 @@ public class RecentsTransitionHandlerTest extends ShellTestCase { @Mock private ShellCommandHandler mShellCommandHandler; @Mock - private DesktopRepository mDesktopRepository; + private DesktopUserRepositories mDesktopUserRepositories; @Mock private ActivityTaskManager mActivityTaskManager; @Mock @@ -112,6 +113,8 @@ public class RecentsTransitionHandlerTest extends ShellTestCase { @Mock private Transitions mTransitions; + @Mock private DesktopRepository mDesktopRepository; + @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); @@ -131,6 +134,7 @@ public class RecentsTransitionHandlerTest extends ShellTestCase { ExtendedMockito.doReturn(true) .when(() -> DesktopModeStatus.canEnterDesktopMode(any())); + when(mDesktopUserRepositories.getCurrent()).thenReturn(mDesktopRepository); mMainExecutor = new TestShellExecutor(); when(mContext.getPackageManager()).thenReturn(mock(PackageManager.class)); when(mContext.getSystemService(KeyguardManager.class)) @@ -140,7 +144,7 @@ public class RecentsTransitionHandlerTest extends ShellTestCase { mDisplayInsetsController, mMainExecutor)); mRecentTasksControllerReal = new RecentTasksController(mContext, mShellInit, mShellController, mShellCommandHandler, mTaskStackListener, mActivityTaskManager, - Optional.of(mDesktopRepository), mTaskStackTransitionObserver, + Optional.of(mDesktopUserRepositories), mTaskStackTransitionObserver, mMainExecutor); mRecentTasksController = spy(mRecentTasksControllerReal); mShellTaskOrganizer = new ShellTaskOrganizer(mShellInit, mShellCommandHandler, diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenuTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenuTest.kt index 1215c52209a5..44035588887f 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenuTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopHeaderManageWindowsMenuTest.kt @@ -29,12 +29,13 @@ import com.android.wm.shell.MockToken import com.android.wm.shell.ShellTestCase import com.android.wm.shell.TestRunningTaskInfoBuilder import com.android.wm.shell.TestShellExecutor -import com.android.wm.shell.desktopmode.DesktopRepository +import com.android.wm.shell.desktopmode.DesktopUserRepositories import com.android.wm.shell.sysui.ShellInit import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer import com.google.common.truth.Truth.assertThat import org.junit.After import org.junit.Before +import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -55,17 +56,18 @@ class DesktopHeaderManageWindowsMenuTest : ShellTestCase() { @Rule val setFlagsRule: SetFlagsRule = SetFlagsRule() - private lateinit var desktopRepository: DesktopRepository + private lateinit var userRepositories: DesktopUserRepositories private lateinit var menu: DesktopHeaderManageWindowsMenu @Before fun setUp() { - desktopRepository = DesktopRepository( + userRepositories = DesktopUserRepositories( context = context, shellInit = ShellInit(TestShellExecutor()), persistentRepository = mock(), repositoryInitializer = mock(), - mainCoroutineScope = mock() + mainCoroutineScope = mock(), + userManager = mock(), ) } @@ -75,15 +77,15 @@ class DesktopHeaderManageWindowsMenuTest : ShellTestCase() { } @Test + @Ignore("Test is failing internally") @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP) fun testShow_forImmersiveTask_usesSystemViewContainer() { val task = createFreeformTask() - desktopRepository.setTaskInFullImmersiveState( + userRepositories.getProfile(DEFAULT_USER_ID).setTaskInFullImmersiveState( displayId = task.displayId, taskId = task.taskId, immersive = true ) - menu = createMenu(task) assertThat(menu.menuViewContainer).isInstanceOf(AdditionalSystemViewContainer::class.java) @@ -96,7 +98,7 @@ class DesktopHeaderManageWindowsMenuTest : ShellTestCase() { displayController = mock(), rootTdaOrganizer = mock(), context = context, - desktopRepository = desktopRepository, + desktopUserRepositories = userRepositories, surfaceControlBuilderSupplier = { SurfaceControl.Builder() }, surfaceControlTransactionSupplier = { SurfaceControl.Transaction() }, snapshotList = emptyList(), @@ -109,4 +111,8 @@ class DesktopHeaderManageWindowsMenuTest : ShellTestCase() { .setActivityType(ACTIVITY_TYPE_STANDARD) .setWindowingMode(WINDOWING_MODE_FREEFORM) .build() + + private companion object { + const val DEFAULT_USER_ID = 10 + } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt index 080f496593cf..afd46078074c 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt @@ -60,6 +60,7 @@ import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger import com.android.wm.shell.desktopmode.DesktopRepository import com.android.wm.shell.desktopmode.DesktopTasksController import com.android.wm.shell.desktopmode.DesktopTasksLimiter +import com.android.wm.shell.desktopmode.DesktopUserRepositories import com.android.wm.shell.desktopmode.WindowDecorCaptionHandleRepository import com.android.wm.shell.desktopmode.education.AppHandleEducationController import com.android.wm.shell.desktopmode.education.AppToWebEducationController @@ -108,7 +109,7 @@ open class DesktopModeWindowDecorViewModelTestsBase : ShellTestCase() { protected val mockTaskOrganizer = mock<ShellTaskOrganizer>() protected val mockDisplayController = mock<DisplayController>() protected val mockSplitScreenController = mock<SplitScreenController>() - protected val mockDesktopRepository = mock<DesktopRepository>() + protected val mockDesktopUserRepositories = mock<DesktopUserRepositories>() protected val mockDisplayLayout = mock<DisplayLayout>() protected val displayInsetsController = mock<DisplayInsetsController>() protected val mockSyncQueue = mock<SyncTransactionQueue>() @@ -142,6 +143,7 @@ open class DesktopModeWindowDecorViewModelTestsBase : ShellTestCase() { protected val mockAppToWebEducationController = mock<AppToWebEducationController>() protected val mockFocusTransitionObserver = mock<FocusTransitionObserver>() protected val mockCaptionHandleRepository = mock<WindowDecorCaptionHandleRepository>() + protected val mockDesktopRepository: DesktopRepository = mock<DesktopRepository>() protected val motionEvent = mock<MotionEvent>() val displayController = mock<DisplayController>() val displayLayout = mock<DisplayLayout>() @@ -168,6 +170,9 @@ open class DesktopModeWindowDecorViewModelTestsBase : ShellTestCase() { windowDecorByTaskIdSpy.clear() spyContext.addMockSystemService(InputManager::class.java, mockInputManager) desktopModeEventLogger = mock<DesktopModeEventLogger>() + whenever(mockDesktopUserRepositories.current).thenReturn(mockDesktopRepository) + whenever(mockDesktopUserRepositories.getProfile(anyInt())) + .thenReturn(mockDesktopRepository) desktopModeWindowDecorViewModel = DesktopModeWindowDecorViewModel( spyContext, testShellExecutor, @@ -178,7 +183,7 @@ open class DesktopModeWindowDecorViewModelTestsBase : ShellTestCase() { mockShellCommandHandler, mockWindowManager, mockTaskOrganizer, - mockDesktopRepository, + mockDesktopUserRepositories, mockDisplayController, mockShellController, displayInsetsController, diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java index 03c7c9857d8f..a389bea03141 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java @@ -109,6 +109,7 @@ import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.desktopmode.CaptionState; import com.android.wm.shell.desktopmode.DesktopModeEventLogger; import com.android.wm.shell.desktopmode.DesktopRepository; +import com.android.wm.shell.desktopmode.DesktopUserRepositories; import com.android.wm.shell.desktopmode.WindowDecorCaptionHandleRepository; import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; import com.android.wm.shell.splitscreen.SplitScreenController; @@ -165,7 +166,7 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { @Mock private ShellTaskOrganizer mMockShellTaskOrganizer; @Mock - private DesktopRepository mMockDesktopRepository; + private DesktopUserRepositories mMockDesktopUserRepositories; @Mock private Choreographer mMockChoreographer; @Mock @@ -214,6 +215,8 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { private WindowDecorCaptionHandleRepository mMockCaptionHandleRepository; @Mock private DesktopModeEventLogger mDesktopModeEventLogger; + @Mock + private DesktopRepository mDesktopRepository; @Captor private ArgumentCaptor<Function1<Boolean, Unit>> mOnMaxMenuHoverChangeListener; @Captor @@ -270,6 +273,8 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { when(mMockMultiInstanceHelper.supportsMultiInstanceSplit(any())).thenReturn(false); when(mMockAppHeaderViewHolderFactory.create(any(), any(), any(), any(), any(), any(), any(), any())).thenReturn(mMockAppHeaderViewHolder); + when(mMockDesktopUserRepositories.getCurrent()).thenReturn(mDesktopRepository); + when(mMockDesktopUserRepositories.getProfile(anyInt())).thenReturn(mDesktopRepository); } @After @@ -1469,8 +1474,8 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); final DesktopModeWindowDecoration decoration = createWindowDecoration(taskInfo, true /* relayout */); - when(mMockDesktopRepository.isTaskInFullImmersiveState(taskInfo.taskId)) - .thenReturn(true); + when(mMockDesktopUserRepositories.getCurrent() + .isTaskInFullImmersiveState(taskInfo.taskId)).thenReturn(true); createHandleMenu(decoration); @@ -1705,8 +1710,8 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { boolean relayout) { final DesktopModeWindowDecoration windowDecor = new DesktopModeWindowDecoration(mContext, mContext, mMockDisplayController, mMockSplitScreenController, - mMockDesktopRepository, mMockShellTaskOrganizer, taskInfo, mMockSurfaceControl, - mMockHandler, mBgExecutor, mMockChoreographer, mMockSyncQueue, + mMockDesktopUserRepositories, mMockShellTaskOrganizer, taskInfo, + mMockSurfaceControl, mMockHandler, mBgExecutor, mMockChoreographer, mMockSyncQueue, mMockAppHeaderViewHolderFactory, mMockRootTaskDisplayAreaOrganizer, mMockGenericLinksParser, mMockAssistContentRequester, SurfaceControl.Builder::new, mMockTransactionSupplier, WindowContainerTransaction::new, SurfaceControl::new, diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModelTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModelTest.kt index d29002199f9d..193c2c25d26d 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModelTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDecorViewModelTest.kt @@ -25,7 +25,7 @@ import com.android.wm.shell.ShellTestCase import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.SyncTransactionQueue import com.android.wm.shell.desktopmode.DesktopModeEventLogger -import com.android.wm.shell.desktopmode.DesktopRepository +import com.android.wm.shell.desktopmode.DesktopUserRepositories import com.android.wm.shell.desktopmode.DesktopTasksController import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask import com.android.wm.shell.desktopmode.ReturnToDragStartAnimator @@ -52,7 +52,7 @@ class DesktopTilingDecorViewModelTest : ShellTestCase() { private val syncQueueMock: SyncTransactionQueue = mock() private val transitionsMock: Transitions = mock() private val shellTaskOrganizerMock: ShellTaskOrganizer = mock() - private val desktopRepository: DesktopRepository = mock() + private val userRepositories: DesktopUserRepositories = mock() private val desktopModeEventLogger: DesktopModeEventLogger = mock() private val toggleResizeDesktopTaskTransitionHandlerMock: ToggleResizeDesktopTaskTransitionHandler = @@ -75,7 +75,7 @@ class DesktopTilingDecorViewModelTest : ShellTestCase() { shellTaskOrganizerMock, toggleResizeDesktopTaskTransitionHandlerMock, returnToDragStartAnimatorMock, - desktopRepository, + userRepositories, desktopModeEventLogger, ) whenever(contextMock.createContextAsUser(any(), any())).thenReturn(contextMock) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecorationTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecorationTest.kt index 3b39f1e4a25a..95e2151be96c 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecorationTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecorationTest.kt @@ -39,6 +39,7 @@ import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeT import com.android.wm.shell.desktopmode.DesktopRepository import com.android.wm.shell.desktopmode.DesktopTasksController import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask +import com.android.wm.shell.desktopmode.DesktopUserRepositories import com.android.wm.shell.desktopmode.ReturnToDragStartAnimator import com.android.wm.shell.desktopmode.ToggleResizeDesktopTaskTransitionHandler import com.android.wm.shell.transition.Transitions @@ -93,10 +94,11 @@ class DesktopTilingWindowDecorationTest : ShellTestCase() { private val transition: IBinder = mock() private val info: TransitionInfo = mock() private val finishCallback: Transitions.TransitionFinishCallback = mock() - private val desktopRepository: DesktopRepository = mock() + private val userRepositories: DesktopUserRepositories = mock() private val desktopModeEventLogger: DesktopModeEventLogger = mock() private val desktopTilingDividerWindowManager: DesktopTilingDividerWindowManager = mock() private val motionEvent: MotionEvent = mock() + private val desktopRepository: DesktopRepository = mock() private lateinit var tilingDecoration: DesktopTilingWindowDecoration private val split_divider_width = 10 @@ -116,10 +118,11 @@ class DesktopTilingWindowDecorationTest : ShellTestCase() { shellTaskOrganizer, toggleResizeDesktopTaskTransitionHandler, returnToDragStartAnimator, - desktopRepository, + userRepositories, desktopModeEventLogger, ) whenever(context.createContextAsUser(any(), any())).thenReturn(context) + whenever(userRepositories.current).thenReturn(desktopRepository) } @Test @@ -275,8 +278,8 @@ class DesktopTilingWindowDecorationTest : ShellTestCase() { } whenever(context.resources).thenReturn(resources) whenever(resources.getDimensionPixelSize(any())).thenReturn(split_divider_width) - whenever(desktopRepository.isVisibleTask(eq(task1.taskId))).thenReturn(true) - whenever(desktopRepository.isVisibleTask(eq(task2.taskId))).thenReturn(true) + whenever(userRepositories.current.isVisibleTask(eq(task1.taskId))).thenReturn(true) + whenever(userRepositories.current.isVisibleTask(eq(task2.taskId))).thenReturn(true) tilingDecoration.onAppTiled( task1, @@ -308,7 +311,7 @@ class DesktopTilingWindowDecorationTest : ShellTestCase() { whenever(context.resources).thenReturn(resources) whenever(resources.getDimensionPixelSize(any())).thenReturn(split_divider_width) whenever(desktopWindowDecoration.getLeash()).thenReturn(surfaceControlMock) - whenever(desktopRepository.isVisibleTask(any())).thenReturn(true) + whenever(userRepositories.current.isVisibleTask(any())).thenReturn(true) tilingDecoration.onAppTiled( task1, desktopWindowDecoration, @@ -341,7 +344,7 @@ class DesktopTilingWindowDecorationTest : ShellTestCase() { whenever(context.resources).thenReturn(resources) whenever(resources.getDimensionPixelSize(any())).thenReturn(split_divider_width) whenever(desktopWindowDecoration.getLeash()).thenReturn(surfaceControlMock) - whenever(desktopRepository.isVisibleTask(any())).thenReturn(true) + whenever(userRepositories.current.isVisibleTask(any())).thenReturn(true) tilingDecoration.onAppTiled( task1, desktopWindowDecoration, @@ -614,7 +617,7 @@ class DesktopTilingWindowDecorationTest : ShellTestCase() { private fun createVisibleTask() = createFreeformTask().also { - whenever(desktopRepository.isVisibleTask(eq(it.taskId))).thenReturn(true) + whenever(userRepositories.current.isVisibleTask(eq(it.taskId))).thenReturn(true) } companion object { |