summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Shivangi Dubey <dshivangi@google.com> 2024-10-01 16:05:30 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2024-10-01 16:05:30 +0000
commit73c6a70eed2cce469c0309f68f7ca71b8b3dcf6c (patch)
tree3f3163a4abd8e4081404d4ee45ce3e42af8b1526
parentb3f9f391102fc4ce59992f6c9d028025b11417c9 (diff)
parent2112cf822b07597dc0b43f37ff0f6364f47bd58c (diff)
Merge "Setup onclick listeners on the tooltip to match what we designed" into main
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationController.kt26
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java31
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationControllerTest.kt47
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt83
5 files changed, 187 insertions, 5 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 2d0ec3625d28..2c030591e106 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
@@ -252,6 +252,7 @@ public abstract class WMShellModule {
AssistContentRequester assistContentRequester,
MultiInstanceHelper multiInstanceHelper,
Optional<DesktopTasksLimiter> desktopTasksLimiter,
+ AppHandleEducationController appHandleEducationController,
WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
Optional<DesktopActivityOrientationChangeHandler> desktopActivityOrientationHandler) {
if (DesktopModeStatus.canEnterDesktopMode(context)) {
@@ -277,6 +278,7 @@ public abstract class WMShellModule {
assistContentRequester,
multiInstanceHelper,
desktopTasksLimiter,
+ appHandleEducationController,
windowDecorCaptionHandleRepository,
desktopActivityOrientationHandler);
}
@@ -869,8 +871,7 @@ public abstract class WMShellModule {
@Provides
static Object provideIndependentShellComponentsToCreate(
DragAndDropController dragAndDropController,
- Optional<DesktopTasksTransitionObserver> desktopTasksTransitionObserverOptional,
- AppHandleEducationController appHandleEducationController
+ Optional<DesktopTasksTransitionObserver> desktopTasksTransitionObserverOptional
) {
return new Object();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationController.kt
index ea5c432a17d7..a1dfb6862ad3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/education/AppHandleEducationController.kt
@@ -31,6 +31,7 @@ import com.android.wm.shell.desktopmode.education.data.AppHandleEducationDatasto
import com.android.wm.shell.shared.annotations.ShellBackgroundThread
import com.android.wm.shell.shared.annotations.ShellMainThread
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus.canEnterDesktopMode
+import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource
import com.android.wm.shell.windowdecor.education.DesktopWindowingEducationTooltipController
import com.android.wm.shell.windowdecor.education.DesktopWindowingEducationTooltipController.EducationViewConfig
import kotlin.time.Duration.Companion.milliseconds
@@ -68,6 +69,9 @@ class AppHandleEducationController(
@ShellMainThread private val applicationCoroutineScope: CoroutineScope,
@ShellBackgroundThread private val backgroundDispatcher: MainCoroutineDispatcher,
) {
+ private lateinit var openHandleMenuCallback: (Int) -> Unit
+ private lateinit var toDesktopModeCallback: (Int, DesktopModeTransitionSource) -> Unit
+
init {
runIfEducationFeatureEnabled {
applicationCoroutineScope.launch {
@@ -114,6 +118,7 @@ class AppHandleEducationController(
arrowDirection = DesktopWindowingEducationTooltipController.TooltipArrowDirection.UP,
onEducationClickAction = {
launchWithExceptionHandling { showWindowingImageButtonTooltip() }
+ openHandleMenuCallback(captionState.runningTaskInfo.taskId)
},
onDismissAction = { launchWithExceptionHandling { showWindowingImageButtonTooltip() } },
)
@@ -171,6 +176,9 @@ class AppHandleEducationController(
DesktopWindowingEducationTooltipController.TooltipArrowDirection.LEFT,
onEducationClickAction = {
launchWithExceptionHandling { showExitWindowingTooltip() }
+ toDesktopModeCallback(
+ captionState.runningTaskInfo.taskId,
+ DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON)
},
onDismissAction = { launchWithExceptionHandling { showExitWindowingTooltip() } },
)
@@ -216,7 +224,9 @@ class AppHandleEducationController(
arrowDirection =
DesktopWindowingEducationTooltipController.TooltipArrowDirection.LEFT,
onDismissAction = {},
- onEducationClickAction = {},
+ onEducationClickAction = {
+ openHandleMenuCallback(captionState.runningTaskInfo.taskId)
+ },
)
windowingEducationViewController.showEducationTooltip(
taskId = captionState.runningTaskInfo.taskId,
@@ -225,6 +235,20 @@ class AppHandleEducationController(
}
}
+ /**
+ * Setup callbacks for app handle education tooltips.
+ *
+ * @param openHandleMenuCallback callback invoked to open app handle menu or app chip menu.
+ * @param toDesktopModeCallback callback invoked to move task into desktop mode.
+ */
+ fun setAppHandleEducationTooltipCallbacks(
+ openHandleMenuCallback: (taskId: Int) -> Unit,
+ toDesktopModeCallback: (taskId: Int, DesktopModeTransitionSource) -> Unit
+ ) {
+ this.openHandleMenuCallback = openHandleMenuCallback
+ this.toDesktopModeCallback = toDesktopModeCallback
+ }
+
private inline fun <T> Flow<T>.catchTimeoutAndLog(crossinline block: () -> Unit) =
catch { exception ->
if (exception is TimeoutCancellationException) block() else throw exception
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 272508f46d33..c34a0bc829c4 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
@@ -87,6 +87,7 @@ import android.window.WindowContainerTransaction;
import android.window.flags.DesktopModeFlags;
import androidx.annotation.Nullable;
+import androidx.annotation.OptIn;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.Cuj;
@@ -112,6 +113,7 @@ import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition;
import com.android.wm.shell.desktopmode.DesktopTasksLimiter;
import com.android.wm.shell.desktopmode.DesktopWallpaperActivity;
import com.android.wm.shell.desktopmode.WindowDecorCaptionHandleRepository;
+import com.android.wm.shell.desktopmode.education.AppHandleEducationController;
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
import com.android.wm.shell.shared.annotations.ShellBackgroundThread;
import com.android.wm.shell.shared.annotations.ShellMainThread;
@@ -134,6 +136,8 @@ import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder;
import kotlin.Pair;
import kotlin.Unit;
+import kotlinx.coroutines.ExperimentalCoroutinesApi;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
@@ -167,6 +171,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
private final MultiInstanceHelper mMultiInstanceHelper;
private final WindowDecorCaptionHandleRepository mWindowDecorCaptionHandleRepository;
private final Optional<DesktopTasksLimiter> mDesktopTasksLimiter;
+ private final AppHandleEducationController mAppHandleEducationController;
private final AppHeaderViewHolder.Factory mAppHeaderViewHolderFactory;
private boolean mTransitionDragActive;
@@ -236,6 +241,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
AssistContentRequester assistContentRequester,
MultiInstanceHelper multiInstanceHelper,
Optional<DesktopTasksLimiter> desktopTasksLimiter,
+ AppHandleEducationController appHandleEducationController,
WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler) {
this(
@@ -265,6 +271,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
new SparseArray<>(),
interactionJankMonitor,
desktopTasksLimiter,
+ appHandleEducationController,
windowDecorCaptionHandleRepository,
activityOrientationChangeHandler,
new TaskPositionerFactory());
@@ -298,6 +305,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
SparseArray<DesktopModeWindowDecoration> windowDecorByTaskId,
InteractionJankMonitor interactionJankMonitor,
Optional<DesktopTasksLimiter> desktopTasksLimiter,
+ AppHandleEducationController appHandleEducationController,
WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler,
TaskPositionerFactory taskPositionerFactory) {
@@ -329,6 +337,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
com.android.internal.R.string.config_systemUi);
mInteractionJankMonitor = interactionJankMonitor;
mDesktopTasksLimiter = desktopTasksLimiter;
+ mAppHandleEducationController = appHandleEducationController;
mWindowDecorCaptionHandleRepository = windowDecorCaptionHandleRepository;
mActivityOrientationChangeHandler = activityOrientationChangeHandler;
mAssistContentRequester = assistContentRequester;
@@ -362,6 +371,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
shellInit.addInitCallback(this::onInit, this);
}
+ @OptIn(markerClass = ExperimentalCoroutinesApi.class)
private void onInit() {
mShellController.addKeyguardChangeListener(mDesktopModeKeyguardChangeListener);
mShellCommandHandler.addDumpCallback(this::dump, this);
@@ -378,6 +388,18 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
} catch (RemoteException e) {
Log.e(TAG, "Failed to register window manager callbacks", e);
}
+ if (DesktopModeStatus.canEnterDesktopMode(mContext)
+ && Flags.enableDesktopWindowingAppHandleEducation()) {
+ mAppHandleEducationController.setAppHandleEducationTooltipCallbacks(
+ /* appHandleTooltipClickCallback= */(taskId) -> {
+ openHandleMenu(taskId);
+ return Unit.INSTANCE;
+ },
+ /* onToDesktopClickCallback= */(taskId, desktopModeTransitionSource) -> {
+ onToDesktop(taskId, desktopModeTransitionSource);
+ return Unit.INSTANCE;
+ });
+ }
}
@Override
@@ -495,6 +517,12 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
mWindowDecorByTaskId.remove(taskInfo.taskId);
}
+ private void openHandleMenu(int taskId) {
+ final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId);
+ decoration.createHandleMenu(checkNumberOfOtherInstances(decoration.mTaskInfo)
+ >= MANAGE_WINDOWS_MINIMUM_INSTANCES);
+ }
+
private void onMaximizeOrRestore(int taskId, String source) {
final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId);
if (decoration == null) {
@@ -720,8 +748,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
} else if (id == R.id.caption_handle || id == R.id.open_menu_button) {
if (!decoration.isHandleMenuActive()) {
moveTaskToFront(decoration.mTaskInfo);
- decoration.createHandleMenu(checkNumberOfOtherInstances(decoration.mTaskInfo)
- >= MANAGE_WINDOWS_MINIMUM_INSTANCES);
+ openHandleMenu(mTaskId);
}
} else if (id == R.id.maximize_window) {
// TODO(b/346441962): move click detection logic into the decor's
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationControllerTest.kt
index aa8f911c4df2..aad31a6d57ba 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/education/AppHandleEducationControllerTest.kt
@@ -31,6 +31,7 @@ import com.android.wm.shell.desktopmode.education.AppHandleEducationController.C
import com.android.wm.shell.desktopmode.education.AppHandleEducationController.Companion.APP_HANDLE_EDUCATION_TIMEOUT_MILLIS
import com.android.wm.shell.desktopmode.education.data.AppHandleEducationDatastoreRepository
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
+import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource
import com.android.wm.shell.util.createAppHandleState
import com.android.wm.shell.util.createAppHeaderState
import com.android.wm.shell.util.createWindowingEducationProto
@@ -53,6 +54,7 @@ import org.mockito.MockitoAnnotations
import org.mockito.kotlin.any
import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.atLeastOnce
+import org.mockito.kotlin.mock
import org.mockito.kotlin.never
import org.mockito.kotlin.times
import org.mockito.kotlin.verify
@@ -337,6 +339,51 @@ class AppHandleEducationControllerTest : ShellTestCase() {
verify(mockTooltipController, times(2)).showEducationTooltip(any(), any())
}
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION)
+ fun setAppHandleEducationTooltipCallbacks_onAppHandleTooltipClicked_callbackInvoked() =
+ testScope.runTest {
+ // App handle is visible. Should show education tooltip.
+ setShouldShowAppHandleEducation(true)
+ val mockOpenHandleMenuCallback: (Int) -> Unit = mock()
+ val mockToDesktopModeCallback: (Int, DesktopModeTransitionSource) -> Unit = mock()
+ educationController.setAppHandleEducationTooltipCallbacks(
+ mockOpenHandleMenuCallback, mockToDesktopModeCallback)
+ // Simulate app handle visible.
+ testCaptionStateFlow.value = createAppHandleState()
+ // Wait for first tooltip to showup.
+ waitForBufferDelay()
+
+ verify(mockTooltipController, atLeastOnce())
+ .showEducationTooltip(educationConfigCaptor.capture(), any())
+ educationConfigCaptor.lastValue.onEducationClickAction.invoke()
+
+ verify(mockOpenHandleMenuCallback, times(1)).invoke(any())
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION)
+ fun setAppHandleEducationTooltipCallbacks_onWindowingImageButtonTooltipClicked_callbackInvoked() =
+ testScope.runTest {
+ // After first tooltip is dismissed, app handle is expanded. Should show second education
+ // tooltip.
+ showAndDismissFirstTooltip()
+ val mockOpenHandleMenuCallback: (Int) -> Unit = mock()
+ val mockToDesktopModeCallback: (Int, DesktopModeTransitionSource) -> Unit = mock()
+ educationController.setAppHandleEducationTooltipCallbacks(
+ mockOpenHandleMenuCallback, mockToDesktopModeCallback)
+ // Simulate app handle expanded.
+ testCaptionStateFlow.value = createAppHandleState(isHandleMenuExpanded = true)
+ // Wait for next tooltip to showup.
+ waitForBufferDelay()
+
+ verify(mockTooltipController, atLeastOnce())
+ .showEducationTooltip(educationConfigCaptor.capture(), any())
+ educationConfigCaptor.lastValue.onEducationClickAction.invoke()
+
+ verify(mockToDesktopModeCallback, times(1)).invoke(any(), any())
+ }
+
private suspend fun TestScope.showAndDismissFirstTooltip() {
setShouldShowAppHandleEducation(true)
// Simulate app handle visible.
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
index 3051714b5ae8..9aa6a52fd851 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
@@ -64,6 +64,7 @@ import android.widget.Toast
import android.window.WindowContainerTransaction
import android.window.WindowContainerTransaction.HierarchyOp
import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean
import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn
import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
import com.android.dx.mockito.inline.extended.StaticMockitoSession
@@ -89,6 +90,7 @@ 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.WindowDecorCaptionHandleRepository
+import com.android.wm.shell.desktopmode.education.AppHandleEducationController
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource
@@ -105,6 +107,7 @@ import java.util.function.Consumer
import java.util.function.Supplier
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Before
@@ -136,6 +139,7 @@ import org.mockito.quality.Strictness
* Tests of [DesktopModeWindowDecorViewModel]
* Usage: atest WMShellUnitTests:DesktopModeWindowDecorViewModelTests
*/
+@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidTestingRunner::class)
@RunWithLooper
@@ -184,6 +188,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() {
@Mock private lateinit var mockTaskPositionerFactory:
DesktopModeWindowDecorViewModel.TaskPositionerFactory
@Mock private lateinit var mockTaskPositioner: TaskPositioner
+ @Mock private lateinit var mockAppHandleEducationController: AppHandleEducationController
@Mock private lateinit var mockCaptionHandleRepository: WindowDecorCaptionHandleRepository
private lateinit var spyContext: TestableContext
@@ -242,6 +247,7 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() {
windowDecorByTaskIdSpy,
mockInteractionJankMonitor,
Optional.of(mockTasksLimiter),
+ mockAppHandleEducationController,
mockCaptionHandleRepository,
Optional.of(mockActivityOrientationChangeHandler),
mockTaskPositionerFactory
@@ -957,6 +963,83 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() {
}, eq(mockUserHandle))
}
+ @OptIn(ExperimentalCoroutinesApi::class)
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION)
+ fun testDecor_createWindowDecoration_setsAppHandleEducationTooltipClickCallbacks() {
+ whenever(DesktopModeStatus.canEnterDesktopMode(any())).thenReturn(true)
+
+ shellInit.init()
+
+ verify(
+ mockAppHandleEducationController,
+ times(1)
+ ).setAppHandleEducationTooltipCallbacks(any(), any())
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION)
+ fun testDecor_invokeOpenHandleMenuCallback_openHandleMenu() {
+ whenever(DesktopModeStatus.canEnterDesktopMode(any())).thenReturn(true)
+ val task = createTask(windowingMode = WINDOWING_MODE_FREEFORM)
+ val decor = setUpMockDecorationForTask(task)
+ val openHandleMenuCallbackCaptor = argumentCaptor<(Int) -> Unit>()
+ // Set task as gmail
+ val gmailPackageName = "com.google.android.gm"
+ val baseComponent = ComponentName(gmailPackageName, /* class */ "")
+ task.baseActivity = baseComponent
+
+ onTaskOpening(task)
+ verify(
+ mockAppHandleEducationController,
+ times(1)
+ ).setAppHandleEducationTooltipCallbacks(openHandleMenuCallbackCaptor.capture(), any())
+ openHandleMenuCallbackCaptor.lastValue.invoke(task.taskId)
+
+ verify(decor, times(1)).createHandleMenu(anyBoolean())
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION)
+ fun testDecor_openTaskWithFlagDisabled_doNotOpenHandleMenu() {
+ whenever(DesktopModeStatus.canEnterDesktopMode(any())).thenReturn(true)
+ val task = createTask(windowingMode = WINDOWING_MODE_FREEFORM)
+ setUpMockDecorationForTask(task)
+ val openHandleMenuCallbackCaptor = argumentCaptor<(Int) -> Unit>()
+ // Set task as gmail
+ val gmailPackageName = "com.google.android.gm"
+ val baseComponent = ComponentName(gmailPackageName, /* class */ "")
+ task.baseActivity = baseComponent
+
+ onTaskOpening(task)
+ verify(
+ mockAppHandleEducationController,
+ never()
+ ).setAppHandleEducationTooltipCallbacks(openHandleMenuCallbackCaptor.capture(), any())
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_HANDLE_EDUCATION)
+ fun testDecor_invokeOnToDesktopCallback_setsAppHandleEducationTooltipClickCallbacks() {
+ whenever(DesktopModeStatus.canEnterDesktopMode(any())).thenReturn(true)
+ val task = createTask(windowingMode = WINDOWING_MODE_FREEFORM)
+ setUpMockDecorationsForTasks(task)
+ onTaskOpening(task)
+ val onToDesktopCallbackCaptor = argumentCaptor<(Int, DesktopModeTransitionSource) -> Unit>()
+
+ verify(
+ mockAppHandleEducationController,
+ times(1)
+ ).setAppHandleEducationTooltipCallbacks(any(), onToDesktopCallbackCaptor.capture())
+ onToDesktopCallbackCaptor.lastValue.invoke(
+ task.taskId,
+ DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON
+ )
+
+ verify(mockDesktopTasksController, times(1))
+ .moveTaskToDesktop(any(), any(), any())
+ }
+
@Test
fun testOnDisplayRotation_tasksOutOfValidArea_taskBoundsUpdated() {
val task = createTask(focused = true, windowingMode = WINDOWING_MODE_FREEFORM)