From 7789c0313837adaef0d420d2a2a06b2a06305475 Mon Sep 17 00:00:00 2001 From: Ikram Gabiyev Date: Tue, 28 Feb 2023 00:44:07 +0000 Subject: [PATCH] Implement drag then snap flicker test Add a flicker test for dragging the pip window away from the edge and verifying that it snaps back to that same edge Bug: 264555500 Test: atest WMShellFlickerTests:PipDragThenSnapTest Change-Id: I3397f7f47198b33f4d0250704ef5f2fd54446517 (cherry picked from commit d389b970582b78660021e0a6ec503a6e26eba044) --- .../shell/flicker/pip/PipDragThenSnapTest.kt | 95 +++++++++++++++++++ .../server/wm/flicker/helpers/PipAppHelper.kt | 69 +++++++++++++- 2 files changed, 162 insertions(+), 2 deletions(-) create mode 100644 libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt new file mode 100644 index 0000000000000..5cd66abf5012f --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2023 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.pip + +import android.platform.test.annotations.Postsubmit +import android.tools.common.Rotation +import android.tools.device.flicker.junit.FlickerParametersRunnerFactory +import android.graphics.Rect +import android.tools.device.flicker.legacy.FlickerBuilder +import android.tools.device.flicker.legacy.FlickerTest +import android.tools.device.flicker.legacy.FlickerTestFactory +import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule +import androidx.test.filters.RequiresDevice +import com.android.server.wm.flicker.helpers.setRotation +import com.android.server.wm.flicker.testapp.ActivityOptions +import org.junit.FixMethodOrder +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters +import org.junit.runners.Parameterized + +/** + * Test the snapping of a PIP window via dragging, releasing, and checking its final location. + */ +@RequiresDevice +@RunWith(Parameterized::class) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +class PipDragThenSnapTest(flicker: FlickerTest) : PipTransition(flicker){ + override val transition: FlickerBuilder.() -> Unit + get() = { + val stringExtras: Map = + mapOf(ActivityOptions.Pip.EXTRA_ENTER_PIP to "true") + + // cache the starting bounds here + val startBounds = Rect() + + setup { + // Launch the PIP activity and wait for it to enter PiP mode + setRotation(Rotation.ROTATION_0) + RemoveAllTasksButHomeRule.removeAllTasksButHome() + pipApp.launchViaIntentAndWaitForPip(wmHelper, stringExtras = stringExtras) + + val initRegion = pipApp.dragPipWindowAwayFromEdge(wmHelper, 50) + startBounds + .set(initRegion.left, initRegion.top, initRegion.right, initRegion.bottom) + } + transitions { + // continue the transition until the PIP snaps + pipApp.waitForPipToSnapTo(wmHelper, startBounds) + } + } + + /** Checks that the visible region area of [pipApp] always moves right during the animation. */ + @Postsubmit + @Test + fun pipLayerMovesRight() { + flicker.assertLayers { + val pipLayerList = layers { pipApp.layerMatchesAnyOf(it) && it.isVisible } + pipLayerList.zipWithNext { previous, current -> + current.visibleRegion.isToTheRight(previous.visibleRegion.region) + } + } + } + + companion object { + /** + * Creates the test configurations. + * + * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and + * navigation modes. + */ + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): List { + return FlickerTestFactory.nonRotationTests( + supportedRotations = listOf(Rotation.ROTATION_0) + ) + } + } +} \ No newline at end of file diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt index 0e852b6c84ff5..6e4e937240550 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt @@ -58,7 +58,51 @@ open class PipAppHelper(instrumentation: Instrumentation) : } /** - * Expands the PIP window my using the pinch out gesture. + * Drags the PIP window away from the screen edge while not crossing the display center. + * + * @throws IllegalStateException if default display bounds are not available + * @return initial bounds of the PIP window + */ + fun dragPipWindowAwayFromEdge(wmHelper: WindowManagerStateHelper, steps: Int): Rect { + val initWindowRect = getWindowRect(wmHelper).clone() + + // initial pointer at the center of the window + val startX = initWindowRect.centerX() + val y = initWindowRect.centerY() + + val displayRect = wmHelper.currentState.wmState.getDefaultDisplay()?.displayRect + ?: throw IllegalStateException("Default display is null") + + // the offset to the right of the display center to drag the window to + val offset = 20 + + // the actual final x coordinate with the offset included + // if the pip window is closer to the right edge of the display the offset is positive + // otherwise the offset is negative + val endX = displayRect.centerX() + offset * (if (isCloserToRightEdge(wmHelper)) 1 else -1) + + // drag the window to the left but not beyond the center of the display + uiDevice.drag(startX, y, endX, y, steps) + + return initWindowRect + } + + /** + * Returns true if PIP window is closer to the right edge of the display than left. + * + * @throws IllegalStateException if default display bounds are not available + */ + private fun isCloserToRightEdge(wmHelper: WindowManagerStateHelper): Boolean { + val windowRect = getWindowRect(wmHelper) + + val displayRect = wmHelper.currentState.wmState.getDefaultDisplay()?.displayRect + ?: throw IllegalStateException("Default display is null") + + return windowRect.centerX() > displayRect.centerX() + } + + /** + * Expands the PIP window by using the pinch out gesture. * * @param percent The percentage by which to increase the pip window size. * @throws IllegalArgumentException if percentage isn't between 0.0f and 1.0f @@ -106,7 +150,7 @@ open class PipAppHelper(instrumentation: Instrumentation) : } /** - * Minimizes the PIP window my using the pinch in gesture. + * Minimizes the PIP window by using the pinch in gesture. * * @param percent The percentage by which to decrease the pip window size. * @throws IllegalArgumentException if percentage isn't between 0.0f and 1.0f @@ -307,6 +351,27 @@ open class PipAppHelper(instrumentation: Instrumentation) : .waitForAndVerify() } + /** + * Waits until the PIP window snaps horizontally to the provided bounds. + * + * @param finalRightX the final x coordinate of the right edge of the pip window + */ + fun waitForPipToSnapTo(wmHelper: WindowManagerStateHelper, finalBounds: android.graphics.Rect) { + wmHelper + .StateSyncBuilder() + .add("pipWindowSnapped") { + val pipAppWindow = + it.wmState.visibleWindows.firstOrNull { window -> + this.windowMatchesAnyOf(window) + } + ?: return@add false + val pipRegionBounds = pipAppWindow.frameRegion.bounds + return@add pipRegionBounds.left == finalBounds.left && + pipRegionBounds.right == finalBounds.right + } + .waitForAndVerify() + } + companion object { private const val TAG = "PipAppHelper" private const val ENTER_PIP_BUTTON_ID = "enter_pip"