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

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

Merge changes Ida3a640f,I2c3c689a into main

* changes:
  Add base scenario test for enter desktop mode with app handle menu.
  Add instrumentation for enter window mode with app handle menu CUJ.
parents 2cb43006 cb7746a5
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -573,8 +573,9 @@ public abstract class WMShellModule {
    @Provides
    static EnterDesktopTaskTransitionHandler provideEnterDesktopModeTaskTransitionHandler(
            Transitions transitions,
            Optional<DesktopTasksLimiter> desktopTasksLimiter) {
        return new EnterDesktopTaskTransitionHandler(transitions);
            Optional<DesktopTasksLimiter> desktopTasksLimiter,
            InteractionJankMonitor interactionJankMonitor) {
        return new EnterDesktopTaskTransitionHandler(transitions, interactionJankMonitor);
    }

    @WMSingleton
+8 −2
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.wm.shell.desktopmode;

import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;

import static com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_MODE_APP_HANDLE_MENU;
import static com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.getEnterTransitionType;
import static com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.isEnterDesktopModeTransition;

@@ -39,6 +40,7 @@ import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.android.internal.jank.InteractionJankMonitor;
import com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.windowdecor.OnTaskResizeAnimationListener;
@@ -60,18 +62,21 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
    public static final int FREEFORM_ANIMATION_DURATION = 336;

    private final List<IBinder> mPendingTransitionTokens = new ArrayList<>();
    private final InteractionJankMonitor mInteractionJankMonitor;

    private OnTaskResizeAnimationListener mOnTaskResizeAnimationListener;

    public EnterDesktopTaskTransitionHandler(
            Transitions transitions) {
        this(transitions, SurfaceControl.Transaction::new);
            Transitions transitions, InteractionJankMonitor interactionJankMonitor) {
        this(transitions, interactionJankMonitor, SurfaceControl.Transaction::new);
    }

    public EnterDesktopTaskTransitionHandler(
            Transitions transitions,
            InteractionJankMonitor interactionJankMonitor,
            Supplier<SurfaceControl.Transaction> supplier) {
        mTransitions = transitions;
        mInteractionJankMonitor = interactionJankMonitor;
        mTransactionSupplier = supplier;
    }

@@ -175,6 +180,7 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
                mOnTaskResizeAnimationListener.onAnimationEnd(taskInfo.taskId);
                mTransitions.getMainExecutor().execute(
                        () -> finishCallback.onTransitionFinished(null));
                mInteractionJankMonitor.end(CUJ_DESKTOP_MODE_ENTER_MODE_APP_HANDLE_MENU);
            }
        });
        animator.start();
+3 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_UP;
import static android.view.WindowInsets.Type.statusBars;

import static com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_MODE_APP_HANDLE_MENU;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.compatui.AppCompatUtils.isTopActivityExemptFromDesktopWindowing;
@@ -499,6 +500,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
                final WindowContainerTransaction wct = new WindowContainerTransaction();
                // App sometimes draws before the insets from WindowDecoration#relayout have
                // been added, so they must be added here
                mInteractionJankMonitor.begin(decoration.mTaskSurface, mContext,
                        CUJ_DESKTOP_MODE_ENTER_MODE_APP_HANDLE_MENU);
                mWindowDecorByTaskId.get(mTaskId).addCaptionInset(wct);
                mDesktopTasksController.moveToDesktop(mTaskId, wct,
                        DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON);
+59 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.wm.shell.flicker.service.desktopmode.scenarios

import android.app.Instrumentation
import android.tools.traces.parsers.WindowManagerStateHelper
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import com.android.launcher3.tapl.LauncherInstrumentation
import com.android.server.wm.flicker.helpers.DesktopModeAppHelper
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.window.flags.Flags
import org.junit.After
import org.junit.Assume
import org.junit.Before
import org.junit.Ignore
import org.junit.Test

/** Base test class for enter desktop with app handle menu CUJ. */
@Ignore("Base Test Class")
abstract class EnterDesktopWithAppHandleMenu {

    private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
    private val tapl = LauncherInstrumentation()
    private val wmHelper = WindowManagerStateHelper(instrumentation)
    private val device = UiDevice.getInstance(instrumentation)
    private val simpleAppHelper = SimpleAppHelper(instrumentation)
    private val testApp = DesktopModeAppHelper(simpleAppHelper)

    @Before
    fun setup() {
        Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
    }

    @Test
    open fun enterDesktopWithAppHandleMenu() {
        simpleAppHelper.launchViaIntent(wmHelper)
        testApp.enterDesktopModeFromAppHandleMenu(wmHelper, device)
    }

    @After
    fun teardown() {
        testApp.exit(wmHelper)
    }
}
+41 −11
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.wm.flicker.helpers

import android.graphics.Rect
import android.platform.uiautomator_helpers.DeviceHelpers
import android.tools.device.apphelpers.IStandardAppHelper
import android.tools.helpers.SYSTEMUI_PACKAGE
import android.tools.traces.parsers.WindowManagerStateHelper
@@ -26,6 +27,7 @@ import androidx.test.uiautomator.BySelector
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.UiObject2
import androidx.test.uiautomator.Until
import java.time.Duration

/**
 * Wrapper class around App helper classes. This class adds functionality to the apps that the
@@ -41,16 +43,6 @@ open class DesktopModeAppHelper(private val innerHelper: IStandardAppHelper) :
        RIGHT_BOTTOM
    }

    private val TIMEOUT_MS = 3_000L
    private val CAPTION = "desktop_mode_caption"
    private val CAPTION_HANDLE = "caption_handle"
    private val MAXIMIZE_BUTTON = "maximize_window"
    private val MAXIMIZE_BUTTON_VIEW = "maximize_button_view"
    private val CLOSE_BUTTON = "close_window"

    private val caption: BySelector
        get() = By.res(SYSTEMUI_PACKAGE, CAPTION)

    /** Wait for an app moved to desktop to finish its transition. */
    private fun waitForAppToMoveToDesktop(wmHelper: WindowManagerStateHelper) {
        wmHelper
@@ -123,7 +115,7 @@ open class DesktopModeAppHelper(private val innerHelper: IStandardAppHelper) :
        )
            error("expected a freeform window with caption but window is not in freeform mode")
        val captions =
            device.wait(Until.findObjects(caption), TIMEOUT_MS)
            device.wait(Until.findObjects(caption), TIMEOUT.toMillis())
                ?: error("Unable to find view $caption\n")

        return captions.find {
@@ -200,6 +192,33 @@ open class DesktopModeAppHelper(private val innerHelper: IStandardAppHelper) :
        device.drag(startX, startY, endX, endY, 100)
    }

    fun enterDesktopModeFromAppHandleMenu(
        wmHelper: WindowManagerStateHelper,
        device: UiDevice) {
        val windowRect = wmHelper.getWindowRegion(innerHelper).bounds
        val startX = windowRect.centerX()
        // Click a little under the top to prevent opening the notification shade.
        val startY = 10

        // Click on the app handle coordinates.
        device.click(startX, startY)
        wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify()

        val pill = getAppHandlePillForWindow()
        val desktopModeButton =
            pill
                ?.children
                ?.find { it.resourceName.endsWith(DESKTOP_MODE_BUTTON) }

        desktopModeButton?.click()
        wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify()
    }

    private fun getAppHandlePillForWindow(): UiObject2? {
        val pillContainer: BySelector = By.res(SYSTEMUI_PACKAGE, PILL_CONTAINER)
        return DeviceHelpers.waitForObj(pillContainer, TIMEOUT)
    }

    /** Wait for transition to full screen to finish. */
    private fun waitForTransitionToFullscreen(wmHelper: WindowManagerStateHelper) {
        wmHelper
@@ -208,4 +227,15 @@ open class DesktopModeAppHelper(private val innerHelper: IStandardAppHelper) :
            .withAppTransitionIdle()
            .waitForAndVerify()
    }

    private companion object {
        val TIMEOUT = Duration.ofSeconds(3)
        val CAPTION = "desktop_mode_caption"
        val MAXIMIZE_BUTTON_VIEW = "maximize_button_view"
        val CLOSE_BUTTON = "close_window"
        val PILL_CONTAINER = "windowing_pill"
        val DESKTOP_MODE_BUTTON = "desktop_button"
        val caption: BySelector
            get() = By.res(SYSTEMUI_PACKAGE, CAPTION)
    }
}