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

Commit 04a013d4 authored by Devarshi Bhatt's avatar Devarshi Bhatt Committed by Android (Google) Code Review
Browse files

Merge "Add instrumentation for window minimize with app open CUJ." into main

parents 69d5f012 30d057ed
Loading
Loading
Loading
Loading
+9 −2
Original line number Diff line number Diff line
@@ -566,7 +566,8 @@ public abstract class WMShellModule {
            Context context,
            Transitions transitions,
            @DynamicOverride DesktopModeTaskRepository desktopModeTaskRepository,
            ShellTaskOrganizer shellTaskOrganizer) {
            ShellTaskOrganizer shellTaskOrganizer,
            InteractionJankMonitor interactionJankMonitor) {
        int maxTaskLimit = DesktopModeStatus.getMaxTaskLimit(context);
        if (!DesktopModeStatus.canEnterDesktopMode(context)
                || !ENABLE_DESKTOP_WINDOWING_TASK_LIMIT.isEnabled(context)
@@ -575,7 +576,13 @@ public abstract class WMShellModule {
        }
        return Optional.of(
                new DesktopTasksLimiter(
                        transitions, desktopModeTaskRepository, shellTaskOrganizer, maxTaskLimit));
                        transitions,
                        desktopModeTaskRepository,
                        shellTaskOrganizer,
                        maxTaskLimit,
                        interactionJankMonitor,
                        context)
        );
    }


+35 −3
Original line number Diff line number Diff line
@@ -17,12 +17,15 @@
package com.android.wm.shell.desktopmode

import android.app.ActivityManager.RunningTaskInfo
import android.content.Context
import android.os.IBinder
import android.view.SurfaceControl
import android.view.WindowManager.TRANSIT_TO_BACK
import android.window.TransitionInfo
import android.window.WindowContainerTransaction
import androidx.annotation.VisibleForTesting
import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_MINIMIZE_WINDOW
import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.protolog.ShellProtoLogGroup
@@ -41,6 +44,8 @@ class DesktopTasksLimiter (
        private val taskRepository: DesktopModeTaskRepository,
        private val shellTaskOrganizer: ShellTaskOrganizer,
        private val maxTasksLimit: Int,
        private val interactionJankMonitor: InteractionJankMonitor,
        private val context: Context
) {
    private val minimizeTransitionObserver = MinimizeTransitionObserver()
    @VisibleForTesting
@@ -57,11 +62,16 @@ class DesktopTasksLimiter (
            "DesktopTasksLimiter: starting limiter with a maximum of %d tasks", maxTasksLimit)
    }

    private data class TaskDetails (val displayId: Int, val taskId: Int)
    private data class TaskDetails(
        val displayId: Int,
        val taskId: Int,
        var transitionInfo: TransitionInfo?
    )

    // TODO(b/333018485): replace this observer when implementing the minimize-animation
    private inner class MinimizeTransitionObserver : TransitionObserver {
        private val mPendingTransitionTokensAndTasks = mutableMapOf<IBinder, TaskDetails>()
        private val mActiveTransitionTokensAndTasks = mutableMapOf<IBinder, TaskDetails>()

        fun addPendingTransitionToken(transition: IBinder, taskDetails: TaskDetails) {
            mPendingTransitionTokensAndTasks[transition] = taskDetails
@@ -74,6 +84,8 @@ class DesktopTasksLimiter (
            finishTransaction: SurfaceControl.Transaction
        ) {
            val taskToMinimize = mPendingTransitionTokensAndTasks.remove(transition) ?: return
            taskToMinimize.transitionInfo = info
            mActiveTransitionTokensAndTasks[transition] = taskToMinimize

            if (!taskRepository.isActiveTask(taskToMinimize.taskId)) return

@@ -84,6 +96,7 @@ class DesktopTasksLimiter (
                        taskToMinimize.taskId)
                return
            }

            this@DesktopTasksLimiter.markTaskMinimized(
                    taskToMinimize.displayId, taskToMinimize.taskId)
        }
@@ -107,9 +120,21 @@ class DesktopTasksLimiter (
            return taskChange.mode == TRANSIT_TO_BACK
        }

        override fun onTransitionStarting(transition: IBinder) {}
        override fun onTransitionStarting(transition: IBinder) {
            val mActiveTaskDetails = mActiveTransitionTokensAndTasks[transition]
            if (mActiveTaskDetails != null && mActiveTaskDetails.transitionInfo != null) {
                // Begin minimize window CUJ instrumentation.
                interactionJankMonitor.begin(
                    mActiveTaskDetails.transitionInfo?.rootLeash, context,
                    CUJ_DESKTOP_MODE_MINIMIZE_WINDOW
                )
            }
        }

        override fun onTransitionMerged(merged: IBinder, playing: IBinder) {
            if (mActiveTransitionTokensAndTasks.remove(merged) != null) {
                interactionJankMonitor.end(CUJ_DESKTOP_MODE_MINIMIZE_WINDOW)
            }
            mPendingTransitionTokensAndTasks.remove(merged)?.let { taskToTransfer ->
                mPendingTransitionTokensAndTasks[playing] = taskToTransfer
            }
@@ -119,6 +144,13 @@ class DesktopTasksLimiter (
            ProtoLog.v(
                    ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
                    "DesktopTasksLimiter: transition %s finished", transition)
            if (mActiveTransitionTokensAndTasks.remove(transition) != null) {
                if (aborted) {
                    interactionJankMonitor.cancel(CUJ_DESKTOP_MODE_MINIMIZE_WINDOW)
                } else {
                    interactionJankMonitor.end(CUJ_DESKTOP_MODE_MINIMIZE_WINDOW)
                }
            }
            mPendingTransitionTokensAndTasks.remove(transition)
        }
    }
@@ -196,7 +228,7 @@ class DesktopTasksLimiter (
     */
    fun addPendingMinimizeChange(transition: IBinder, displayId: Int, taskId: Int) {
        minimizeTransitionObserver.addPendingTransitionToken(
                transition, TaskDetails(displayId, taskId))
                transition, TaskDetails(displayId, taskId, transitionInfo = null))
    }

    /**
+2 −1
Original line number Diff line number Diff line
@@ -211,7 +211,8 @@ class DesktopTasksControllerTest : ShellTestCase() {
            taskRepository,
            shellTaskOrganizer,
            MAX_TASK_LIMIT,
        )
            mockInteractionJankMonitor,
            mContext)

    whenever(shellTaskOrganizer.getRunningTasks(anyInt())).thenAnswer { runningTasks }
    whenever(transitions.startTransition(anyInt(), any(), isNull())).thenAnswer { Binder() }
+98 −4
Original line number Diff line number Diff line
@@ -30,6 +30,8 @@ import androidx.test.filters.SmallTest
import com.android.dx.mockito.inline.extended.ExtendedMockito
import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn
import com.android.dx.mockito.inline.extended.StaticMockitoSession
import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_MINIMIZE_WINDOW
import com.android.internal.jank.InteractionJankMonitor
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.ShellTestCase
import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask
@@ -47,6 +49,8 @@ import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.any
import org.mockito.Mockito.`when`
import org.mockito.kotlin.eq
import org.mockito.kotlin.verify
import org.mockito.quality.Strictness


@@ -65,6 +69,7 @@ class DesktopTasksLimiterTest : ShellTestCase() {

    @Mock lateinit var shellTaskOrganizer: ShellTaskOrganizer
    @Mock lateinit var transitions: Transitions
    @Mock lateinit var interactionJankMonitor: InteractionJankMonitor

    private lateinit var mockitoSession: StaticMockitoSession
    private lateinit var desktopTasksLimiter: DesktopTasksLimiter
@@ -79,7 +84,8 @@ class DesktopTasksLimiterTest : ShellTestCase() {
        desktopTaskRepo = DesktopModeTaskRepository()

        desktopTasksLimiter =
            DesktopTasksLimiter(transitions, desktopTaskRepo, shellTaskOrganizer, MAX_TASK_LIMIT)
            DesktopTasksLimiter(transitions, desktopTaskRepo, shellTaskOrganizer, MAX_TASK_LIMIT,
                interactionJankMonitor, mContext)
    }

    @After
@@ -90,14 +96,16 @@ class DesktopTasksLimiterTest : ShellTestCase() {
    @Test
    fun createDesktopTasksLimiter_withZeroLimit_shouldThrow() {
        assertFailsWith<IllegalArgumentException> {
            DesktopTasksLimiter(transitions, desktopTaskRepo, shellTaskOrganizer, 0)
            DesktopTasksLimiter(transitions, desktopTaskRepo, shellTaskOrganizer, 0,
                interactionJankMonitor, mContext)
        }
    }

    @Test
    fun createDesktopTasksLimiter_withNegativeLimit_shouldThrow() {
        assertFailsWith<IllegalArgumentException> {
            DesktopTasksLimiter(transitions, desktopTaskRepo, shellTaskOrganizer, -5)
            DesktopTasksLimiter(transitions, desktopTaskRepo, shellTaskOrganizer, -5,
                interactionJankMonitor, mContext)
        }
    }

@@ -325,7 +333,8 @@ class DesktopTasksLimiterTest : ShellTestCase() {
    @Test
    fun getTaskToMinimizeIfNeeded_tasksAboveLimit_otherLimit_returnsBackTask() {
        desktopTasksLimiter =
            DesktopTasksLimiter(transitions, desktopTaskRepo, shellTaskOrganizer, MAX_TASK_LIMIT2)
            DesktopTasksLimiter(transitions, desktopTaskRepo, shellTaskOrganizer, MAX_TASK_LIMIT2,
                interactionJankMonitor, mContext)
        val tasks = (1..MAX_TASK_LIMIT2 + 1).map { setUpFreeformTask() }

        val minimizedTask = desktopTasksLimiter.getTaskToMinimizeIfNeeded(
@@ -347,6 +356,91 @@ class DesktopTasksLimiterTest : ShellTestCase() {
        assertThat(minimizedTask).isEqualTo(tasks.last())
    }

    @Test
    fun minimizeTransitionReadyAndFinished_logsJankInstrumentationBeginAndEnd() {
        (1..<MAX_TASK_LIMIT).forEach { _ -> setUpFreeformTask() }
        val transition = Binder()
        val task = setUpFreeformTask()
        desktopTasksLimiter.addPendingMinimizeChange(
            transition, displayId = DEFAULT_DISPLAY, taskId = task.taskId)

        desktopTasksLimiter.getTransitionObserver().onTransitionReady(
            transition,
            TransitionInfoBuilder(TRANSIT_OPEN).build(),
            StubTransaction() /* startTransaction */,
            StubTransaction() /* finishTransaction */)

        desktopTasksLimiter.getTransitionObserver().onTransitionStarting(transition)

        verify(interactionJankMonitor).begin(
            any(),
            eq(mContext),
            eq(CUJ_DESKTOP_MODE_MINIMIZE_WINDOW))

        desktopTasksLimiter.getTransitionObserver().onTransitionFinished(
            transition,
            /* aborted = */ false)

        verify(interactionJankMonitor).end(eq(CUJ_DESKTOP_MODE_MINIMIZE_WINDOW))
    }

    @Test
    fun minimizeTransitionReadyAndAborted_logsJankInstrumentationBeginAndCancel() {
        (1..<MAX_TASK_LIMIT).forEach { _ -> setUpFreeformTask() }
        val transition = Binder()
        val task = setUpFreeformTask()
        desktopTasksLimiter.addPendingMinimizeChange(
            transition, displayId = DEFAULT_DISPLAY, taskId = task.taskId)

        desktopTasksLimiter.getTransitionObserver().onTransitionReady(
            transition,
            TransitionInfoBuilder(TRANSIT_OPEN).build(),
            StubTransaction() /* startTransaction */,
            StubTransaction() /* finishTransaction */)

        desktopTasksLimiter.getTransitionObserver().onTransitionStarting(transition)

        verify(interactionJankMonitor).begin(
            any(),
            eq(mContext),
            eq(CUJ_DESKTOP_MODE_MINIMIZE_WINDOW))

        desktopTasksLimiter.getTransitionObserver().onTransitionFinished(
            transition,
            /* aborted = */ true)

        verify(interactionJankMonitor).cancel(eq(CUJ_DESKTOP_MODE_MINIMIZE_WINDOW))
    }

    @Test
    fun minimizeTransitionReadyAndMerged_logsJankInstrumentationBeginAndEnd() {
        (1..<MAX_TASK_LIMIT).forEach { _ -> setUpFreeformTask() }
        val mergedTransition = Binder()
        val newTransition = Binder()
        val task = setUpFreeformTask()
        desktopTasksLimiter.addPendingMinimizeChange(
            mergedTransition, displayId = DEFAULT_DISPLAY, taskId = task.taskId)

        desktopTasksLimiter.getTransitionObserver().onTransitionReady(
            mergedTransition,
            TransitionInfoBuilder(TRANSIT_OPEN).build(),
            StubTransaction() /* startTransaction */,
            StubTransaction() /* finishTransaction */)

        desktopTasksLimiter.getTransitionObserver().onTransitionStarting(mergedTransition)

        verify(interactionJankMonitor).begin(
            any(),
            eq(mContext),
            eq(CUJ_DESKTOP_MODE_MINIMIZE_WINDOW))

        desktopTasksLimiter.getTransitionObserver().onTransitionMerged(
            mergedTransition,
            newTransition)

        verify(interactionJankMonitor).end(eq(CUJ_DESKTOP_MODE_MINIMIZE_WINDOW))
    }

    private fun setUpFreeformTask(
            displayId: Int = DEFAULT_DISPLAY,
    ): RunningTaskInfo {