diff options
25 files changed, 128 insertions, 681 deletions
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/AndroidTestTemplate.xml b/libs/WindowManager/Shell/tests/flicker/pip/AndroidTestTemplate.xml index 9f32d68559e7..a136936c0838 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/AndroidTestTemplate.xml +++ b/libs/WindowManager/Shell/tests/flicker/pip/AndroidTestTemplate.xml @@ -25,7 +25,7 @@ <!-- keeps the screen on during tests --> <option name="screen-always-on" value="on"/> <!-- Turns off Wi-fi --> - <option name="wifi" value="off"/> + <option name="wifi" value="on"/> <!-- Turns off Bluetooth --> <option name="bluetooth" value="off"/> <!-- prevents the phone from restarting --> @@ -109,4 +109,11 @@ <option name="collect-on-run-ended-only" value="true"/> <option name="clean-up" value="true"/> </metrics_collector> + <!-- Enable mocking GPS location by the test app --> + <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"> + <option name="run-command" + value="appops set com.android.shell android:mock_location allow"/> + <option name="teardown-command" + value="appops set com.android.shell android:mock_location deny"/> + </target_preparer> </configuration> diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt index fd4328dee0a1..609a2849f915 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt @@ -27,6 +27,7 @@ import android.tools.flicker.legacy.LegacyFlickerTest import android.tools.flicker.subject.exceptions.ExceptionMessageBuilder import android.tools.flicker.subject.exceptions.IncorrectRegionException import android.tools.flicker.subject.layers.LayerSubject +import com.android.server.wm.flicker.helpers.PipAppHelper import com.android.wm.shell.Flags import com.android.wm.shell.flicker.pip.common.EnterPipTransition import org.junit.Assume @@ -65,6 +66,8 @@ import kotlin.math.abs @FixMethodOrder(MethodSorters.NAME_ASCENDING) @RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) open class AutoEnterPipOnGoToHomeTest(flicker: LegacyFlickerTest) : EnterPipTransition(flicker) { + override val pipApp: PipAppHelper = PipAppHelper(instrumentation) + override val thisTransition: FlickerBuilder.() -> Unit = { transitions { tapl.goHome() } } override val defaultEnterPip: FlickerBuilder.() -> Unit = { diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt index d4ad4ef8a401..5698023240ab 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt @@ -22,6 +22,7 @@ import android.tools.flicker.junit.FlickerParametersRunnerFactory import android.tools.flicker.legacy.FlickerBuilder import android.tools.flicker.legacy.LegacyFlickerTest import android.tools.traces.component.ComponentNameMatcher +import com.android.server.wm.flicker.helpers.PipAppHelper import com.android.wm.shell.Flags import org.junit.FixMethodOrder import org.junit.Test @@ -57,6 +58,8 @@ import org.junit.runners.Parameterized @RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) class AutoEnterPipWithSourceRectHintTest(flicker: LegacyFlickerTest) : AutoEnterPipOnGoToHomeTest(flicker) { + override val pipApp: PipAppHelper = PipAppHelper(instrumentation) + override val defaultEnterPip: FlickerBuilder.() -> Unit = { setup { pipApp.launchViaIntent(wmHelper) diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt index 53725fa046c6..880e4cd4e5f7 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt @@ -21,6 +21,7 @@ import android.platform.test.annotations.RequiresFlagsDisabled import android.tools.flicker.junit.FlickerParametersRunnerFactory import android.tools.flicker.legacy.FlickerBuilder import android.tools.flicker.legacy.LegacyFlickerTest +import com.android.server.wm.flicker.helpers.PipAppHelper import com.android.wm.shell.Flags import com.android.wm.shell.flicker.pip.common.ClosePipTransition import org.junit.FixMethodOrder @@ -56,6 +57,8 @@ import org.junit.runners.Parameterized @FixMethodOrder(MethodSorters.NAME_ASCENDING) @RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) class ClosePipWithDismissButtonTest(flicker: LegacyFlickerTest) : ClosePipTransition(flicker) { + override val pipApp: PipAppHelper = PipAppHelper(instrumentation) + override val thisTransition: FlickerBuilder.() -> Unit = { transitions { pipApp.closePipWindow(wmHelper) } } diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt index a1551b7924fe..4399a237bcbb 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt @@ -21,6 +21,7 @@ import android.platform.test.annotations.RequiresFlagsDisabled import android.tools.flicker.junit.FlickerParametersRunnerFactory import android.tools.flicker.legacy.FlickerBuilder import android.tools.flicker.legacy.LegacyFlickerTest +import com.android.server.wm.flicker.helpers.PipAppHelper import com.android.wm.shell.Flags import com.android.wm.shell.flicker.pip.common.EnterPipTransition import org.junit.Assume @@ -47,6 +48,7 @@ import org.junit.runners.Parameterized @FixMethodOrder(MethodSorters.NAME_ASCENDING) @RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) class EnterPipOnUserLeaveHintTest(flicker: LegacyFlickerTest) : EnterPipTransition(flicker) { + override val pipApp: PipAppHelper = PipAppHelper(instrumentation) override val thisTransition: FlickerBuilder.() -> Unit = { transitions { tapl.goHome() } } override val defaultEnterPip: FlickerBuilder.() -> Unit = { diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt index ea5b3e5b08df..49efd1d56256 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt @@ -31,6 +31,7 @@ import android.tools.traces.component.ComponentNameMatcher import androidx.test.filters.FlakyTest import com.android.server.wm.flicker.entireScreenCovered import com.android.server.wm.flicker.helpers.FixedOrientationAppHelper +import com.android.server.wm.flicker.helpers.PipAppHelper import com.android.server.wm.flicker.testapp.ActivityOptions.Pip.ACTION_ENTER_PIP import com.android.server.wm.flicker.testapp.ActivityOptions.PortraitOnlyActivity.EXTRA_FIXED_ORIENTATION import com.android.wm.shell.Flags @@ -72,6 +73,7 @@ import org.junit.runners.Parameterized @FixMethodOrder(MethodSorters.NAME_ASCENDING) @RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) class EnterPipToOtherOrientation(flicker: LegacyFlickerTest) : PipTransition(flicker) { + override val pipApp: PipAppHelper = PipAppHelper(instrumentation) private val testApp = FixedOrientationAppHelper(instrumentation) private val startingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_90) private val endingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_0) diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt index a109c4bba2b3..97cc9d29929c 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt @@ -20,6 +20,7 @@ import android.platform.test.annotations.RequiresFlagsDisabled import android.tools.flicker.junit.FlickerParametersRunnerFactory import android.tools.flicker.legacy.FlickerBuilder import android.tools.flicker.legacy.LegacyFlickerTest +import com.android.server.wm.flicker.helpers.PipAppHelper import com.android.wm.shell.Flags import com.android.wm.shell.flicker.pip.common.EnterPipTransition import org.junit.FixMethodOrder @@ -53,6 +54,8 @@ import org.junit.runners.Parameterized @FixMethodOrder(MethodSorters.NAME_ASCENDING) @RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) open class EnterPipViaAppUiButtonTest(flicker: LegacyFlickerTest) : EnterPipTransition(flicker) { + override val pipApp: PipAppHelper = PipAppHelper(instrumentation) + override val thisTransition: FlickerBuilder.() -> Unit = { transitions { pipApp.clickEnterPipButton(wmHelper) } } diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt index 14ec303206ee..b5b7847e205d 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt @@ -20,6 +20,7 @@ import android.platform.test.annotations.RequiresFlagsDisabled import android.tools.flicker.junit.FlickerParametersRunnerFactory import android.tools.flicker.legacy.FlickerBuilder import android.tools.flicker.legacy.LegacyFlickerTest +import com.android.server.wm.flicker.helpers.PipAppHelper import com.android.wm.shell.Flags import com.android.wm.shell.flicker.pip.common.ExitPipToAppTransition import org.junit.FixMethodOrder @@ -56,6 +57,8 @@ import org.junit.runners.Parameterized @RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) class ExitPipToAppViaExpandButtonTest(flicker: LegacyFlickerTest) : ExitPipToAppTransition(flicker) { + override val pipApp: PipAppHelper = PipAppHelper(instrumentation) + override val thisTransition: FlickerBuilder.() -> Unit = { setup { // launch an app behind the pip one diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt index 8a34b5e27fdb..f9a9df43a009 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt @@ -20,6 +20,7 @@ import android.platform.test.annotations.RequiresFlagsDisabled import android.tools.flicker.junit.FlickerParametersRunnerFactory import android.tools.flicker.legacy.FlickerBuilder import android.tools.flicker.legacy.LegacyFlickerTest +import com.android.server.wm.flicker.helpers.PipAppHelper import com.android.wm.shell.Flags import com.android.wm.shell.flicker.pip.common.ExitPipToAppTransition import org.junit.FixMethodOrder @@ -54,6 +55,8 @@ import org.junit.runners.Parameterized @FixMethodOrder(MethodSorters.NAME_ASCENDING) @RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) class ExitPipToAppViaIntentTest(flicker: LegacyFlickerTest) : ExitPipToAppTransition(flicker) { + override val pipApp: PipAppHelper = PipAppHelper(instrumentation) + override val thisTransition: FlickerBuilder.() -> Unit = { setup { // launch an app behind the pip one diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt index 12e23285ea68..79e2e4e5a82c 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt @@ -27,6 +27,7 @@ import android.tools.flicker.legacy.LegacyFlickerTest import android.tools.flicker.legacy.LegacyFlickerTestFactory import android.tools.helpers.WindowUtils import android.tools.traces.parsers.toFlickerComponent +import com.android.server.wm.flicker.helpers.PipAppHelper import com.android.server.wm.flicker.helpers.SimpleAppHelper import com.android.server.wm.flicker.testapp.ActivityOptions import com.android.wm.shell.Flags @@ -68,6 +69,7 @@ import org.junit.runners.Parameterized @RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) class FromSplitScreenEnterPipOnUserLeaveHintTest(flicker: LegacyFlickerTest) : EnterPipTransition(flicker) { + override val pipApp: PipAppHelper = PipAppHelper(instrumentation) private val portraitDisplayBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_0) /** Second app used to enter split screen mode */ private val secondAppForSplitScreen = diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt index 04016a93e53d..14ae93a81c6d 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt @@ -23,6 +23,7 @@ import android.tools.flicker.junit.FlickerParametersRunnerFactory import android.tools.flicker.legacy.FlickerBuilder import android.tools.flicker.legacy.LegacyFlickerTest import android.tools.flicker.legacy.LegacyFlickerTestFactory +import com.android.server.wm.flicker.helpers.PipAppHelper import com.android.wm.shell.Flags import com.android.wm.shell.flicker.pip.common.PipTransition import org.junit.FixMethodOrder @@ -37,6 +38,8 @@ import org.junit.runners.Parameterized @FixMethodOrder(MethodSorters.NAME_ASCENDING) @RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) class PipAspectRatioChangeTest(flicker: LegacyFlickerTest) : PipTransition(flicker) { + override val pipApp: PipAppHelper = PipAppHelper(instrumentation) + override val thisTransition: FlickerBuilder.() -> Unit = { transitions { pipApp.changeAspectRatio(wmHelper) } } diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt index 6bcaabc3b680..81162c6f53f5 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt @@ -49,7 +49,8 @@ class PipDragTest(flicker: LegacyFlickerTest) : PipTransition(flicker) { val stringExtras = mapOf(ActivityOptions.Pip.EXTRA_ENTER_PIP to "true") setup { tapl.setEnableRotation(true) - pipApp.launchViaIntentAndWaitForPip(wmHelper, stringExtras = stringExtras) + pipApp.launchViaIntent(wmHelper, stringExtras = stringExtras) + pipApp.waitForPip(wmHelper) // determine the direction of dragging to test for isDraggedLeft = pipApp.isCloserToRightEdge(wmHelper) diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt index d82bfdd6dc2f..6118d73796a1 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt @@ -59,7 +59,8 @@ class PipDragThenSnapTest(flicker: LegacyFlickerTest) : PipTransition(flicker) { // Launch the PIP activity and wait for it to enter PiP mode setRotation(Rotation.ROTATION_0) RemoveAllTasksButHomeRule.removeAllTasksButHome() - pipApp.launchViaIntentAndWaitForPip(wmHelper, stringExtras = stringExtras) + pipApp.launchViaIntent(wmHelper, stringExtras = stringExtras) + pipApp.waitForPip(wmHelper) // get the initial region bounds and cache them val initRegion = pipApp.getWindowRect(wmHelper) diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt index dbc97d072f9b..61c59cc45504 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt @@ -25,6 +25,7 @@ import android.tools.flicker.legacy.FlickerBuilder import android.tools.flicker.legacy.LegacyFlickerTest import android.tools.flicker.legacy.LegacyFlickerTestFactory import android.tools.flicker.subject.exceptions.IncorrectRegionException +import com.android.server.wm.flicker.helpers.PipAppHelper import com.android.wm.shell.Flags import com.android.wm.shell.flicker.pip.common.PipTransition import org.junit.FixMethodOrder @@ -40,6 +41,8 @@ import org.junit.runners.Parameterized @FixMethodOrder(MethodSorters.NAME_ASCENDING) @RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) class PipPinchInTest(flicker: LegacyFlickerTest) : PipTransition(flicker) { + override val pipApp: PipAppHelper = PipAppHelper(instrumentation) + override val thisTransition: FlickerBuilder.() -> Unit = { transitions { pipApp.pinchInPipWindow(wmHelper, 0.4f, 30) } } diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt index 65b60ce1022b..0867f654bcaf 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt @@ -18,7 +18,6 @@ package com.android.wm.shell.flicker.pip.apps import android.platform.test.annotations.Postsubmit import android.tools.Rotation -import android.tools.device.apphelpers.StandardAppHelper import android.tools.flicker.junit.FlickerBuilderProvider import android.tools.flicker.legacy.FlickerBuilder import android.tools.flicker.legacy.LegacyFlickerTest @@ -29,8 +28,6 @@ import org.junit.Test import org.junit.runners.Parameterized abstract class AppsEnterPipTransition(flicker: LegacyFlickerTest) : EnterPipTransition(flicker) { - protected abstract val standardAppHelper: StandardAppHelper - protected abstract val permissions: Array<String> @FlickerBuilderProvider @@ -39,7 +36,7 @@ abstract class AppsEnterPipTransition(flicker: LegacyFlickerTest) : EnterPipTran instrumentation.uiAutomation.adoptShellPermissionIdentity() for (permission in permissions) { instrumentation.uiAutomation.grantRuntimePermission( - standardAppHelper.packageName, + pipApp.packageName, permission ) } @@ -48,18 +45,18 @@ abstract class AppsEnterPipTransition(flicker: LegacyFlickerTest) : EnterPipTran } } - /** Checks [standardAppHelper] window remains visible throughout the animation */ + /** Checks [pipApp] window remains visible throughout the animation */ @Postsubmit @Test override fun pipAppWindowAlwaysVisible() { - flicker.assertWm { this.isAppWindowVisible(standardAppHelper.packageNameMatcher) } + flicker.assertWm { this.isAppWindowVisible(pipApp.packageNameMatcher) } } - /** Checks [standardAppHelper] layer remains visible throughout the animation */ + /** Checks [pipApp] layer remains visible throughout the animation */ @Postsubmit @Test override fun pipAppLayerAlwaysVisible() { - flicker.assertLayers { this.isVisible(standardAppHelper.packageNameMatcher) } + flicker.assertLayers { this.isVisible(pipApp.packageNameMatcher) } } /** Checks the content overlay appears then disappears during the animation */ @@ -70,39 +67,39 @@ abstract class AppsEnterPipTransition(flicker: LegacyFlickerTest) : EnterPipTran } /** - * Checks that [standardAppHelper] window remains inside the display bounds throughout the whole + * Checks that [pipApp] window remains inside the display bounds throughout the whole * animation */ @Postsubmit @Test override fun pipWindowRemainInsideVisibleBounds() { - flicker.assertWmVisibleRegion(standardAppHelper.packageNameMatcher) { + flicker.assertWmVisibleRegion(pipApp.packageNameMatcher) { coversAtMost(displayBounds) } } /** - * Checks that the [standardAppHelper] layer remains inside the display bounds throughout the + * Checks that the [pipApp] layer remains inside the display bounds throughout the * whole animation */ @Postsubmit @Test override fun pipLayerOrOverlayRemainInsideVisibleBounds() { flicker.assertLayersVisibleRegion( - standardAppHelper.packageNameMatcher.or(ComponentNameMatcher.PIP_CONTENT_OVERLAY) + pipApp.packageNameMatcher.or(ComponentNameMatcher.PIP_CONTENT_OVERLAY) ) { coversAtMost(displayBounds) } } - /** Checks that the visible region of [standardAppHelper] always reduces during the animation */ + /** Checks that the visible region of [pipApp] always reduces during the animation */ @Postsubmit @Test override fun pipLayerReduces() { flicker.assertLayers { val pipLayerList = this.layers { - standardAppHelper.packageNameMatcher.layerMatchesAnyOf(it) && it.isVisible + pipApp.packageNameMatcher.layerMatchesAnyOf(it) && it.isVisible } pipLayerList.zipWithNext { previous, current -> current.visibleRegion.notBiggerThan(previous.visibleRegion.region) @@ -110,14 +107,14 @@ abstract class AppsEnterPipTransition(flicker: LegacyFlickerTest) : EnterPipTran } } - /** Checks that [standardAppHelper] window becomes pinned */ + /** Checks that [pipApp] window becomes pinned */ @Postsubmit @Test override fun pipWindowBecomesPinned() { flicker.assertWm { - invoke("pipWindowIsNotPinned") { it.isNotPinned(standardAppHelper.packageNameMatcher) } + invoke("pipWindowIsNotPinned") { it.isNotPinned(pipApp.packageNameMatcher) } .then() - .invoke("pipWindowIsPinned") { it.isPinned(standardAppHelper.packageNameMatcher) } + .invoke("pipWindowIsPinned") { it.isPinned(pipApp.packageNameMatcher) } } } @@ -129,14 +126,14 @@ abstract class AppsEnterPipTransition(flicker: LegacyFlickerTest) : EnterPipTran } /** - * Checks that the focus changes between the [standardAppHelper] window and the launcher when + * Checks that the focus changes between the [pipApp] window and the launcher when * closing the pip window */ @Postsubmit @Test override fun focusChanges() { flicker.assertEventLog { - this.focusChanges(standardAppHelper.packageName, "NexusLauncherActivity") + this.focusChanges(pipApp.packageName, "NexusLauncherActivity") } } diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt index 7b04b766a191..651c92308c04 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt @@ -29,6 +29,8 @@ import android.tools.device.apphelpers.MapsAppHelper import android.tools.flicker.junit.FlickerParametersRunnerFactory import android.tools.flicker.legacy.FlickerBuilder import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.subject.layers.LayersTraceSubject.Companion.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS +import android.tools.traces.component.ComponentRegexMatcher import androidx.test.filters.RequiresDevice import org.junit.Assume import org.junit.FixMethodOrder @@ -63,7 +65,7 @@ import org.junit.runners.Parameterized @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) open class MapsEnterPipTest(flicker: LegacyFlickerTest) : AppsEnterPipTransition(flicker) { - override val standardAppHelper: MapsAppHelper = MapsAppHelper(instrumentation) + override val pipApp: MapsAppHelper = MapsAppHelper(instrumentation) override val permissions: Array<String> = arrayOf(Manifest.permission.POST_NOTIFICATIONS, Manifest.permission.ACCESS_FINE_LOCATION) @@ -110,23 +112,23 @@ open class MapsEnterPipTest(flicker: LegacyFlickerTest) : AppsEnterPipTransition // normal app open through the Launcher All Apps // var mapsAddressOption = "Golden Gate Bridge" - // standardAppHelper.open() - // standardAppHelper.doSearch(mapsAddressOption) - // standardAppHelper.getDirections() - // standardAppHelper.startNavigation(); + // pipApp.open() + // pipApp.doSearch(mapsAddressOption) + // pipApp.getDirections() + // pipApp.startNavigation(); - standardAppHelper.launchViaIntent( + pipApp.launchViaIntent( wmHelper, MapsAppHelper.getMapIntent(MapsAppHelper.INTENT_NAVIGATION) ) - standardAppHelper.waitForNavigationToStart() + pipApp.waitForNavigationToStart() } } override val defaultTeardown: FlickerBuilder.() -> Unit = { teardown { - standardAppHelper.exit(wmHelper) + pipApp.exit(wmHelper) mainHandler.removeCallbacks(updateLocation) // the main looper callback might have tried to provide a new location after the // provider is no longer in test mode, causing a crash, this prevents it from happening @@ -137,14 +139,14 @@ open class MapsEnterPipTest(flicker: LegacyFlickerTest) : AppsEnterPipTransition override val thisTransition: FlickerBuilder.() -> Unit = { transitions { tapl.goHome() } } - /** Checks [standardAppHelper] layer remains visible throughout the animation */ + /** Checks [pipApp] layer remains visible throughout the animation */ @Postsubmit @Test override fun pipAppLayerAlwaysVisible() { // For Maps the transition goes through the UI mode change that adds a snapshot overlay so // we assert only start/end layers matching the app instead. - flicker.assertLayersStart { this.isVisible(standardAppHelper.packageNameMatcher) } - flicker.assertLayersEnd { this.isVisible(standardAppHelper.packageNameMatcher) } + flicker.assertLayersStart { this.isVisible(pipApp.packageNameMatcher) } + flicker.assertLayersEnd { this.isVisible(pipApp.packageNameMatcher) } } @Postsubmit @@ -154,4 +156,15 @@ open class MapsEnterPipTest(flicker: LegacyFlickerTest) : AppsEnterPipTransition Assume.assumeFalse(flicker.scenario.isGesturalNavigation) super.focusChanges() } + + @Postsubmit + @Test + override fun visibleLayersShownMoreThanOneConsecutiveEntry() { + flicker.assertLayers { + this.visibleLayersShownMoreThanOneConsecutiveEntry( + ignoreLayers = VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS + + ComponentRegexMatcher(Regex("Background for .* SurfaceView\\[com\\.google\\.android\\.apps\\.maps/com\\.google\\.android\\.maps\\.MapsActivity\\]\\#\\d+")) + ) + } + } } diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt index 691194609343..be4cd780e45e 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt @@ -61,7 +61,7 @@ import org.junit.runners.Parameterized @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) open class NetflixEnterPipTest(flicker: LegacyFlickerTest) : AppsEnterPipTransition(flicker) { - override val standardAppHelper: NetflixAppHelper = NetflixAppHelper(instrumentation) + override val pipApp: NetflixAppHelper = NetflixAppHelper(instrumentation) private val startingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_90) private val endingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_0) @@ -69,17 +69,17 @@ open class NetflixEnterPipTest(flicker: LegacyFlickerTest) : AppsEnterPipTransit override val defaultEnterPip: FlickerBuilder.() -> Unit = { setup { - standardAppHelper.launchViaIntent( + pipApp.launchViaIntent( wmHelper, NetflixAppHelper.getNetflixWatchVideoIntent("81605060"), ComponentNameMatcher(NetflixAppHelper.PACKAGE_NAME, NetflixAppHelper.WATCH_ACTIVITY) ) - standardAppHelper.waitForVideoPlaying() + pipApp.waitForVideoPlaying() } } override val defaultTeardown: FlickerBuilder.() -> Unit = { - teardown { standardAppHelper.exit(wmHelper) } + teardown { pipApp.exit(wmHelper) } } override val thisTransition: FlickerBuilder.() -> Unit = { @@ -143,7 +143,7 @@ open class NetflixEnterPipTest(flicker: LegacyFlickerTest) : AppsEnterPipTransit // might go outside of bounds as we resize from landscape fullscreen to destination bounds, // and once the animation is over we assert that it's fully within the display bounds, at // which point the device also performs orientation change from landscape to portrait - flicker.assertWmVisibleRegion(standardAppHelper.packageNameMatcher) { + flicker.assertWmVisibleRegion(pipApp.packageNameMatcher) { regionsCenterPointInside(startingBounds).then().coversAtMost(endingBounds) } } @@ -156,7 +156,7 @@ open class NetflixEnterPipTest(flicker: LegacyFlickerTest) : AppsEnterPipTransit // and once the animation is over we assert that it's fully within the display bounds, at // which point the device also performs orientation change from landscape to portrait // since Netflix uses source rect hint, there is no PiP overlay present - flicker.assertLayersVisibleRegion(standardAppHelper.packageNameMatcher) { + flicker.assertLayersVisibleRegion(pipApp.packageNameMatcher) { regionsCenterPointInside(startingBounds).then().coversAtMost(endingBounds) } } diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt index 5e54f30dae8a..3e4ff3075f73 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt @@ -57,23 +57,23 @@ import org.junit.runners.Parameterized @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) open class YouTubeEnterPipTest(flicker: LegacyFlickerTest) : AppsEnterPipTransition(flicker) { - override val standardAppHelper: YouTubeAppHelper = YouTubeAppHelper(instrumentation) + override val pipApp: YouTubeAppHelper = YouTubeAppHelper(instrumentation) override val permissions: Array<String> = arrayOf(Manifest.permission.POST_NOTIFICATIONS) override val defaultEnterPip: FlickerBuilder.() -> Unit = { setup { - standardAppHelper.launchViaIntent( + pipApp.launchViaIntent( wmHelper, YouTubeAppHelper.getYoutubeVideoIntent("3KtWfp0UopM"), ComponentNameMatcher(YouTubeAppHelper.PACKAGE_NAME, "") ) - standardAppHelper.waitForVideoPlaying() + pipApp.waitForVideoPlaying() } } override val defaultTeardown: FlickerBuilder.() -> Unit = { - teardown { standardAppHelper.exit(wmHelper) } + teardown { pipApp.exit(wmHelper) } } override val thisTransition: FlickerBuilder.() -> Unit = { transitions { tapl.goHome() } } diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipToOtherOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipToOtherOrientationTest.kt index 159cba4a559e..2c6cb503465c 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipToOtherOrientationTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipToOtherOrientationTest.kt @@ -63,7 +63,7 @@ import org.junit.runners.Parameterized @FixMethodOrder(MethodSorters.NAME_ASCENDING) open class YouTubeEnterPipToOtherOrientationTest(flicker: LegacyFlickerTest) : YouTubeEnterPipTest(flicker) { - override val standardAppHelper: YouTubeAppHelper = YouTubeAppHelper(instrumentation) + override val pipApp: YouTubeAppHelper = YouTubeAppHelper(instrumentation) private val startingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_90) private val endingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_0) @@ -71,13 +71,13 @@ open class YouTubeEnterPipToOtherOrientationTest(flicker: LegacyFlickerTest) : override val defaultEnterPip: FlickerBuilder.() -> Unit = { setup { - standardAppHelper.launchViaIntent( + pipApp.launchViaIntent( wmHelper, YouTubeAppHelper.getYoutubeVideoIntent("3KtWfp0UopM"), ComponentNameMatcher(YouTubeAppHelper.PACKAGE_NAME, "") ) - standardAppHelper.enterFullscreen() - standardAppHelper.waitForVideoPlaying() + pipApp.enterFullscreen() + pipApp.waitForVideoPlaying() } } @@ -101,7 +101,7 @@ open class YouTubeEnterPipToOtherOrientationTest(flicker: LegacyFlickerTest) : // might go outside of bounds as we resize from landscape fullscreen to destination bounds, // and once the animation is over we assert that it's fully within the display bounds, at // which point the device also performs orientation change from landscape to portrait - flicker.assertWmVisibleRegion(standardAppHelper.packageNameMatcher) { + flicker.assertWmVisibleRegion(pipApp.packageNameMatcher) { regionsCenterPointInside(startingBounds).then().coversAtMost(endingBounds) } } @@ -114,7 +114,7 @@ open class YouTubeEnterPipToOtherOrientationTest(flicker: LegacyFlickerTest) : // and once the animation is over we assert that it's fully within the display bounds, at // which point the device also performs orientation change from landscape to portrait // since YouTube uses source rect hint, there is no PiP overlay present - flicker.assertLayersVisibleRegion(standardAppHelper.packageNameMatcher) { + flicker.assertLayersVisibleRegion(pipApp.packageNameMatcher) { regionsCenterPointInside(startingBounds).then().coversAtMost(endingBounds) } } diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/EnterPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/EnterPipTransition.kt index 6dd3a175da65..a72de0f6daf4 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/EnterPipTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/EnterPipTransition.kt @@ -71,7 +71,9 @@ abstract class EnterPipTransition(flicker: LegacyFlickerTest) : PipTransition(fl @Presubmit @Test open fun pipLayerOrOverlayRemainInsideVisibleBounds() { - flicker.assertLayersVisibleRegion(pipApp.or(ComponentNameMatcher.PIP_CONTENT_OVERLAY)) { + flicker.assertLayersVisibleRegion( + pipApp.or(ComponentNameMatcher.PIP_CONTENT_OVERLAY) + ) { coversAtMost(displayBounds) } } @@ -117,7 +119,9 @@ abstract class EnterPipTransition(flicker: LegacyFlickerTest) : PipTransition(fl @Presubmit @Test open fun focusChanges() { - flicker.assertEventLog { this.focusChanges(pipApp.packageName, "NexusLauncherActivity") } + flicker.assertEventLog { + this.focusChanges(pipApp.packageName, "NexusLauncherActivity") + } } companion object { diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt index c37bf3579e93..7b6625ddc429 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt @@ -27,6 +27,7 @@ import android.tools.flicker.legacy.LegacyFlickerTest import android.tools.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome import android.tools.helpers.WindowUtils import android.tools.traces.component.ComponentNameMatcher +import android.tools.device.apphelpers.PipApp import com.android.server.wm.flicker.helpers.PipAppHelper import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.testapp.ActivityOptions @@ -40,7 +41,6 @@ abstract class PipTransition(flicker: LegacyFlickerTest) : BaseTest(flicker) { @Rule val checkFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() - protected val pipApp = PipAppHelper(instrumentation) protected val displayBounds = WindowUtils.getDisplayBounds(flicker.scenario.startRotation) protected val broadcastActionTrigger = BroadcastActionTrigger(instrumentation) @@ -63,6 +63,11 @@ abstract class PipTransition(flicker: LegacyFlickerTest) : BaseTest(flicker) { } } + /** + * Defines the test app to run PIP flicker test. + */ + protected open val pipApp: PipApp = PipAppHelper(instrumentation) + /** Defines the transition used to run the test */ protected open val thisTransition: FlickerBuilder.() -> Unit = {} @@ -85,10 +90,11 @@ abstract class PipTransition(flicker: LegacyFlickerTest) : BaseTest(flicker) { /** Defines the default method of entering PiP */ protected open val defaultEnterPip: FlickerBuilder.() -> Unit = { setup { - pipApp.launchViaIntentAndWaitForPip( + pipApp.launchViaIntent( wmHelper, stringExtras = mapOf(ActivityOptions.Pip.EXTRA_ENTER_PIP to "true") ) + pipApp.waitForPip(wmHelper) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt index c4954f90179c..feb3edc9dab7 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt @@ -20,6 +20,7 @@ import android.app.Instrumentation import android.graphics.Point import android.os.SystemClock import android.tools.Rotation +import android.tools.device.apphelpers.IStandardAppHelper import android.tools.device.apphelpers.StandardAppHelper import android.tools.flicker.rules.ChangeDisplayOrientationRule import android.tools.traces.component.ComponentNameMatcher @@ -102,8 +103,8 @@ object SplitScreenUtils { wmHelper: WindowManagerStateHelper, tapl: LauncherInstrumentation, device: UiDevice, - primaryApp: StandardAppHelper, - secondaryApp: StandardAppHelper, + primaryApp: IStandardAppHelper, + secondaryApp: IStandardAppHelper, rotation: Rotation ) { primaryApp.launchViaIntent(wmHelper) @@ -117,8 +118,8 @@ object SplitScreenUtils { fun enterSplitViaIntent( wmHelper: WindowManagerStateHelper, - primaryApp: StandardAppHelper, - secondaryApp: StandardAppHelper + primaryApp: IStandardAppHelper, + secondaryApp: IStandardAppHelper ) { val stringExtras = mapOf(Primary.EXTRA_LAUNCH_ADJACENT to "true") primaryApp.launchViaIntent(wmHelper, null, null, stringExtras) diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GestureHelper.java b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GestureHelper.java deleted file mode 100644 index eeee7b4dfc6b..000000000000 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GestureHelper.java +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Copyright (C) 2022 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.server.wm.flicker.helpers; - -import android.annotation.NonNull; -import android.app.Instrumentation; -import android.app.UiAutomation; -import android.os.SystemClock; -import android.view.InputDevice; -import android.view.InputEvent; -import android.view.MotionEvent; -import android.view.MotionEvent.PointerCoords; -import android.view.MotionEvent.PointerProperties; - -import androidx.annotation.Nullable; - -/** - * Injects gestures given an {@link Instrumentation} object. - */ -public class GestureHelper { - // Inserted after each motion event injection. - private static final int MOTION_EVENT_INJECTION_DELAY_MILLIS = 5; - - private final UiAutomation mUiAutomation; - - /** - * Primary pointer should be cached here for separate release - */ - @Nullable private PointerProperties mPrimaryPtrProp; - @Nullable private PointerCoords mPrimaryPtrCoord; - private long mPrimaryPtrDownTime; - - /** - * A pair of floating point values. - */ - public static class Tuple { - public float x; - public float y; - - public Tuple(float x, float y) { - this.x = x; - this.y = y; - } - } - - public GestureHelper(Instrumentation instrumentation) { - mUiAutomation = instrumentation.getUiAutomation(); - } - - /** - * Injects a series of {@link MotionEvent}s to simulate tapping. - * - * @param point coordinates of pointer to tap - * @param times the number of times to tap - */ - public boolean tap(@NonNull Tuple point, int times) throws InterruptedException { - PointerProperties ptrProp = getPointerProp(0, MotionEvent.TOOL_TYPE_FINGER); - PointerCoords ptrCoord = getPointerCoord(point.x, point.y, 1, 1); - - for (int i = 0; i <= times; i++) { - // If already tapped, inject delay in between movements - if (times > 0) { - SystemClock.sleep(50L); - } - if (!primaryPointerDown(ptrProp, ptrCoord, SystemClock.uptimeMillis())) { - return false; - } - // Delay before releasing tap - SystemClock.sleep(100L); - if (!primaryPointerUp(ptrProp, ptrCoord, SystemClock.uptimeMillis())) { - return false; - } - } - return true; - } - - /** - * Injects a series of {@link MotionEvent}s to simulate a drag gesture without pointer release. - * - * Simulates a drag gesture without releasing the primary pointer. The primary pointer info - * will be cached for potential release later on by {@code releasePrimaryPointer()} - * - * @param startPoint initial coordinates of the primary pointer - * @param endPoint final coordinates of the primary pointer - * @param steps number of steps to take to animate dragging - * @return true if gesture is injected successfully - */ - public boolean dragWithoutRelease(@NonNull Tuple startPoint, - @NonNull Tuple endPoint, int steps) { - PointerProperties ptrProp = getPointerProp(0, MotionEvent.TOOL_TYPE_FINGER); - PointerCoords ptrCoord = getPointerCoord(startPoint.x, startPoint.y, 1, 1); - - PointerProperties[] ptrProps = new PointerProperties[] { ptrProp }; - PointerCoords[] ptrCoords = new PointerCoords[] { ptrCoord }; - - long downTime = SystemClock.uptimeMillis(); - - if (!primaryPointerDown(ptrProp, ptrCoord, downTime)) { - return false; - } - - // cache the primary pointer info for later potential release - mPrimaryPtrProp = ptrProp; - mPrimaryPtrCoord = ptrCoord; - mPrimaryPtrDownTime = downTime; - - return movePointers(ptrProps, ptrCoords, new Tuple[] { endPoint }, downTime, steps); - } - - /** - * Release primary pointer if previous gesture has cached the primary pointer info. - * - * @return true if the release was injected successfully - */ - public boolean releasePrimaryPointer() { - if (mPrimaryPtrProp != null && mPrimaryPtrCoord != null) { - return primaryPointerUp(mPrimaryPtrProp, mPrimaryPtrCoord, mPrimaryPtrDownTime); - } - - return false; - } - - /** - * Injects a series of {@link MotionEvent} objects to simulate a pinch gesture. - * - * @param startPoint1 initial coordinates of the first pointer - * @param startPoint2 initial coordinates of the second pointer - * @param endPoint1 final coordinates of the first pointer - * @param endPoint2 final coordinates of the second pointer - * @param steps number of steps to take to animate pinching - * @return true if gesture is injected successfully - */ - public boolean pinch(@NonNull Tuple startPoint1, @NonNull Tuple startPoint2, - @NonNull Tuple endPoint1, @NonNull Tuple endPoint2, int steps) { - PointerProperties ptrProp1 = getPointerProp(0, MotionEvent.TOOL_TYPE_FINGER); - PointerProperties ptrProp2 = getPointerProp(1, MotionEvent.TOOL_TYPE_FINGER); - - PointerCoords ptrCoord1 = getPointerCoord(startPoint1.x, startPoint1.y, 1, 1); - PointerCoords ptrCoord2 = getPointerCoord(startPoint2.x, startPoint2.y, 1, 1); - - PointerProperties[] ptrProps = new PointerProperties[] { - ptrProp1, ptrProp2 - }; - - PointerCoords[] ptrCoords = new PointerCoords[] { - ptrCoord1, ptrCoord2 - }; - - long downTime = SystemClock.uptimeMillis(); - - if (!primaryPointerDown(ptrProp1, ptrCoord1, downTime)) { - return false; - } - - if (!nonPrimaryPointerDown(ptrProps, ptrCoords, downTime, 1)) { - return false; - } - - if (!movePointers(ptrProps, ptrCoords, new Tuple[] { endPoint1, endPoint2 }, - downTime, steps)) { - return false; - } - - if (!nonPrimaryPointerUp(ptrProps, ptrCoords, downTime, 1)) { - return false; - } - - return primaryPointerUp(ptrProp1, ptrCoord1, downTime); - } - - private boolean primaryPointerDown(@NonNull PointerProperties prop, - @NonNull PointerCoords coord, long downTime) { - MotionEvent event = getMotionEvent(downTime, downTime, MotionEvent.ACTION_DOWN, 1, - new PointerProperties[]{ prop }, new PointerCoords[]{ coord }); - - return injectEventSync(event); - } - - private boolean nonPrimaryPointerDown(@NonNull PointerProperties[] props, - @NonNull PointerCoords[] coords, long downTime, int index) { - // at least 2 pointers are needed - if (props.length != coords.length || coords.length < 2) { - return false; - } - - long eventTime = SystemClock.uptimeMillis(); - - MotionEvent event = getMotionEvent(downTime, eventTime, MotionEvent.ACTION_POINTER_DOWN - + (index << MotionEvent.ACTION_POINTER_INDEX_SHIFT), coords.length, props, coords); - - return injectEventSync(event); - } - - private boolean movePointers(@NonNull PointerProperties[] props, - @NonNull PointerCoords[] coords, @NonNull Tuple[] endPoints, long downTime, int steps) { - // the number of endpoints should be the same as the number of pointers - if (props.length != coords.length || coords.length != endPoints.length) { - return false; - } - - // prevent division by 0 and negative number of steps - if (steps < 1) { - steps = 1; - } - - // save the starting points before updating any pointers - Tuple[] startPoints = new Tuple[coords.length]; - - for (int i = 0; i < coords.length; i++) { - startPoints[i] = new Tuple(coords[i].x, coords[i].y); - } - - MotionEvent event; - long eventTime; - - for (int i = 0; i < steps; i++) { - // inject a delay between movements - SystemClock.sleep(MOTION_EVENT_INJECTION_DELAY_MILLIS); - - // update the coordinates - for (int j = 0; j < coords.length; j++) { - coords[j].x += (endPoints[j].x - startPoints[j].x) / steps; - coords[j].y += (endPoints[j].y - startPoints[j].y) / steps; - } - - eventTime = SystemClock.uptimeMillis(); - - event = getMotionEvent(downTime, eventTime, MotionEvent.ACTION_MOVE, - coords.length, props, coords); - - boolean didInject = injectEventSync(event); - - if (!didInject) { - return false; - } - } - - return true; - } - - private boolean primaryPointerUp(@NonNull PointerProperties prop, - @NonNull PointerCoords coord, long downTime) { - long eventTime = SystemClock.uptimeMillis(); - - MotionEvent event = getMotionEvent(downTime, eventTime, MotionEvent.ACTION_UP, 1, - new PointerProperties[]{ prop }, new PointerCoords[]{ coord }); - - return injectEventSync(event); - } - - private boolean nonPrimaryPointerUp(@NonNull PointerProperties[] props, - @NonNull PointerCoords[] coords, long downTime, int index) { - // at least 2 pointers are needed - if (props.length != coords.length || coords.length < 2) { - return false; - } - - long eventTime = SystemClock.uptimeMillis(); - - MotionEvent event = getMotionEvent(downTime, eventTime, MotionEvent.ACTION_POINTER_UP - + (index << MotionEvent.ACTION_POINTER_INDEX_SHIFT), coords.length, props, coords); - - return injectEventSync(event); - } - - private PointerCoords getPointerCoord(float x, float y, float pressure, float size) { - PointerCoords ptrCoord = new PointerCoords(); - ptrCoord.x = x; - ptrCoord.y = y; - ptrCoord.pressure = pressure; - ptrCoord.size = size; - return ptrCoord; - } - - private PointerProperties getPointerProp(int id, int toolType) { - PointerProperties ptrProp = new PointerProperties(); - ptrProp.id = id; - ptrProp.toolType = toolType; - return ptrProp; - } - - private static MotionEvent getMotionEvent(long downTime, long eventTime, int action, - int pointerCount, PointerProperties[] ptrProps, PointerCoords[] ptrCoords) { - return MotionEvent.obtain(downTime, eventTime, action, pointerCount, - ptrProps, ptrCoords, 0, 0, 1.0f, 1.0f, - 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0); - } - - private boolean injectEventSync(InputEvent event) { - return mUiAutomation.injectInputEvent(event, true); - } -} diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt index fd13d14074d4..d5334cbd541c 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt @@ -21,6 +21,7 @@ import android.graphics.Rect import android.graphics.Region import android.tools.device.apphelpers.StandardAppHelper import android.tools.helpers.FIND_TIMEOUT +import android.tools.helpers.GestureHelper import android.tools.helpers.SYSTEMUI_PACKAGE import android.tools.traces.component.ComponentNameMatcher import android.tools.traces.parsers.WindowManagerStateHelper @@ -38,7 +39,8 @@ constructor( ActivityOptions.NonResizeableFixedAspectRatioPortraitActivity.COMPONENT.toFlickerComponent() ) : StandardAppHelper(instr, launcherName, component) { - private val gestureHelper: GestureHelper = GestureHelper(instrumentation) + private val gestureHelper: GestureHelper = + GestureHelper(instrumentation) fun clickRestart(wmHelper: WindowManagerStateHelper) { val restartButton = diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt index db4838ee6092..de17bf422c0c 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt @@ -18,29 +18,26 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation import android.content.Intent -import android.graphics.Rect import android.graphics.Region import android.media.session.MediaController import android.media.session.MediaSessionManager -import android.tools.datatypes.coversMoreThan -import android.tools.device.apphelpers.StandardAppHelper +import android.tools.device.apphelpers.BasePipAppHelper import android.tools.helpers.FIND_TIMEOUT import android.tools.helpers.SYSTEMUI_PACKAGE import android.tools.traces.ConditionsFactory +import android.tools.traces.component.ComponentNameMatcher import android.tools.traces.component.IComponentMatcher import android.tools.traces.parsers.WindowManagerStateHelper import android.tools.traces.parsers.toFlickerComponent -import android.util.Log import androidx.test.uiautomator.By import androidx.test.uiautomator.Until import com.android.server.wm.flicker.testapp.ActivityOptions -open class PipAppHelper(instrumentation: Instrumentation) : - StandardAppHelper( - instrumentation, - ActivityOptions.Pip.LABEL, - ActivityOptions.Pip.COMPONENT.toFlickerComponent() - ) { +open class PipAppHelper( + instrumentation: Instrumentation, + appName: String = ActivityOptions.Pip.LABEL, + componentNameMatcher: ComponentNameMatcher = ActivityOptions.Pip.COMPONENT.toFlickerComponent(), +) : BasePipAppHelper(instrumentation, appName, componentNameMatcher) { private val mediaSessionManager: MediaSessionManager get() = context.getSystemService(MediaSessionManager::class.java) @@ -52,189 +49,6 @@ open class PipAppHelper(instrumentation: Instrumentation) : it.packageName == packageName } - private val gestureHelper: GestureHelper = GestureHelper(instrumentation) - - open fun clickObject(resId: String) { - val selector = By.res(packageName, resId) - val obj = uiDevice.findObject(selector) ?: error("Could not find `$resId` object") - - obj.click() - } - - /** Drags the PIP window to the provided final coordinates without releasing the pointer. */ - fun dragPipWindowAwayFromEdgeWithoutRelease(wmHelper: WindowManagerStateHelper, steps: Int) { - val initWindowRect = Rect(getWindowRect(wmHelper)) - - // initial pointer at the center of the window - val initialCoord = - GestureHelper.Tuple( - initWindowRect.centerX().toFloat(), - initWindowRect.centerY().toFloat() - ) - - // the offset to the right (or left) of the window center to drag the window to - val offset = 50 - - // 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 negative - // otherwise the offset is positive - val endX = - initWindowRect.centerX() + offset * (if (isCloserToRightEdge(wmHelper)) -1 else 1) - val finalCoord = GestureHelper.Tuple(endX.toFloat(), initWindowRect.centerY().toFloat()) - - // drag to the final coordinate - gestureHelper.dragWithoutRelease(initialCoord, finalCoord, steps) - } - - /** - * Releases the primary pointer. - * - * Injects the release of the primary pointer if the primary pointer info was cached after - * another gesture was injected without pointer release. - */ - fun releasePipAfterDragging() { - gestureHelper.releasePrimaryPointer() - } - - /** - * Drags the PIP window away from the screen edge while not crossing the display center. - * - * @throws IllegalStateException if default display bounds are not available - */ - fun dragPipWindowAwayFromEdge(wmHelper: WindowManagerStateHelper, steps: Int) { - val initWindowRect = Rect(getWindowRect(wmHelper)) - - // 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 (or left) 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) - } - - /** - * 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 - */ - 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 - */ - fun pinchOpenPipWindow(wmHelper: WindowManagerStateHelper, percent: Float, steps: Int) { - // the percentage must be between 0.0f and 1.0f - if (percent <= 0.0f || percent > 1.0f) { - throw IllegalArgumentException("Percent must be between 0.0f and 1.0f") - } - - val windowRect = getWindowRect(wmHelper) - - // first pointer's initial x coordinate is halfway between the left edge and the center - val initLeftX = (windowRect.centerX() - windowRect.width() / 4).toFloat() - // second pointer's initial x coordinate is halfway between the right edge and the center - val initRightX = (windowRect.centerX() + windowRect.width() / 4).toFloat() - - // horizontal distance the window should increase by - val distIncrease = windowRect.width() * percent - - // final x-coordinates - val finalLeftX = initLeftX - (distIncrease / 2) - val finalRightX = initRightX + (distIncrease / 2) - - // y-coordinate is the same throughout this animation - val yCoord = windowRect.centerY().toFloat() - - var adjustedSteps = MIN_STEPS_TO_ANIMATE - - // if distance per step is at least 1, then we can use the number of steps requested - if (distIncrease.toInt() / (steps * 2) >= 1) { - adjustedSteps = steps - } - - // if the distance per step is less than 1, carry out the animation in two steps - gestureHelper.pinch( - GestureHelper.Tuple(initLeftX, yCoord), - GestureHelper.Tuple(initRightX, yCoord), - GestureHelper.Tuple(finalLeftX, yCoord), - GestureHelper.Tuple(finalRightX, yCoord), - adjustedSteps - ) - - waitForPipWindowToExpandFrom(wmHelper, Region(windowRect)) - } - - /** - * 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 - */ - fun pinchInPipWindow(wmHelper: WindowManagerStateHelper, percent: Float, steps: Int) { - // the percentage must be between 0.0f and 1.0f - if (percent <= 0.0f || percent > 1.0f) { - throw IllegalArgumentException("Percent must be between 0.0f and 1.0f") - } - - val windowRect = getWindowRect(wmHelper) - - // first pointer's initial x coordinate is halfway between the left edge and the center - val initLeftX = (windowRect.centerX() - windowRect.width() / 4).toFloat() - // second pointer's initial x coordinate is halfway between the right edge and the center - val initRightX = (windowRect.centerX() + windowRect.width() / 4).toFloat() - - // decrease by the distance specified through the percentage - val distDecrease = windowRect.width() * percent - - // get the final x-coordinates and make sure they are not passing the center of the window - val finalLeftX = Math.min(initLeftX + (distDecrease / 2), windowRect.centerX().toFloat()) - val finalRightX = Math.max(initRightX - (distDecrease / 2), windowRect.centerX().toFloat()) - - // y-coordinate is the same throughout this animation - val yCoord = windowRect.centerY().toFloat() - - var adjustedSteps = MIN_STEPS_TO_ANIMATE - - // if distance per step is at least 1, then we can use the number of steps requested - if (distDecrease.toInt() / (steps * 2) >= 1) { - adjustedSteps = steps - } - - // if the distance per step is less than 1, carry out the animation in two steps - gestureHelper.pinch( - GestureHelper.Tuple(initLeftX, yCoord), - GestureHelper.Tuple(initRightX, yCoord), - GestureHelper.Tuple(finalLeftX, yCoord), - GestureHelper.Tuple(finalRightX, yCoord), - adjustedSteps - ) - - waitForPipWindowToMinimizeFrom(wmHelper, Region(windowRect)) - } - /** * Launches the app through an intent instead of interacting with the launcher and waits until * the app window is in PIP mode @@ -331,126 +145,6 @@ open class PipAppHelper(instrumentation: Instrumentation) : closePipWindow(WindowManagerStateHelper(instrumentation)) } - /** Returns the pip window bounds. */ - fun getWindowRect(wmHelper: WindowManagerStateHelper): Rect { - val windowRegion = wmHelper.getWindowRegion(this) - require(!windowRegion.isEmpty) { "Unable to find a PIP window in the current state" } - return windowRegion.bounds - } - - /** Taps the pip window and dismisses it by clicking on the X button. */ - open fun closePipWindow(wmHelper: WindowManagerStateHelper) { - val windowRect = getWindowRect(wmHelper) - uiDevice.click(windowRect.centerX(), windowRect.centerY()) - // search and interact with the dismiss button - val dismissSelector = By.res(SYSTEMUI_PACKAGE, "dismiss") - uiDevice.wait(Until.hasObject(dismissSelector), FIND_TIMEOUT) - val dismissPipObject = - uiDevice.findObject(dismissSelector) ?: error("PIP window dismiss button not found") - val dismissButtonBounds = dismissPipObject.visibleBounds - uiDevice.click(dismissButtonBounds.centerX(), dismissButtonBounds.centerY()) - - // Wait for animation to complete. - wmHelper.StateSyncBuilder().withPipGone().withHomeActivityVisible().waitForAndVerify() - } - - open fun tapPipToShowMenu(wmHelper: WindowManagerStateHelper) { - val windowRect = getWindowRect(wmHelper) - uiDevice.click(windowRect.centerX(), windowRect.centerY()) - // search and interact with the dismiss button - val dismissSelector = By.res(SYSTEMUI_PACKAGE, "dismiss") - uiDevice.wait(Until.hasObject(dismissSelector), FIND_TIMEOUT) - } - - /** Close the pip window by pressing the expand button */ - fun expandPipWindowToApp(wmHelper: WindowManagerStateHelper) { - val windowRect = getWindowRect(wmHelper) - uiDevice.click(windowRect.centerX(), windowRect.centerY()) - // search and interact with the expand button - val expandSelector = By.res(SYSTEMUI_PACKAGE, "expand_button") - uiDevice.wait(Until.hasObject(expandSelector), FIND_TIMEOUT) - val expandPipObject = - uiDevice.findObject(expandSelector) ?: error("PIP window expand button not found") - val expandButtonBounds = expandPipObject.visibleBounds - uiDevice.click(expandButtonBounds.centerX(), expandButtonBounds.centerY()) - wmHelper.StateSyncBuilder().withPipGone().withFullScreenApp(this).waitForAndVerify() - } - - /** Double click on the PIP window to expand it */ - fun doubleClickPipWindow(wmHelper: WindowManagerStateHelper) { - val windowRect = getWindowRect(wmHelper) - Log.d(TAG, "First click") - uiDevice.click(windowRect.centerX(), windowRect.centerY()) - Log.d(TAG, "Second click") - uiDevice.click(windowRect.centerX(), windowRect.centerY()) - Log.d(TAG, "Wait for app transition to end") - wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify() - waitForPipWindowToExpandFrom(wmHelper, Region(windowRect)) - } - - private fun waitForPipWindowToExpandFrom( - wmHelper: WindowManagerStateHelper, - windowRect: Region - ) { - wmHelper - .StateSyncBuilder() - .add("pipWindowExpanded") { - val pipAppWindow = - it.wmState.visibleWindows.firstOrNull { window -> - this.windowMatchesAnyOf(window) - } - ?: return@add false - val pipRegion = pipAppWindow.frameRegion - return@add pipRegion.coversMoreThan(windowRect) - } - .waitForAndVerify() - } - - private fun waitForPipWindowToMinimizeFrom( - wmHelper: WindowManagerStateHelper, - windowRect: Region - ) { - wmHelper - .StateSyncBuilder() - .add("pipWindowMinimized") { - val pipAppWindow = - it.wmState.visibleWindows.firstOrNull { window -> - this.windowMatchesAnyOf(window) - } - Log.d(TAG, "window " + pipAppWindow) - if (pipAppWindow == null) return@add false - val pipRegion = pipAppWindow.frameRegion - Log.d( - TAG, - "region " + pipRegion + " covers " + windowRect.coversMoreThan(pipRegion) - ) - return@add windowRect.coversMoreThan(pipRegion) - } - .waitForAndVerify() - } - - /** - * Waits until the PIP window snaps horizontally to the provided bounds. - * - * @param finalBounds the bounds to wait for PIP window to snap to - */ - 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 - } - .add(ConditionsFactory.isWMStateComplete()) - .waitForAndVerify() - } - companion object { private const val TAG = "PipAppHelper" private const val ENTER_PIP_BUTTON_ID = "enter_pip" @@ -459,8 +153,5 @@ open class PipAppHelper(instrumentation: Instrumentation) : private const val ENTER_PIP_ON_USER_LEAVE_HINT = "enter_pip_on_leave_manual" private const val ENTER_PIP_AUTOENTER = "enter_pip_on_leave_autoenter" private const val SOURCE_RECT_HINT = "set_source_rect_hint" - // minimum number of steps to take, when animating gestures, needs to be 2 - // so that there is at least a single intermediate layer that flicker tests can check - private const val MIN_STEPS_TO_ANIMATE = 2 } -} +}
\ No newline at end of file |