diff options
6 files changed, 235 insertions, 43 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java index 8a6fe437e652..701a3a42fadd 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 @@ -190,7 +190,8 @@ public abstract class WMShellModule { ShellTaskOrganizer taskOrganizer, DisplayController displayController, SyncTransactionQueue syncQueue, - Optional<DesktopModeController> desktopModeController) { + Optional<DesktopModeController> desktopModeController, + Optional<DesktopTasksController> desktopTasksController) { return new CaptionWindowDecorViewModel( context, mainHandler, @@ -198,7 +199,8 @@ public abstract class WMShellModule { taskOrganizer, displayController, syncQueue, - desktopModeController); + desktopModeController, + desktopTasksController); } // 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 8ded092f5383..b075b14fb0a4 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 @@ -16,7 +16,11 @@ package com.android.wm.shell.desktopmode +import android.app.ActivityManager +import android.app.WindowConfiguration import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME +import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED +import android.app.WindowConfiguration.WindowingMode import android.content.Context import android.view.WindowManager import android.window.WindowContainerTransaction @@ -84,6 +88,59 @@ class DesktopTasksController( } } + /** Move a task with given `taskId` to desktop */ + fun moveToDesktop(taskId: Int) { + shellTaskOrganizer.getRunningTaskInfo(taskId)?.let { task -> moveToDesktop(task) } + } + + /** Move a task to desktop */ + fun moveToDesktop(task: ActivityManager.RunningTaskInfo) { + ProtoLog.v(WM_SHELL_DESKTOP_MODE, "moveToDesktop: %d", task.taskId) + + val wct = WindowContainerTransaction() + // Bring other apps to front first + bringDesktopAppsToFront(wct) + + wct.setWindowingMode(task.getToken(), WindowConfiguration.WINDOWING_MODE_FREEFORM) + wct.reorder(task.getToken(), true /* onTop */) + + if (Transitions.ENABLE_SHELL_TRANSITIONS) { + transitions.startTransition(WindowManager.TRANSIT_CHANGE, wct, null /* handler */) + } else { + shellTaskOrganizer.applyTransaction(wct) + } + } + + /** Move a task with given `taskId` to fullscreen */ + fun moveToFullscreen(taskId: Int) { + shellTaskOrganizer.getRunningTaskInfo(taskId)?.let { task -> moveToFullscreen(task) } + } + + /** Move a task to fullscreen */ + fun moveToFullscreen(task: ActivityManager.RunningTaskInfo) { + ProtoLog.v(WM_SHELL_DESKTOP_MODE, "moveToFullscreen: %d", task.taskId) + + val wct = WindowContainerTransaction() + wct.setWindowingMode(task.getToken(), WindowConfiguration.WINDOWING_MODE_FULLSCREEN) + wct.setBounds(task.getToken(), null) + if (Transitions.ENABLE_SHELL_TRANSITIONS) { + transitions.startTransition(WindowManager.TRANSIT_CHANGE, wct, null /* handler */) + } else { + shellTaskOrganizer.applyTransaction(wct) + } + } + + /** + * Get windowing move for a given `taskId` + * + * @return [WindowingMode] for the task or [WINDOWING_MODE_UNDEFINED] if task is not found + */ + @WindowingMode + fun getTaskWindowingMode(taskId: Int): Int { + return shellTaskOrganizer.getRunningTaskInfo(taskId)?.windowingMode + ?: WINDOWING_MODE_UNDEFINED + } + private fun bringDesktopAppsToFront(wct: WindowContainerTransaction) { val activeTasks = desktopModeTaskRepository.getActiveTasks() diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java index 42e2b3fadf19..299284f5bda6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java @@ -53,6 +53,7 @@ import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.desktopmode.DesktopModeController; import com.android.wm.shell.desktopmode.DesktopModeStatus; +import com.android.wm.shell.desktopmode.DesktopTasksController; import com.android.wm.shell.freeform.FreeformTaskTransitionStarter; import com.android.wm.shell.transition.Transitions; @@ -75,6 +76,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { private final SyncTransactionQueue mSyncQueue; private FreeformTaskTransitionStarter mTransitionStarter; private Optional<DesktopModeController> mDesktopModeController; + private Optional<DesktopTasksController> mDesktopTasksController; private boolean mTransitionDragActive; private SparseArray<EventReceiver> mEventReceiversByDisplay = new SparseArray<>(); @@ -90,7 +92,8 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { ShellTaskOrganizer taskOrganizer, DisplayController displayController, SyncTransactionQueue syncQueue, - Optional<DesktopModeController> desktopModeController) { + Optional<DesktopModeController> desktopModeController, + Optional<DesktopTasksController> desktopTasksController) { this( context, mainHandler, @@ -99,6 +102,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { displayController, syncQueue, desktopModeController, + desktopTasksController, new CaptionWindowDecoration.Factory(), new InputMonitorFactory()); } @@ -112,6 +116,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { DisplayController displayController, SyncTransactionQueue syncQueue, Optional<DesktopModeController> desktopModeController, + Optional<DesktopTasksController> desktopTasksController, CaptionWindowDecoration.Factory captionWindowDecorFactory, InputMonitorFactory inputMonitorFactory) { mContext = context; @@ -122,6 +127,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { mDisplayController = displayController; mSyncQueue = syncQueue; mDesktopModeController = desktopModeController; + mDesktopTasksController = desktopTasksController; mCaptionWindowDecorFactory = captionWindowDecorFactory; mInputMonitorFactory = inputMonitorFactory; @@ -242,11 +248,13 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { decoration.createHandleMenu(); } else if (id == R.id.desktop_button) { mDesktopModeController.ifPresent(c -> c.setDesktopModeActive(true)); + mDesktopTasksController.ifPresent(c -> c.moveToDesktop(mTaskId)); decoration.closeHandleMenu(); } else if (id == R.id.fullscreen_button) { mDesktopModeController.ifPresent(c -> c.setDesktopModeActive(false)); + mDesktopTasksController.ifPresent(c -> c.moveToFullscreen(mTaskId)); decoration.closeHandleMenu(); - decoration.setButtonVisibility(); + decoration.setButtonVisibility(false); } } @@ -299,8 +307,13 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { */ private void handleEventForMove(MotionEvent e) { RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId); - if (mDesktopModeController.isPresent() - && mDesktopModeController.get().getDisplayAreaWindowingMode(taskInfo.displayId) + if (DesktopModeStatus.isProto2Enabled() + && taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) { + return; + } + if (DesktopModeStatus.isProto1Enabled() && mDesktopModeController.isPresent() + && mDesktopModeController.get().getDisplayAreaWindowingMode( + taskInfo.displayId) == WINDOWING_MODE_FULLSCREEN) { return; } @@ -324,9 +337,20 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { .stableInsets().top; mDragResizeCallback.onDragResizeEnd( e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx)); - if (e.getRawY(dragPointerIdx) <= statusBarHeight - && DesktopModeStatus.isActive(mContext)) { - mDesktopModeController.ifPresent(c -> c.setDesktopModeActive(false)); + if (e.getRawY(dragPointerIdx) <= statusBarHeight) { + if (DesktopModeStatus.isProto2Enabled()) { + if (taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) { + // Switch a single task to fullscreen + mDesktopTasksController.ifPresent( + c -> c.moveToFullscreen(taskInfo)); + } + } else if (DesktopModeStatus.isProto1Enabled()) { + if (DesktopModeStatus.isActive(mContext)) { + // Turn off desktop mode + mDesktopModeController.ifPresent( + c -> c.setDesktopModeActive(false)); + } + } } break; } @@ -408,13 +432,27 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { * @param ev the {@link MotionEvent} received by {@link EventReceiver} */ private void handleReceivedMotionEvent(MotionEvent ev, InputMonitor inputMonitor) { - if (!DesktopModeStatus.isActive(mContext)) { - handleCaptionThroughStatusBar(ev); + if (DesktopModeStatus.isProto2Enabled()) { + CaptionWindowDecoration focusedDecor = getFocusedDecor(); + if (focusedDecor == null + || focusedDecor.mTaskInfo.getWindowingMode() != WINDOWING_MODE_FREEFORM) { + handleCaptionThroughStatusBar(ev); + } + } else if (DesktopModeStatus.isProto1Enabled()) { + if (!DesktopModeStatus.isActive(mContext)) { + handleCaptionThroughStatusBar(ev); + } } handleEventOutsideFocusedCaption(ev); // Prevent status bar from reacting to a caption drag. - if (mTransitionDragActive && !DesktopModeStatus.isActive(mContext)) { - inputMonitor.pilferPointers(); + if (DesktopModeStatus.isProto2Enabled()) { + if (mTransitionDragActive) { + inputMonitor.pilferPointers(); + } + } else if (DesktopModeStatus.isProto1Enabled()) { + if (mTransitionDragActive && !DesktopModeStatus.isActive(mContext)) { + inputMonitor.pilferPointers(); + } } } @@ -443,9 +481,20 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { case MotionEvent.ACTION_DOWN: { // Begin drag through status bar if applicable. CaptionWindowDecoration focusedDecor = getFocusedDecor(); - if (focusedDecor != null && !DesktopModeStatus.isActive(mContext) - && focusedDecor.checkTouchEventInHandle(ev)) { - mTransitionDragActive = true; + if (focusedDecor != null) { + boolean dragFromStatusBarAllowed = false; + if (DesktopModeStatus.isProto2Enabled()) { + // In proto2 any full screen task can be dragged to freeform + dragFromStatusBarAllowed = focusedDecor.mTaskInfo.getWindowingMode() + == WINDOWING_MODE_FULLSCREEN; + } else if (DesktopModeStatus.isProto1Enabled()) { + // In proto1 task can be dragged to freeform when not in desktop mode + dragFromStatusBarAllowed = !DesktopModeStatus.isActive(mContext); + } + + if (dragFromStatusBarAllowed && focusedDecor.checkTouchEventInHandle(ev)) { + mTransitionDragActive = true; + } } break; } @@ -460,7 +509,13 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel { int statusBarHeight = mDisplayController .getDisplayLayout(focusedDecor.mTaskInfo.displayId).stableInsets().top; if (ev.getY() > statusBarHeight) { - mDesktopModeController.ifPresent(c -> c.setDesktopModeActive(true)); + if (DesktopModeStatus.isProto2Enabled()) { + mDesktopTasksController.ifPresent( + c -> c.moveToDesktop(focusedDecor.mTaskInfo)); + } else if (DesktopModeStatus.isProto1Enabled()) { + mDesktopModeController.ifPresent(c -> c.setDesktopModeActive(true)); + } + return; } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java index 037ca2031254..f7c7a87e6659 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java @@ -16,8 +16,9 @@ package com.android.wm.shell.windowdecor; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; + import android.app.ActivityManager; -import android.app.WindowConfiguration; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.Resources; @@ -117,7 +118,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL ? R.dimen.freeform_decor_shadow_focused_thickness : R.dimen.freeform_decor_shadow_unfocused_thickness; final boolean isFreeform = - taskInfo.getWindowingMode() == WindowConfiguration.WINDOWING_MODE_FREEFORM; + taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM; final boolean isDragResizeable = isFreeform && taskInfo.isResizeable; WindowDecorLinearLayout oldRootView = mResult.mRootView; @@ -167,11 +168,17 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL // If this task is not focused, do not show caption. setCaptionVisibility(mTaskInfo.isFocused); - // Only handle should show if Desktop Mode is inactive. - boolean desktopCurrentStatus = DesktopModeStatus.isActive(mContext); - if (mDesktopActive != desktopCurrentStatus && mTaskInfo.isFocused) { - mDesktopActive = desktopCurrentStatus; - setButtonVisibility(); + if (mTaskInfo.isFocused) { + if (DesktopModeStatus.isProto2Enabled()) { + updateButtonVisibility(); + } else if (DesktopModeStatus.isProto1Enabled()) { + // Only handle should show if Desktop Mode is inactive. + boolean desktopCurrentStatus = DesktopModeStatus.isActive(mContext); + if (mDesktopActive != desktopCurrentStatus) { + mDesktopActive = desktopCurrentStatus; + setButtonVisibility(mDesktopActive); + } + } } if (!isDragResizeable) { @@ -214,7 +221,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL View handle = caption.findViewById(R.id.caption_handle); handle.setOnTouchListener(mOnCaptionTouchListener); handle.setOnClickListener(mOnCaptionButtonClickListener); - setButtonVisibility(); + updateButtonVisibility(); } private void setupHandleMenu() { @@ -244,14 +251,25 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL /** * Sets the visibility of buttons and color of caption based on desktop mode status */ - void setButtonVisibility() { - mDesktopActive = DesktopModeStatus.isActive(mContext); - int v = mDesktopActive ? View.VISIBLE : View.GONE; + void updateButtonVisibility() { + if (DesktopModeStatus.isProto2Enabled()) { + setButtonVisibility(mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM); + } else if (DesktopModeStatus.isProto1Enabled()) { + mDesktopActive = DesktopModeStatus.isActive(mContext); + setButtonVisibility(mDesktopActive); + } + } + + /** + * Show or hide buttons + */ + void setButtonVisibility(boolean visible) { + int visibility = visible ? View.VISIBLE : View.GONE; View caption = mResult.mRootView.findViewById(R.id.caption); View back = caption.findViewById(R.id.back_button); View close = caption.findViewById(R.id.close_window); - back.setVisibility(v); - close.setVisibility(v); + back.setVisibility(visibility); + close.setVisibility(visibility); int buttonTintColorRes = mDesktopActive ? R.color.decor_button_dark_color : R.color.decor_button_light_color; @@ -260,7 +278,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL View handle = caption.findViewById(R.id.caption_handle); VectorDrawable handleBackground = (VectorDrawable) handle.getBackground(); handleBackground.setTintList(buttonTintColor); - caption.getBackground().setTint(v == View.VISIBLE ? Color.WHITE : Color.TRANSPARENT); + caption.getBackground().setTint(visible ? Color.WHITE : Color.TRANSPARENT); } boolean isHandleMenuActive() { 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 4e0a5b59cbdc..de2473b8deba 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 @@ -17,6 +17,9 @@ package com.android.wm.shell.desktopmode import android.app.ActivityManager.RunningTaskInfo +import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM +import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN +import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED import android.testing.AndroidTestingRunner import android.window.WindowContainerTransaction import android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER @@ -29,6 +32,7 @@ import com.android.wm.shell.ShellTestCase import com.android.wm.shell.TestShellExecutor import com.android.wm.shell.common.ShellExecutor import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask +import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFullscreenTask import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createHomeTask import com.android.wm.shell.sysui.ShellController import com.android.wm.shell.sysui.ShellInit @@ -118,8 +122,8 @@ class DesktopTasksControllerTest : ShellTestCase() { @Test fun showDesktopApps_allAppsInvisible_bringsToFront() { val homeTask = setUpHomeTask() - val task1 = setUpDesktopTask() - val task2 = setUpDesktopTask() + val task1 = setUpFreeformTask() + val task2 = setUpFreeformTask() markTaskHidden(task1) markTaskHidden(task2) @@ -136,25 +140,21 @@ class DesktopTasksControllerTest : ShellTestCase() { @Test fun showDesktopApps_appsAlreadyVisible_doesNothing() { setUpHomeTask() - val task1 = setUpDesktopTask() - val task2 = setUpDesktopTask() + val task1 = setUpFreeformTask() + val task2 = setUpFreeformTask() markTaskVisible(task1) markTaskVisible(task2) controller.showDesktopApps() - if (Transitions.ENABLE_SHELL_TRANSITIONS) { - verify(transitions, never()).startTransition(anyInt(), any(), isNull()) - } else { - verify(shellTaskOrganizer, never()).applyTransaction(any()) - } + verifyWCTNotExecuted() } @Test fun showDesktopApps_someAppsInvisible_reordersAll() { val homeTask = setUpHomeTask() - val task1 = setUpDesktopTask() - val task2 = setUpDesktopTask() + val task1 = setUpFreeformTask() + val task2 = setUpFreeformTask() markTaskHidden(task1) markTaskVisible(task2) @@ -179,7 +179,49 @@ class DesktopTasksControllerTest : ShellTestCase() { wct.assertReorderAt(index = 0, homeTask) } - private fun setUpDesktopTask(): RunningTaskInfo { + @Test + fun moveToDesktop() { + val task = setUpFullscreenTask() + controller.moveToDesktop(task) + val wct = getLatestWct() + assertThat(wct.changes[task.token.asBinder()]?.windowingMode) + .isEqualTo(WINDOWING_MODE_FREEFORM) + } + + @Test + fun moveToDesktop_nonExistentTask_doesNothing() { + controller.moveToDesktop(999) + verifyWCTNotExecuted() + } + + @Test + fun moveToFullscreen() { + val task = setUpFreeformTask() + controller.moveToFullscreen(task) + val wct = getLatestWct() + assertThat(wct.changes[task.token.asBinder()]?.windowingMode) + .isEqualTo(WINDOWING_MODE_FULLSCREEN) + } + + @Test + fun moveToFullscreen_nonExistentTask_doesNothing() { + controller.moveToFullscreen(999) + verifyWCTNotExecuted() + } + + @Test + fun getTaskWindowingMode() { + val fullscreenTask = setUpFullscreenTask() + val freeformTask = setUpFreeformTask() + + assertThat(controller.getTaskWindowingMode(fullscreenTask.taskId)) + .isEqualTo(WINDOWING_MODE_FULLSCREEN) + assertThat(controller.getTaskWindowingMode(freeformTask.taskId)) + .isEqualTo(WINDOWING_MODE_FREEFORM) + assertThat(controller.getTaskWindowingMode(999)).isEqualTo(WINDOWING_MODE_UNDEFINED) + } + + private fun setUpFreeformTask(): RunningTaskInfo { val task = createFreeformTask() whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task) desktopModeTaskRepository.addActiveTask(task.taskId) @@ -195,6 +237,13 @@ class DesktopTasksControllerTest : ShellTestCase() { return task } + private fun setUpFullscreenTask(): RunningTaskInfo { + val task = createFullscreenTask() + whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task) + runningTasks.add(task) + return task + } + private fun markTaskVisible(task: RunningTaskInfo) { desktopModeTaskRepository.updateVisibleFreeformTasks(task.taskId, visible = true) } @@ -212,6 +261,14 @@ class DesktopTasksControllerTest : ShellTestCase() { } return arg.value } + + private fun verifyWCTNotExecuted() { + if (Transitions.ENABLE_SHELL_TRANSITIONS) { + verify(transitions, never()).startTransition(anyInt(), any(), isNull()) + } else { + verify(shellTaskOrganizer, never()).applyTransaction(any()) + } + } } private fun WindowContainerTransaction.assertReorderAt(index: Int, task: RunningTaskInfo) { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModelTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModelTests.java index 0dbf30d69f75..487583262011 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModelTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModelTests.java @@ -48,6 +48,7 @@ import com.android.wm.shell.TestRunningTaskInfoBuilder; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.desktopmode.DesktopModeController; +import com.android.wm.shell.desktopmode.DesktopTasksController; import org.junit.Before; import org.junit.Test; @@ -74,6 +75,7 @@ public class CaptionWindowDecorViewModelTests extends ShellTestCase { @Mock private DisplayController mDisplayController; @Mock private SyncTransactionQueue mSyncQueue; @Mock private DesktopModeController mDesktopModeController; + @Mock private DesktopTasksController mDesktopTasksController; @Mock private InputMonitor mInputMonitor; @Mock private InputManager mInputManager; @@ -95,6 +97,7 @@ public class CaptionWindowDecorViewModelTests extends ShellTestCase { mDisplayController, mSyncQueue, Optional.of(mDesktopModeController), + Optional.of(mDesktopTasksController), mCaptionWindowDecorFactory, mMockInputMonitorFactory ); |