Loading libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +4 −2 Original line number Diff line number Diff line Loading @@ -1054,7 +1054,8 @@ public abstract class WMShellModule { DesktopModeCompatPolicy desktopModeCompatPolicy, DesktopTilingDecorViewModel desktopTilingDecorViewModel, MultiDisplayDragMoveIndicatorController multiDisplayDragMoveIndicatorController, Optional<CompatUIHandler> compatUI Optional<CompatUIHandler> compatUI, DesksOrganizer desksOrganizer ) { if (!DesktopModeStatus.canEnterDesktopModeOrShowAppHandle(context)) { return Optional.empty(); Loading @@ -1072,7 +1073,8 @@ public abstract class WMShellModule { activityOrientationChangeHandler, focusTransitionObserver, desktopModeEventLogger, desktopModeUiEventLogger, taskResourceLoader, recentsTransitionHandler, desktopModeCompatPolicy, desktopTilingDecorViewModel, multiDisplayDragMoveIndicatorController, compatUI.orElse(null))); multiDisplayDragMoveIndicatorController, compatUI.orElse(null), desksOrganizer)); } @WMSingleton Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksOrganizer.kt +3 −0 Original line number Diff line number Diff line Loading @@ -78,6 +78,9 @@ interface DesksOrganizer { /** Whether the desk is activate according to the given change at the end of a transition. */ fun isDeskActiveAtEnd(change: TransitionInfo.Change, deskId: Int): Boolean /** Allows for other classes to respond to task changes this organizer receives. */ fun setOnDesktopTaskInfoChangedListener(listener: (ActivityManager.RunningTaskInfo) -> Unit) /** A callback that is invoked when the desk container is created. */ fun interface OnCreateCallback { /** Calls back when the [deskId] has been created. */ Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizer.kt +11 −0 Original line number Diff line number Diff line Loading @@ -54,6 +54,7 @@ class RootTaskDesksOrganizer( mutableListOf<CreateDeskMinimizationRootRequest>() @VisibleForTesting val deskMinimizationRootsByDeskId: MutableMap<Int, DeskMinimizationRoot> = mutableMapOf() private var onTaskInfoChangedListener: ((RunningTaskInfo) -> Unit)? = null init { if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { Loading Loading @@ -213,6 +214,10 @@ class RootTaskDesksOrganizer( change.taskInfo?.isVisibleRequested == true && change.mode == TRANSIT_TO_FRONT override fun setOnDesktopTaskInfoChangedListener(listener: (RunningTaskInfo) -> Unit) { onTaskInfoChangedListener = listener } override fun onTaskAppeared(taskInfo: RunningTaskInfo, leash: SurfaceControl) { handleTaskAppeared(taskInfo, leash) updateLaunchAdjacentController() Loading @@ -220,6 +225,12 @@ class RootTaskDesksOrganizer( override fun onTaskInfoChanged(taskInfo: RunningTaskInfo) { handleTaskInfoChanged(taskInfo) if ( taskInfo.taskId !in deskRootsByDeskId && deskMinimizationRootsByDeskId.values.none { it.rootId == taskInfo.taskId } ) { onTaskInfoChangedListener?.invoke(taskInfo) } updateLaunchAdjacentController() } Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +13 −3 Original line number Diff line number Diff line Loading @@ -125,6 +125,7 @@ import com.android.wm.shell.desktopmode.common.ToggleTaskSizeInteraction; import com.android.wm.shell.desktopmode.common.ToggleTaskSizeUtilsKt; import com.android.wm.shell.desktopmode.education.AppHandleEducationController; import com.android.wm.shell.desktopmode.education.AppToWebEducationController; import com.android.wm.shell.desktopmode.multidesks.DesksOrganizer; import com.android.wm.shell.freeform.FreeformTaskTransitionStarter; import com.android.wm.shell.recents.RecentsTransitionHandler; import com.android.wm.shell.recents.RecentsTransitionStateListener; Loading Loading @@ -210,6 +211,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, private final AppHandleAndHeaderVisibilityHelper mAppHandleAndHeaderVisibilityHelper; private final AppHeaderViewHolder.Factory mAppHeaderViewHolderFactory; private final AppHandleViewHolder.Factory mAppHandleViewHolderFactory; private final DesksOrganizer mDesksOrganizer; private boolean mTransitionDragActive; private SparseArray<EventReceiver> mEventReceiversByDisplay = new SparseArray<>(); Loading Loading @@ -308,7 +310,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, DesktopModeCompatPolicy desktopModeCompatPolicy, DesktopTilingDecorViewModel desktopTilingDecorViewModel, MultiDisplayDragMoveIndicatorController multiDisplayDragMoveIndicatorController, CompatUIHandler compatUI) { CompatUIHandler compatUI, DesksOrganizer desksOrganizer) { this( context, shellExecutor, Loading Loading @@ -356,7 +359,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, desktopModeCompatPolicy, desktopTilingDecorViewModel, multiDisplayDragMoveIndicatorController, compatUI); compatUI, desksOrganizer); } @VisibleForTesting Loading Loading @@ -407,7 +411,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, DesktopModeCompatPolicy desktopModeCompatPolicy, DesktopTilingDecorViewModel desktopTilingDecorViewModel, MultiDisplayDragMoveIndicatorController multiDisplayDragMoveIndicatorController, CompatUIHandler compatUI) { CompatUIHandler compatUI, DesksOrganizer desksOrganizer) { mContext = context; mMainExecutor = shellExecutor; mMainHandler = mainHandler; Loading Loading @@ -485,6 +490,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, mDesktopTasksController.setSnapEventHandler(this); mMultiDisplayDragMoveIndicatorController = multiDisplayDragMoveIndicatorController; mLatencyTracker = LatencyTracker.getInstance(mContext); mDesksOrganizer = desksOrganizer; shellInit.addInitCallback(this::onInit, this); } Loading Loading @@ -523,6 +529,10 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, }); } mFocusTransitionObserver.setLocalFocusTransitionListener(this, mMainExecutor); mDesksOrganizer.setOnDesktopTaskInfoChangedListener((taskInfo) -> { onTaskInfoChanged(taskInfo); return Unit.INSTANCE; }); } @Override Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizerTest.kt +37 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ package com.android.wm.shell.desktopmode.multidesks import android.app.ActivityManager import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED import android.testing.AndroidTestingRunner Loading Loading @@ -48,7 +49,9 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.kotlin.any import org.mockito.kotlin.argThat import org.mockito.kotlin.mock import org.mockito.kotlin.whenever Loading @@ -67,6 +70,7 @@ class RootTaskDesksOrganizerTest : ShellTestCase() { private val mockShellCommandHandler = mock<ShellCommandHandler>() private val mockShellTaskOrganizer = mock<ShellTaskOrganizer>() private val launchAdjacentController = LaunchAdjacentController(mock()) private val taskInfoChangedListener = mock<(ActivityManager.RunningTaskInfo) -> Unit>() private lateinit var organizer: RootTaskDesksOrganizer Loading @@ -79,6 +83,7 @@ class RootTaskDesksOrganizerTest : ShellTestCase() { mockShellTaskOrganizer, launchAdjacentController, ) organizer.setOnDesktopTaskInfoChangedListener(taskInfoChangedListener) } @Test fun testCreateDesk_createsDeskAndMinimizationRoots() = runTest { createDesk() } Loading Loading @@ -652,6 +657,34 @@ class RootTaskDesksOrganizerTest : ShellTestCase() { assertThat(launchAdjacentController.launchAdjacentEnabled).isFalse() } @Test fun onTaskInfoChanged_taskNotRoot_invokesListener() = runTest { createDesk() val task = createFreeformTask().apply { taskId = TEST_CHILD_TASK_ID } organizer.onTaskInfoChanged(task) verify(taskInfoChangedListener).invoke(task) } @Test fun onTaskInfoChanged_isDeskRoot_doesNotInvokeListener() = runTest { val deskRoot = createDesk().deskRoot organizer.onTaskInfoChanged(deskRoot.taskInfo) verify(taskInfoChangedListener, never()).invoke(any()) } @Test fun onTaskInfoChanged_isMinimizationRoot_doesNotInvokeListener() = runTest { val minimizationRoot = createDesk().minimizationRoot organizer.onTaskInfoChanged(minimizationRoot.taskInfo) verify(taskInfoChangedListener, never()).invoke(any()) } private data class DeskRoots( val deskRoot: DeskRoot, val minimizationRoot: DeskMinimizationRoot, Loading Loading @@ -712,4 +745,8 @@ class RootTaskDesksOrganizerTest : ShellTestCase() { hop.newParent == desk.deskRoot.token.asBinder() && hop.toTop } companion object { private const val TEST_CHILD_TASK_ID = 100 } } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +4 −2 Original line number Diff line number Diff line Loading @@ -1054,7 +1054,8 @@ public abstract class WMShellModule { DesktopModeCompatPolicy desktopModeCompatPolicy, DesktopTilingDecorViewModel desktopTilingDecorViewModel, MultiDisplayDragMoveIndicatorController multiDisplayDragMoveIndicatorController, Optional<CompatUIHandler> compatUI Optional<CompatUIHandler> compatUI, DesksOrganizer desksOrganizer ) { if (!DesktopModeStatus.canEnterDesktopModeOrShowAppHandle(context)) { return Optional.empty(); Loading @@ -1072,7 +1073,8 @@ public abstract class WMShellModule { activityOrientationChangeHandler, focusTransitionObserver, desktopModeEventLogger, desktopModeUiEventLogger, taskResourceLoader, recentsTransitionHandler, desktopModeCompatPolicy, desktopTilingDecorViewModel, multiDisplayDragMoveIndicatorController, compatUI.orElse(null))); multiDisplayDragMoveIndicatorController, compatUI.orElse(null), desksOrganizer)); } @WMSingleton Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksOrganizer.kt +3 −0 Original line number Diff line number Diff line Loading @@ -78,6 +78,9 @@ interface DesksOrganizer { /** Whether the desk is activate according to the given change at the end of a transition. */ fun isDeskActiveAtEnd(change: TransitionInfo.Change, deskId: Int): Boolean /** Allows for other classes to respond to task changes this organizer receives. */ fun setOnDesktopTaskInfoChangedListener(listener: (ActivityManager.RunningTaskInfo) -> Unit) /** A callback that is invoked when the desk container is created. */ fun interface OnCreateCallback { /** Calls back when the [deskId] has been created. */ Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizer.kt +11 −0 Original line number Diff line number Diff line Loading @@ -54,6 +54,7 @@ class RootTaskDesksOrganizer( mutableListOf<CreateDeskMinimizationRootRequest>() @VisibleForTesting val deskMinimizationRootsByDeskId: MutableMap<Int, DeskMinimizationRoot> = mutableMapOf() private var onTaskInfoChangedListener: ((RunningTaskInfo) -> Unit)? = null init { if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { Loading Loading @@ -213,6 +214,10 @@ class RootTaskDesksOrganizer( change.taskInfo?.isVisibleRequested == true && change.mode == TRANSIT_TO_FRONT override fun setOnDesktopTaskInfoChangedListener(listener: (RunningTaskInfo) -> Unit) { onTaskInfoChangedListener = listener } override fun onTaskAppeared(taskInfo: RunningTaskInfo, leash: SurfaceControl) { handleTaskAppeared(taskInfo, leash) updateLaunchAdjacentController() Loading @@ -220,6 +225,12 @@ class RootTaskDesksOrganizer( override fun onTaskInfoChanged(taskInfo: RunningTaskInfo) { handleTaskInfoChanged(taskInfo) if ( taskInfo.taskId !in deskRootsByDeskId && deskMinimizationRootsByDeskId.values.none { it.rootId == taskInfo.taskId } ) { onTaskInfoChangedListener?.invoke(taskInfo) } updateLaunchAdjacentController() } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +13 −3 Original line number Diff line number Diff line Loading @@ -125,6 +125,7 @@ import com.android.wm.shell.desktopmode.common.ToggleTaskSizeInteraction; import com.android.wm.shell.desktopmode.common.ToggleTaskSizeUtilsKt; import com.android.wm.shell.desktopmode.education.AppHandleEducationController; import com.android.wm.shell.desktopmode.education.AppToWebEducationController; import com.android.wm.shell.desktopmode.multidesks.DesksOrganizer; import com.android.wm.shell.freeform.FreeformTaskTransitionStarter; import com.android.wm.shell.recents.RecentsTransitionHandler; import com.android.wm.shell.recents.RecentsTransitionStateListener; Loading Loading @@ -210,6 +211,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, private final AppHandleAndHeaderVisibilityHelper mAppHandleAndHeaderVisibilityHelper; private final AppHeaderViewHolder.Factory mAppHeaderViewHolderFactory; private final AppHandleViewHolder.Factory mAppHandleViewHolderFactory; private final DesksOrganizer mDesksOrganizer; private boolean mTransitionDragActive; private SparseArray<EventReceiver> mEventReceiversByDisplay = new SparseArray<>(); Loading Loading @@ -308,7 +310,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, DesktopModeCompatPolicy desktopModeCompatPolicy, DesktopTilingDecorViewModel desktopTilingDecorViewModel, MultiDisplayDragMoveIndicatorController multiDisplayDragMoveIndicatorController, CompatUIHandler compatUI) { CompatUIHandler compatUI, DesksOrganizer desksOrganizer) { this( context, shellExecutor, Loading Loading @@ -356,7 +359,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, desktopModeCompatPolicy, desktopTilingDecorViewModel, multiDisplayDragMoveIndicatorController, compatUI); compatUI, desksOrganizer); } @VisibleForTesting Loading Loading @@ -407,7 +411,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, DesktopModeCompatPolicy desktopModeCompatPolicy, DesktopTilingDecorViewModel desktopTilingDecorViewModel, MultiDisplayDragMoveIndicatorController multiDisplayDragMoveIndicatorController, CompatUIHandler compatUI) { CompatUIHandler compatUI, DesksOrganizer desksOrganizer) { mContext = context; mMainExecutor = shellExecutor; mMainHandler = mainHandler; Loading Loading @@ -485,6 +490,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, mDesktopTasksController.setSnapEventHandler(this); mMultiDisplayDragMoveIndicatorController = multiDisplayDragMoveIndicatorController; mLatencyTracker = LatencyTracker.getInstance(mContext); mDesksOrganizer = desksOrganizer; shellInit.addInitCallback(this::onInit, this); } Loading Loading @@ -523,6 +529,10 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, }); } mFocusTransitionObserver.setLocalFocusTransitionListener(this, mMainExecutor); mDesksOrganizer.setOnDesktopTaskInfoChangedListener((taskInfo) -> { onTaskInfoChanged(taskInfo); return Unit.INSTANCE; }); } @Override Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizerTest.kt +37 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ package com.android.wm.shell.desktopmode.multidesks import android.app.ActivityManager import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED import android.testing.AndroidTestingRunner Loading Loading @@ -48,7 +49,9 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.kotlin.any import org.mockito.kotlin.argThat import org.mockito.kotlin.mock import org.mockito.kotlin.whenever Loading @@ -67,6 +70,7 @@ class RootTaskDesksOrganizerTest : ShellTestCase() { private val mockShellCommandHandler = mock<ShellCommandHandler>() private val mockShellTaskOrganizer = mock<ShellTaskOrganizer>() private val launchAdjacentController = LaunchAdjacentController(mock()) private val taskInfoChangedListener = mock<(ActivityManager.RunningTaskInfo) -> Unit>() private lateinit var organizer: RootTaskDesksOrganizer Loading @@ -79,6 +83,7 @@ class RootTaskDesksOrganizerTest : ShellTestCase() { mockShellTaskOrganizer, launchAdjacentController, ) organizer.setOnDesktopTaskInfoChangedListener(taskInfoChangedListener) } @Test fun testCreateDesk_createsDeskAndMinimizationRoots() = runTest { createDesk() } Loading Loading @@ -652,6 +657,34 @@ class RootTaskDesksOrganizerTest : ShellTestCase() { assertThat(launchAdjacentController.launchAdjacentEnabled).isFalse() } @Test fun onTaskInfoChanged_taskNotRoot_invokesListener() = runTest { createDesk() val task = createFreeformTask().apply { taskId = TEST_CHILD_TASK_ID } organizer.onTaskInfoChanged(task) verify(taskInfoChangedListener).invoke(task) } @Test fun onTaskInfoChanged_isDeskRoot_doesNotInvokeListener() = runTest { val deskRoot = createDesk().deskRoot organizer.onTaskInfoChanged(deskRoot.taskInfo) verify(taskInfoChangedListener, never()).invoke(any()) } @Test fun onTaskInfoChanged_isMinimizationRoot_doesNotInvokeListener() = runTest { val minimizationRoot = createDesk().minimizationRoot organizer.onTaskInfoChanged(minimizationRoot.taskInfo) verify(taskInfoChangedListener, never()).invoke(any()) } private data class DeskRoots( val deskRoot: DeskRoot, val minimizationRoot: DeskMinimizationRoot, Loading Loading @@ -712,4 +745,8 @@ class RootTaskDesksOrganizerTest : ShellTestCase() { hop.newParent == desk.deskRoot.token.asBinder() && hop.toTop } companion object { private const val TEST_CHILD_TASK_ID = 100 } }