Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 13409d5d authored by Eric Sum's avatar Eric Sum
Browse files

Add ACTION_DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE latency.

This measures the delay from when the user closes or minimizes
the last open window in desktop mode until the animation to exit
desktop mode draws its first frame.

Flag: EXEMPT metric change

Bug: 390544490
Test: Run `statsd_testdrive 306` and ensure that latency metric is
      reported.
Change-Id: I6e9f5c248c57d6094ad6472506d93c9eefba5cb4
parent edcbb43a
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPOR
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_MENU;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_DESKTOP_MODE_EXIT_MODE;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_EXPAND_PANEL;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_FACE_WAKE_AND_UNLOCK;
import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_FINGERPRINT_WAKE_AND_UNLOCK;
@@ -301,6 +302,14 @@ public class LatencyTracker {
     */
    public static final int ACTION_DESKTOP_MODE_EXIT_MODE = 32;

    /**
     * Time it takes for the "exit desktop" mode animation to begin after closing the last window.
     * <p>
     * Starts when the user provides input to either close or minimize the last window in desktop
     * mode. Ends when the animation to exit desktop mode is about to draw its first frame.
     */
    public static final int ACTION_DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE = 33;

    private static final int[] ACTIONS_ALL = {
        ACTION_EXPAND_PANEL,
        ACTION_TOGGLE_RECENTS,
@@ -335,6 +344,7 @@ public class LatencyTracker {
        ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG,
        ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_MENU,
        ACTION_DESKTOP_MODE_EXIT_MODE,
        ACTION_DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE,
    };

    /** @hide */
@@ -372,6 +382,7 @@ public class LatencyTracker {
        ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG,
        ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_MENU,
        ACTION_DESKTOP_MODE_EXIT_MODE,
        ACTION_DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface Action {}
@@ -411,6 +422,7 @@ public class LatencyTracker {
            UIACTION_LATENCY_REPORTED__ACTION__ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG,
            UIACTION_LATENCY_REPORTED__ACTION__ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_MENU,
            UIACTION_LATENCY_REPORTED__ACTION__ACTION_DESKTOP_MODE_EXIT_MODE,
            UIACTION_LATENCY_REPORTED__ACTION__ACTION_DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE,
    };

    private final Object mLock = new Object();
@@ -617,6 +629,8 @@ public class LatencyTracker {
                return "ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_MENU";
            case UIACTION_LATENCY_REPORTED__ACTION__ACTION_DESKTOP_MODE_EXIT_MODE:
                return "ACTION_DESKTOP_MODE_EXIT_MODE";
            case UIACTION_LATENCY_REPORTED__ACTION__ACTION_DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE:
                return "ACTION_DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE";
            default:
                throw new IllegalArgumentException("Invalid action");
        }
+18 −10
Original line number Diff line number Diff line
@@ -234,6 +234,7 @@ class DesktopTasksController(
    private var userId: Int
    private val desktopModeShellCommandHandler: DesktopModeShellCommandHandler =
        DesktopModeShellCommandHandler(this, focusTransitionObserver)
    private val latencyTracker: LatencyTracker

    private val mOnAnimationFinishedCallback = { releaseVisualIndicator() }
    private lateinit var snapEventHandler: SnapEventHandler
@@ -283,6 +284,7 @@ class DesktopTasksController(
        }
        userId = ActivityManager.getCurrentUser()
        taskRepository = userRepositories.getProfile(userId)
        latencyTracker = LatencyTracker.getInstance(context)

        if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
            desktopRepositoryInitializer.deskRecreationFactory =
@@ -779,8 +781,7 @@ class DesktopTasksController(
                taskRepository.setActiveDesk(displayId = taskInfo.displayId, deskId = deskId)
            }
        } else {
            LatencyTracker.getInstance(context)
                .onActionCancel(LatencyTracker.ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG)
            latencyTracker.onActionCancel(LatencyTracker.ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG)
        }
    }

@@ -1021,7 +1022,8 @@ class DesktopTasksController(
            && !DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue
        ) {
            desktopModeEnterExitTransitionListener?.onExitDesktopModeTransitionStarted(
                FULLSCREEN_ANIMATION_DURATION
                FULLSCREEN_ANIMATION_DURATION,
                shouldEndUpAtHome = false,
            )
        }
    }
@@ -1982,7 +1984,8 @@ class DesktopTasksController(
    ): RunOnTransitStart? {
        if (!willExitDesktop) return null
        desktopModeEnterExitTransitionListener?.onExitDesktopModeTransitionStarted(
            FULLSCREEN_ANIMATION_DURATION
            FULLSCREEN_ANIMATION_DURATION,
            shouldEndUpAtHome,
        )
        // No need to clean up the wallpaper / reorder home when coming from a recents transition.
        if (
@@ -3481,8 +3484,9 @@ class DesktopTasksController(
        val indicatorType = indicator.updateIndicatorType(inputCoordinates)
        when (indicatorType) {
            IndicatorType.TO_DESKTOP_INDICATOR -> {
                LatencyTracker.getInstance(context)
                    .onActionStart(LatencyTracker.ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG)
                latencyTracker.onActionStart(
                    LatencyTracker.ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG
                )
                // Start a new jank interaction for the drag release to desktop window animation.
                interactionJankMonitor.begin(
                    taskSurface,
@@ -3861,14 +3865,18 @@ class DesktopTasksController(
                    }
                }

                override fun onExitDesktopModeTransitionStarted(transitionDuration: Int) {
                override fun onExitDesktopModeTransitionStarted(
                    transitionDuration: Int,
                    shouldEndUpAtHome: Boolean,
                ) {
                    ProtoLog.v(
                        WM_SHELL_DESKTOP_MODE,
                        "IDesktopModeImpl: onExitDesktopModeTransitionStarted transitionTime=%s",
                        "IDesktopModeImpl: onExitDesktopModeTransitionStarted transitionTime=%s shouldEndUpAtHome=%b",
                        transitionDuration,
                        shouldEndUpAtHome,
                    )
                    remoteListener.call { l ->
                        l.onExitDesktopModeTransitionStarted(transitionDuration)
                        l.onExitDesktopModeTransitionStarted(transitionDuration, shouldEndUpAtHome)
                    }
                }
            }
@@ -4073,7 +4081,7 @@ class DesktopTasksController(
        fun onEnterDesktopModeTransitionStarted(transitionDuration: Int)

        /** [transitionDuration] time it takes to run exit desktop mode transition */
        fun onExitDesktopModeTransitionStarted(transitionDuration: Int)
        fun onExitDesktopModeTransitionStarted(transitionDuration: Int, shouldEndUpAtHome: Boolean)
    }

    /** The positions on a screen that a task can snap to. */
+5 −2
Original line number Diff line number Diff line
@@ -45,8 +45,11 @@ oneway interface IDesktopTaskListener {
    /** Entering desktop mode transition is started, send the signal with transition duration. */
    void onEnterDesktopModeTransitionStarted(int transitionDuration);

    /** Exiting desktop mode transition is started, send the signal with transition duration. */
    void onExitDesktopModeTransitionStarted(int transitionDuration);
    /** Exiting desktop mode transition is started, send the signal with transition duration
     *  and whether the display will end up at the home activity (as opposed to an app's full screen
     *  mode).
     */
    void onExitDesktopModeTransitionStarted(int transitionDuration, boolean shouldEndUpAtHome);

    /**
     * Called when the conditions that allow the creation of a new desk changes. This is a global
+46 −47
Original line number Diff line number Diff line
@@ -2257,7 +2257,10 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
        controller.moveToFullscreen(task.taskId, transitionSource = UNKNOWN)
        val wct = getLatestExitDesktopWct()
        verify(desktopModeEnterExitTransitionListener, times(1))
            .onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
            .onExitDesktopModeTransitionStarted(
                FULLSCREEN_ANIMATION_DURATION,
                shouldEndUpAtHome = false,
            )
        assertThat(wct.changes[task.token.asBinder()]?.windowingMode)
            .isEqualTo(WINDOWING_MODE_UNDEFINED)
    }
@@ -2279,7 +2282,10 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
        val wct = getLatestExitDesktopWct()
        val taskChange = assertNotNull(wct.changes[task.token.asBinder()])
        verify(desktopModeEnterExitTransitionListener)
            .onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
            .onExitDesktopModeTransitionStarted(
                FULLSCREEN_ANIMATION_DURATION,
                shouldEndUpAtHome = false,
            )
        assertThat(taskChange.windowingMode).isEqualTo(WINDOWING_MODE_UNDEFINED)
        assertThat(wct.hierarchyOps).hasSize(3)
        // Removes wallpaper activity when leaving desktop
@@ -2308,7 +2314,10 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
        val wct = getLatestExitDesktopWct()
        val taskChange = assertNotNull(wct.changes[task.token.asBinder()])
        verify(desktopModeEnterExitTransitionListener)
            .onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
            .onExitDesktopModeTransitionStarted(
                FULLSCREEN_ANIMATION_DURATION,
                shouldEndUpAtHome = false,
            )
        assertThat(taskChange.windowingMode).isEqualTo(WINDOWING_MODE_UNDEFINED)
        // Removes wallpaper activity when leaving desktop
        wct.assertReorder(wallpaperToken, toTop = false)
@@ -2333,7 +2342,10 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
        val wct = getLatestExitDesktopWct()
        val taskChange = assertNotNull(wct.changes[task.token.asBinder()])
        verify(desktopModeEnterExitTransitionListener)
            .onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
            .onExitDesktopModeTransitionStarted(
                FULLSCREEN_ANIMATION_DURATION,
                shouldEndUpAtHome = false,
            )
        assertThat(taskChange.windowingMode).isEqualTo(WINDOWING_MODE_UNDEFINED)
        // Moves home task behind the fullscreen task
        val homeReorderIndex = wct.indexOfReorder(homeTask, toTop = true)
@@ -2358,7 +2370,10 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()

        val wct = getLatestExitDesktopWct()
        verify(desktopModeEnterExitTransitionListener)
            .onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
            .onExitDesktopModeTransitionStarted(
                FULLSCREEN_ANIMATION_DURATION,
                shouldEndUpAtHome = false,
            )
        // Removes wallpaper activity when leaving desktop but doesn't reorder home or the task
        wct.assertReorder(wallpaperToken, toTop = false)
        wct.assertWithoutHop(ReorderPredicate(homeTask.token, toTop = null))
@@ -2374,7 +2389,10 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
        assertThat(wct.changes[task.token.asBinder()]?.windowingMode)
            .isEqualTo(WINDOWING_MODE_FULLSCREEN)
        verify(desktopModeEnterExitTransitionListener)
            .onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
            .onExitDesktopModeTransitionStarted(
                FULLSCREEN_ANIMATION_DURATION,
                shouldEndUpAtHome = false,
            )
    }

    @Test
@@ -2396,7 +2414,10 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
        val taskChange = assertNotNull(wct.changes[task.token.asBinder()])
        assertThat(taskChange.windowingMode).isEqualTo(WINDOWING_MODE_FULLSCREEN)
        verify(desktopModeEnterExitTransitionListener)
            .onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
            .onExitDesktopModeTransitionStarted(
                FULLSCREEN_ANIMATION_DURATION,
                shouldEndUpAtHome = false,
            )
        assertThat(wct.hierarchyOps).hasSize(3)
        // Removes wallpaper activity when leaving desktop
        wct.assertReorderAt(index = 0, wallpaperToken, toTop = false)
@@ -2425,7 +2446,10 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
        val taskChange = assertNotNull(wct.changes[task.token.asBinder()])
        assertThat(taskChange.windowingMode).isEqualTo(WINDOWING_MODE_FULLSCREEN)
        verify(desktopModeEnterExitTransitionListener)
            .onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
            .onExitDesktopModeTransitionStarted(
                FULLSCREEN_ANIMATION_DURATION,
                shouldEndUpAtHome = false,
            )
        // Removes wallpaper activity when leaving desktop
        wct.assertReorder(wallpaperToken, toTop = false)
    }
@@ -2451,7 +2475,10 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
        val taskChange = assertNotNull(wct.changes[task.token.asBinder()])
        assertThat(taskChange.windowingMode).isEqualTo(WINDOWING_MODE_FULLSCREEN)
        verify(desktopModeEnterExitTransitionListener)
            .onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
            .onExitDesktopModeTransitionStarted(
                FULLSCREEN_ANIMATION_DURATION,
                shouldEndUpAtHome = false,
            )
        // Moves home task behind the fullscreen task
        val homeReorderIndex = wct.indexOfReorder(homeTask, toTop = true)
        val fullscreenReorderIndex = wct.indexOfReorder(task, toTop = true)
@@ -2482,7 +2509,10 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
        val task1Change = assertNotNull(wct.changes[task1.token.asBinder()])
        assertThat(task1Change.windowingMode).isEqualTo(WINDOWING_MODE_UNDEFINED)
        verify(desktopModeEnterExitTransitionListener)
            .onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
            .onExitDesktopModeTransitionStarted(
                FULLSCREEN_ANIMATION_DURATION,
                shouldEndUpAtHome = false,
            )
        // Does not remove wallpaper activity, as desktop still has a visible desktop task
        assertThat(wct.hierarchyOps).hasSize(2)
        // Moves home task behind the fullscreen task
@@ -2508,7 +2538,10 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
            assertThat(changes.keys).doesNotContain(taskSecondDisplay.token.asBinder())
        }
        verify(desktopModeEnterExitTransitionListener)
            .onExitDesktopModeTransitionStarted(FULLSCREEN_ANIMATION_DURATION)
            .onExitDesktopModeTransitionStarted(
                FULLSCREEN_ANIMATION_DURATION,
                shouldEndUpAtHome = false,
            )
    }

    @Test
@@ -6216,41 +6249,6 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
            )
    }

    @Test
    @EnableFlags(
        Flags.FLAG_ENABLE_CONNECTED_DISPLAYS_WINDOW_DRAG,
        Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND,
    )
    fun onDesktopDragEnd_noIndicatorAndMoveToNewDisplay_reparentToDesk() {
        val deskId = 5
        val task = setUpFreeformTask()
        val spyController = spy(controller)
        val mockSurface = mock(SurfaceControl::class.java)
        val mockDisplayLayout = mock(DisplayLayout::class.java)
        taskRepository.addDesk(displayId = SECONDARY_DISPLAY_ID, deskId = deskId)
        whenever(displayController.getDisplayLayout(task.displayId)).thenReturn(mockDisplayLayout)
        whenever(mockDisplayLayout.stableInsets()).thenReturn(Rect(0, 100, 2000, 2000))
        spyController.onDragPositioningMove(task, mockSurface, 200f, Rect(100, 200, 500, 1000))

        val currentDragBounds = Rect(100, 200, 500, 1000)
        whenever(spyController.getVisualIndicator()).thenReturn(desktopModeVisualIndicator)
        whenever(desktopModeVisualIndicator.updateIndicatorType(anyOrNull()))
            .thenReturn(DesktopModeVisualIndicator.IndicatorType.NO_INDICATOR)
        whenever(motionEvent.displayId).thenReturn(SECONDARY_DISPLAY_ID)

        spyController.onDragPositioningEnd(
            task,
            mockSurface,
            inputCoordinate = PointF(200f, 300f),
            currentDragBounds,
            validDragArea = Rect(0, 50, 2000, 2000),
            dragStartBounds = Rect(),
            motionEvent,
        )

        verify(desksOrganizer).moveTaskToDesk(any(), eq(deskId), eq(task))
    }

    @Test
    fun onDesktopDragEnd_fullscreenIndicator_dragToExitDesktop() {
        val task = setUpFreeformTask(bounds = Rect(0, 0, 100, 100))
@@ -7949,7 +7947,8 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
            returnToApp = false,
        )

        verify(desktopModeEnterExitTransitionListener).onExitDesktopModeTransitionStarted(any())
        verify(desktopModeEnterExitTransitionListener)
            .onExitDesktopModeTransitionStarted(any(), any())
    }

    @Test