diff options
16 files changed, 834 insertions, 634 deletions
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/Extensions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/Extensions.kt new file mode 100644 index 000000000000..1869d833fbc4 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/Extensions.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2021 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. + */ + +@file:JvmName("Utils") +package com.android.wm.shell.flicker + +import android.app.ActivityTaskManager +import android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT +import android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS +import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD +import android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED + +fun removeAllTasksButHome() { + val ALL_ACTIVITY_TYPE_BUT_HOME = intArrayOf( + ACTIVITY_TYPE_STANDARD, ACTIVITY_TYPE_ASSISTANT, ACTIVITY_TYPE_RECENTS, + ACTIVITY_TYPE_UNDEFINED) + val atm = ActivityTaskManager.getService() + atm.removeRootTasksWithActivityTypes(ALL_ACTIVITY_TYPE_BUT_HOME) +} diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt index 7ec22bb9db1c..cac46fe676b3 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt @@ -32,13 +32,12 @@ open class ImeAppHelper(instrumentation: Instrumentation) : BaseAppHelper( /** * Opens the IME and wait for it to be displayed * - * @param device UIDevice instance to interact with the device * @param wmHelper Helper used to wait for WindowManager states */ @JvmOverloads - open fun openIME(device: UiDevice, wmHelper: WindowManagerStateHelper? = null) { + open fun openIME(wmHelper: WindowManagerStateHelper? = null) { if (!isTelevision) { - val editText = device.wait( + val editText = uiDevice.wait( Until.findObject(By.res(getPackage(), "plain_text_input")), FIND_TIMEOUT) @@ -47,7 +46,7 @@ open class ImeAppHelper(instrumentation: Instrumentation) : BaseAppHelper( "was left in an unknown state (e.g. in split screen)" } editText.click() - waitAndAssertIMEShown(device, wmHelper) + waitAndAssertIMEShown(uiDevice, wmHelper) } else { // If we do the same thing as above - editText.click() - on TV, that's going to force TV // into the touch mode. We really don't want that. @@ -69,16 +68,15 @@ open class ImeAppHelper(instrumentation: Instrumentation) : BaseAppHelper( /** * Opens the IME and wait for it to be gone * - * @param device UIDevice instance to interact with the device * @param wmHelper Helper used to wait for WindowManager states */ @JvmOverloads - open fun closeIME(device: UiDevice, wmHelper: WindowManagerStateHelper? = null) { + open fun closeIME(wmHelper: WindowManagerStateHelper? = null) { if (!isTelevision) { - device.pressBack() + uiDevice.pressBack() // Using only the AccessibilityInfo it is not possible to identify if the IME is active if (wmHelper == null) { - device.waitForIdle() + uiDevice.waitForIdle() } else { require(wmHelper.waitImeWindowGone()) { "IME did did not close" } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt index b90e865de691..111362a93495 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt @@ -17,17 +17,20 @@ package com.android.wm.shell.flicker.helpers import android.app.Instrumentation +import android.graphics.Point import android.media.session.MediaController import android.media.session.MediaSessionManager import android.os.SystemClock import androidx.test.uiautomator.By import androidx.test.uiautomator.BySelector +import com.android.server.wm.flicker.helpers.SYSTEMUI_PACKAGE import com.android.server.wm.flicker.helpers.closePipWindow -import com.android.server.wm.flicker.helpers.hasPipWindow +import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper import com.android.wm.shell.flicker.pip.tv.closeTvPipWindow import com.android.wm.shell.flicker.pip.tv.isFocusedOrHasFocusedChild +import com.android.wm.shell.flicker.pip.waitPipWindowGone +import com.android.wm.shell.flicker.pip.waitPipWindowShown import com.android.wm.shell.flicker.testapp.Components -import org.junit.Assert.fail class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper( instrumentation, @@ -55,6 +58,17 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper( } } + /** {@inheritDoc} */ + override fun launchViaIntent( + wmHelper: WindowManagerStateHelper, + expectedWindowName: String, + action: String?, + stringExtras: Map<String, String> + ) { + super.launchViaIntent(wmHelper, expectedWindowName, action, stringExtras) + wmHelper.waitPipWindowShown() + } + private fun focusOnObject(selector: BySelector): Boolean { // We expect all the focusable UI elements to be arranged in a way so that it is possible // to "cycle" over all them by clicking the D-Pad DOWN button, going back up to "the top" @@ -69,16 +83,12 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper( return false } - fun clickEnterPipButton() { + @JvmOverloads + fun clickEnterPipButton(wmHelper: WindowManagerStateHelper? = null) { clickObject(ENTER_PIP_BUTTON_ID) - // TODO(b/172321238): remove this check once hasPipWindow is fixed on TVs - if (!isTelevision) { - uiDevice.hasPipWindow() - } else { - // Simply wait for 3 seconds - SystemClock.sleep(3_000) - } + // Wait on WMHelper or simply wait for 3 seconds + wmHelper?.waitPipWindowShown() ?: SystemClock.sleep(3_000) } fun clickStartMediaSessionButton() { @@ -97,16 +107,75 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper( fun stopMedia() = mediaController?.transportControls?.stop() ?: error("No active media session found") + @Deprecated("Use PipAppHelper.closePipWindow(wmHelper) instead", + ReplaceWith("closePipWindow(wmHelper)")) fun closePipWindow() { if (isTelevision) { uiDevice.closeTvPipWindow() } else { uiDevice.closePipWindow() } + } + + /** + * Expands the pip window and dismisses it by clicking on the X button. + * + * Note, currently the View coordinates reported by the accessibility are relative to + * the window, so the correct coordinates need to be calculated + * + * For example, in a PIP window located at Rect(508, 1444 - 1036, 1741), the + * dismiss button coordinates are shown as Rect(650, 0 - 782, 132), with center in + * Point(716, 66), instead of Point(970, 1403) + * + * See b/179337864 + */ + fun closePipWindow(wmHelper: WindowManagerStateHelper) { + if (isTelevision) { + uiDevice.closeTvPipWindow() + } else { + expandPipWindow(wmHelper) + val exitPipObject = uiDevice.findObject(By.res(SYSTEMUI_PACKAGE, "dismiss")) + requireNotNull(exitPipObject) { "PIP window dismiss button not found" } + val coordinatesInWindow = exitPipObject.visibleBounds + val windowOffset = wmHelper.getWindowRegion(component).bounds + val newCoordinates = Point(windowOffset.left + coordinatesInWindow.centerX(), + windowOffset.top + coordinatesInWindow.centerY()) + uiDevice.click(newCoordinates.x, newCoordinates.y) + } + + // Wait for animation to complete. + wmHelper.waitPipWindowGone() + wmHelper.waitForHomeActivityVisible() + } + + /** + * Click once on the PIP window to expand it + */ + fun expandPipWindow(wmHelper: WindowManagerStateHelper) { + val windowRegion = wmHelper.getWindowRegion(component) + require(!windowRegion.isEmpty) { + "Unable to find a PIP window in the current state" + } + val windowRect = windowRegion.bounds + uiDevice.click(windowRect.centerX(), windowRect.centerY()) + // Ensure WindowManagerService wait until all animations have completed + wmHelper.waitForAppTransitionIdle() + mInstrumentation.uiAutomation.syncInputTransactions() + } - if (!waitUntilClosed()) { - fail("Couldn't close Pip") + /** + * Double click on the PIP window to reopen to app + */ + fun expandPipWindowToApp(wmHelper: WindowManagerStateHelper) { + val windowRegion = wmHelper.getWindowRegion(component) + require(!windowRegion.isEmpty) { + "Unable to find a PIP window in the current state" } + val windowRect = windowRegion.bounds + uiDevice.click(windowRect.centerX(), windowRect.centerY()) + uiDevice.click(windowRect.centerX(), windowRect.centerY()) + wmHelper.waitPipWindowGone() + wmHelper.waitForAppTransitionIdle() } companion object { diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AppTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AppTestBase.kt index 2015f4941cea..bc42d5ed04ce 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AppTestBase.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AppTestBase.kt @@ -16,11 +16,6 @@ package com.android.wm.shell.flicker.pip -import android.app.ActivityTaskManager -import android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT -import android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS -import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD -import android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED import android.os.SystemClock import com.android.wm.shell.flicker.NonRotationTestBase @@ -29,14 +24,6 @@ abstract class AppTestBase( rotation: Int ) : NonRotationTestBase(rotationName, rotation) { companion object { - fun removeAllTasksButHome() { - val ALL_ACTIVITY_TYPE_BUT_HOME = intArrayOf( - ACTIVITY_TYPE_STANDARD, ACTIVITY_TYPE_ASSISTANT, ACTIVITY_TYPE_RECENTS, - ACTIVITY_TYPE_UNDEFINED) - val atm = ActivityTaskManager.getService() - atm.removeRootTasksWithActivityTypes(ALL_ACTIVITY_TYPE_BUT_HOME) - } - fun waitForAnimationComplete() { // TODO: UiDevice doesn't have reliable way to wait for the completion of animation. // Consider to introduce WindowManagerStateHelper to access Activity state. diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt index 5a3d18d9feef..a14b46ef7a3d 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt @@ -16,21 +16,21 @@ package com.android.wm.shell.flicker.pip -import android.platform.test.annotations.Presubmit +import android.os.Bundle import android.view.Surface import androidx.test.filters.RequiresDevice -import com.android.server.wm.flicker.dsl.runFlicker +import androidx.test.platform.app.InstrumentationRegistry +import com.android.server.wm.flicker.FlickerTestRunner +import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.helpers.WindowUtils -import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen import com.android.wm.shell.flicker.helpers.FixedAppHelper -import com.android.wm.shell.flicker.helpers.PipAppHelper import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible +import com.android.server.wm.flicker.startRotation import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible -import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP import org.junit.FixMethodOrder -import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -39,82 +39,67 @@ import org.junit.runners.Parameterized * Test Pip launch and exit. * To run this test: `atest WMShellFlickerTests:EnterExitPipTest` */ -@Presubmit @RequiresDevice @RunWith(Parameterized::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) class EnterExitPipTest( - rotationName: String, - rotation: Int -) : AppTestBase(rotationName, rotation) { - private val pipApp = PipAppHelper(instrumentation) - private val testApp = FixedAppHelper(instrumentation) - - @Test - fun testDisplayMetricsPinUnpin() { - runFlicker(instrumentation) { - withTestName { "testDisplayMetricsPinUnpin" } - setup { - test { - removeAllTasksButHome() - device.wakeUpAndGoToHomeScreen() - pipApp.launchViaIntent(stringExtras = mapOf(EXTRA_ENTER_PIP to "true")) - testApp.launchViaIntent() - waitForAnimationComplete() - } - } - transitions { - // This will bring PipApp to fullscreen - pipApp.launchViaIntent() - waitForAnimationComplete() - } - teardown { - test { - removeAllTasksButHome() - } - } - assertions { - val displayBounds = WindowUtils.getDisplayBounds(rotation) - windowManagerTrace { - all("pipApp must remain inside visible bounds") { - coversAtMostRegion(pipApp.defaultWindowName, displayBounds) - } - all("Initially shows both app windows then pipApp hides testApp") { - showsAppWindow(testApp.defaultWindowName) - .showsAppWindowOnTop(pipApp.defaultWindowName) - .then() - .hidesAppWindow(testApp.defaultWindowName) + testSpec: FlickerTestRunnerFactory.TestSpec +) : FlickerTestRunner(testSpec) { + companion object : PipTransitionBase(InstrumentationRegistry.getInstrumentation()) { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): List<Array<Any>> { + val testApp = FixedAppHelper(instrumentation) + val baseConfig = getTransitionLaunch(eachRun = true) + val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration -> + setup { + eachRun { + testApp.launchViaIntent(wmHelper) } - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() } - layersTrace { - all("Initially shows both app layers then pipApp hides testApp") { - showsLayer(testApp.defaultWindowName) - .showsLayer(pipApp.defaultWindowName) - .then() - .hidesLayer(testApp.defaultWindowName) - } - start("testApp covers the fullscreen, pipApp remains inside display") { - hasVisibleRegion(testApp.defaultWindowName, displayBounds) - coversAtMostRegion(displayBounds, pipApp.defaultWindowName) - } - end("pipApp covers the fullscreen") { - hasVisibleRegion(pipApp.defaultWindowName, displayBounds) + transitions { + // This will bring PipApp to fullscreen + pipApp.launchViaIntent(wmHelper) + } + assertions { + val displayBounds = WindowUtils.getDisplayBounds(configuration.startRotation) + presubmit { + windowManagerTrace { + all("pipApp must remain inside visible bounds") { + coversAtMostRegion(pipApp.defaultWindowName, displayBounds) + } + all("Initially shows both app windows then pipApp hides testApp") { + showsAppWindow(testApp.defaultWindowName) + .showsAppWindowOnTop(pipApp.defaultWindowName) + .then() + .hidesAppWindow(testApp.defaultWindowName) + } + navBarWindowIsAlwaysVisible() + statusBarWindowIsAlwaysVisible() + } + layersTrace { + all("Initially shows both app layers then pipApp hides testApp") { + showsLayer(testApp.defaultWindowName) + .showsLayer(pipApp.defaultWindowName) + .then() + .hidesLayer(testApp.defaultWindowName) + } + start("testApp covers the fullscreen, pipApp remains inside display") { + hasVisibleRegion(testApp.defaultWindowName, displayBounds) + coversAtMostRegion(displayBounds, pipApp.defaultWindowName) + } + end("pipApp covers the fullscreen") { + hasVisibleRegion(pipApp.defaultWindowName, displayBounds) + } + navBarLayerIsAlwaysVisible() + statusBarLayerIsAlwaysVisible() + } } - navBarLayerIsAlwaysVisible() - statusBarLayerIsAlwaysVisible() } } - } - } - - companion object { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection<Array<Any>> { - val supportedRotations = intArrayOf(Surface.ROTATION_0) - return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) } + return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation, baseConfig, + testSpec, supportedRotations = listOf(Surface.ROTATION_0), + repetitions = 5) } } }
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt index af62eb9ae40d..99a40daa027f 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt @@ -16,18 +16,13 @@ package com.android.wm.shell.flicker.pip +import android.os.Bundle import android.view.Surface -import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import androidx.test.platform.app.InstrumentationRegistry import com.android.server.wm.flicker.FlickerTestRunner import com.android.server.wm.flicker.FlickerTestRunnerFactory -import com.android.server.wm.flicker.helpers.buildTestTag -import com.android.server.wm.flicker.helpers.closePipWindow -import com.android.server.wm.flicker.helpers.expandPipWindow -import com.android.server.wm.flicker.helpers.hasPipWindow -import com.android.server.wm.flicker.helpers.setRotation -import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen +import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible import com.android.server.wm.flicker.navBarLayerRotatesAndScales import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible @@ -35,9 +30,7 @@ import com.android.server.wm.flicker.statusBarLayerRotatesScales import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible import com.android.server.wm.flicker.noUncoveredRegions -import com.android.server.wm.flicker.repetitions import com.android.server.wm.flicker.startRotation -import com.android.wm.shell.flicker.helpers.PipAppHelper import org.junit.FixMethodOrder import org.junit.runner.RunWith import org.junit.runners.MethodSorters @@ -50,80 +43,58 @@ import org.junit.runners.Parameterized @RequiresDevice @RunWith(Parameterized::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -@FlakyTest(bugId = 152738416) class EnterPipTest( testSpec: FlickerTestRunnerFactory.TestSpec ) : FlickerTestRunner(testSpec) { - companion object { + companion object : PipTransitionBase(InstrumentationRegistry.getInstrumentation()) { @Parameterized.Parameters(name = "{0}") @JvmStatic fun getParams(): List<Array<Any>> { - val instrumentation = InstrumentationRegistry.getInstrumentation() - val testApp = PipAppHelper(instrumentation) - return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation, - supportedRotations = listOf(Surface.ROTATION_0)) { configuration -> - withTestName { buildTestTag("enterPip", testApp, configuration) } - repeat { configuration.repetitions } - setup { - test { - device.wakeUpAndGoToHomeScreen() - } - eachRun { - device.pressHome() - testApp.launchViaIntent(wmHelper) - this.setRotation(configuration.startRotation) - } - } - teardown { - eachRun { - if (device.hasPipWindow()) { - device.closePipWindow() - } - testApp.exit() - this.setRotation(Surface.ROTATION_0) - } - test { - if (device.hasPipWindow()) { - device.closePipWindow() - } - } - } - transitions { - testApp.clickEnterPipButton() - device.expandPipWindow() - } - assertions { + val baseConfig = getTransitionLaunch( + eachRun = true, stringExtras = emptyMap()) + val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration -> + transitions { + pipApp.clickEnterPipButton() + pipApp.expandPipWindow(wmHelper) + } + assertions { + presubmit { windowManagerTrace { navBarWindowIsAlwaysVisible() statusBarWindowIsAlwaysVisible() all("pipWindowBecomesVisible") { - this.showsAppWindow(testApp.`package`) - .then() - .showsAppWindow(PIP_WINDOW_TITLE) + this.showsAppWindow(pipApp.defaultWindowName) } } layersTrace { - navBarLayerIsAlwaysVisible(bugId = 140855415) statusBarLayerIsAlwaysVisible() - noUncoveredRegions(configuration.startRotation, Surface.ROTATION_0, - enabled = false) - navBarLayerRotatesAndScales(configuration.startRotation, - Surface.ROTATION_0, bugId = 140855415) statusBarLayerRotatesScales(configuration.startRotation, Surface.ROTATION_0) } layersTrace { all("pipLayerBecomesVisible") { - this.showsLayer(testApp.launcherName) - .then() - .showsLayer(PIP_WINDOW_TITLE) + this.showsLayer(pipApp.launcherName) } } } + + flaky { + layersTrace { + navBarLayerIsAlwaysVisible(bugId = 140855415) + noUncoveredRegions(configuration.startRotation, Surface.ROTATION_0) + navBarLayerRotatesAndScales(configuration.startRotation, + Surface.ROTATION_0, bugId = 140855415) + } + } } + } + + return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation, baseConfig, + testSpec, supportedRotations = listOf(Surface.ROTATION_0), + repetitions = 5) } } }
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt new file mode 100644 index 000000000000..eaaa2f6390be --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2021 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.view.Surface +import androidx.test.filters.RequiresDevice +import androidx.test.platform.app.InstrumentationRegistry +import com.android.server.wm.flicker.FlickerTestRunner +import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.helpers.WindowUtils +import com.android.wm.shell.flicker.helpers.FixedAppHelper +import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible +import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible +import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible +import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible +import com.android.wm.shell.flicker.pip.PipTransitionBase.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE +import com.android.wm.shell.flicker.pip.PipTransitionBase.BroadcastActionTrigger.Companion.ORIENTATION_PORTRAIT +import com.android.wm.shell.flicker.testapp.Components.PipActivity.ACTION_ENTER_PIP +import com.android.wm.shell.flicker.testapp.Components.FixedActivity.EXTRA_FIXED_ORIENTATION +import org.junit.FixMethodOrder +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters +import org.junit.runners.Parameterized + +/** + * Test Pip with orientation changes. + * To run this test: `atest WMShellFlickerTests:PipOrientationTest` + */ +@RequiresDevice +@RunWith(Parameterized::class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +class EnterPipToOtherOrientationTest( + testSpec: FlickerTestRunnerFactory.TestSpec +) : FlickerTestRunner(testSpec) { + companion object : PipTransitionBase(InstrumentationRegistry.getInstrumentation()) { + private val testApp = FixedAppHelper(instrumentation) + + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): Collection<Array<Any>> { + return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation, + supportedRotations = listOf(Surface.ROTATION_0), + repetitions = 5) { configuration -> + setupAndTeardown(this, configuration) + + setup { + eachRun { + // Launch a portrait only app on the fullscreen stack + testApp.launchViaIntent(wmHelper, stringExtras = mapOf( + EXTRA_FIXED_ORIENTATION to ORIENTATION_PORTRAIT.toString())) + // Launch the PiP activity fixed as landscape + pipApp.launchViaIntent(wmHelper, stringExtras = mapOf( + EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString())) + } + } + teardown { + eachRun { + pipApp.exit() + testApp.exit() + } + } + transitions { + // Enter PiP, and assert that the PiP is within bounds now that the device is back + // in portrait + broadcastActionTrigger.doAction(ACTION_ENTER_PIP) + wmHelper.waitPipWindowShown() + wmHelper.waitForAppTransitionIdle() + } + assertions { + val startingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_90) + val endingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_0) + + presubmit { + windowManagerTrace { + all("pipApp window is always on top") { + showsAppWindowOnTop(pipApp.defaultWindowName) + } + start("pipApp window hides testApp") { + isInvisible(testApp.defaultWindowName) + } + end("testApp windows is shown") { + isVisible(testApp.defaultWindowName) + } + navBarWindowIsAlwaysVisible() + statusBarWindowIsAlwaysVisible() + } + + layersTrace { + start("pipApp layer hides testApp") { + hasVisibleRegion(pipApp.defaultWindowName, startingBounds) + isInvisible(testApp.defaultWindowName) + } + } + } + + flaky { + layersTrace { + end("testApp layer covers fullscreen") { + hasVisibleRegion(testApp.defaultWindowName, endingBounds) + } + navBarLayerIsAlwaysVisible(bugId = 140855415) + statusBarLayerIsAlwaysVisible(bugId = 140855415) + } + } + } + } + } + } +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/Extensions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/Extensions.kt new file mode 100644 index 000000000000..707d28d9c4c0 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/Extensions.kt @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2021 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.app.WindowConfiguration +import android.content.ComponentName +import com.android.server.wm.flicker.traces.windowmanager.WindowManagerStateSubject +import com.android.server.wm.traces.common.windowmanager.WindowManagerState +import com.android.server.wm.traces.parser.toWindowName +import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper +import com.google.common.truth.Truth + +inline val WindowManagerState.pinnedWindows + get() = visibleWindows + .filter { it.windowingMode == WindowConfiguration.WINDOWING_MODE_PINNED } + +/** + * Checks if the state has any window in PIP mode + */ +fun WindowManagerState.hasPipWindow(): Boolean = pinnedWindows.isNotEmpty() + +/** + * Checks that an activity [activity] is in PIP mode + */ +fun WindowManagerState.isInPipMode(activity: ComponentName): Boolean { + val windowName = activity.toWindowName() + return pinnedWindows.any { it.title == windowName } +} + +/** + * Asserts that an activity [activity] exists and is in PIP mode + */ +fun WindowManagerStateSubject.isInPipMode( + activity: ComponentName +): WindowManagerStateSubject = apply { + val windowName = activity.toWindowName() + hasWindow(windowName) + val pinnedWindows = wmState.pinnedWindows + .map { it.title } + Truth.assertWithMessage("Window not in PIP mode") + .that(pinnedWindows) + .contains(windowName) +} + +/** + * Waits until the state has a window in PIP mode, i.e., with + * windowingMode = WindowConfiguration.WINDOWING_MODE_PINNED + */ +fun WindowManagerStateHelper.waitPipWindowShown(): Boolean = + waitFor("PIP window shown") { + val result = it.wmState.hasPipWindow() + result + } + +/** + * Waits until the state doesn't have a window in PIP mode, i.e., with + * windowingMode = WindowConfiguration.WINDOWING_MODE_PINNED + */ +fun WindowManagerStateHelper.waitPipWindowGone(): Boolean = + waitFor("PIP window gone") { + val result = !it.wmState.hasPipWindow() + result + } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt index c21b594246b9..7576e24ace19 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt @@ -16,21 +16,19 @@ package com.android.wm.shell.flicker.pip -import android.platform.test.annotations.Presubmit +import android.os.Bundle import android.view.Surface import androidx.test.filters.RequiresDevice +import androidx.test.platform.app.InstrumentationRegistry +import com.android.server.wm.flicker.FlickerTestRunner +import com.android.server.wm.flicker.FlickerTestRunnerFactory import com.android.server.wm.flicker.dsl.FlickerBuilder -import com.android.server.wm.flicker.dsl.runWithFlicker import com.android.server.wm.flicker.helpers.WindowUtils -import com.android.server.wm.flicker.helpers.closePipWindow -import com.android.server.wm.flicker.helpers.hasPipWindow -import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen -import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper +import com.android.server.wm.flicker.helpers.setRotation +import com.android.server.wm.flicker.startRotation import com.android.wm.shell.flicker.IME_WINDOW_NAME import com.android.wm.shell.flicker.helpers.ImeAppHelper -import com.android.wm.shell.flicker.testapp.Components import org.junit.FixMethodOrder -import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters import org.junit.runners.Parameterized @@ -39,114 +37,61 @@ import org.junit.runners.Parameterized * Test Pip launch. * To run this test: `atest WMShellFlickerTests:PipKeyboardTest` */ -@Presubmit @RequiresDevice @RunWith(Parameterized::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -class PipKeyboardTest( - rotationName: String, - rotation: Int -) : PipTestBase(rotationName, rotation) { - private val keyboardApp = ImeAppHelper(instrumentation) - private val keyboardComponent = Components.ImeActivity.COMPONENT - private val helper = WindowManagerStateHelper() +class PipKeyboardTest(testSpec: FlickerTestRunnerFactory.TestSpec) : FlickerTestRunner(testSpec) { + companion object : PipTransitionBase(InstrumentationRegistry.getInstrumentation()) { + private const val TAG_IME_VISIBLE = "imeIsVisible" - private val keyboardScenario: FlickerBuilder - get() = FlickerBuilder(instrumentation).apply { - repeat { TEST_REPETITIONS } - // disable layer tracing - withLayerTracing { null } - setup { - test { - device.wakeUpAndGoToHomeScreen() - device.pressHome() - // launch our target pip app - testApp.launchViaIntent(wmHelper) - this.setRotation(rotation) - testApp.clickEnterPipButton() - // open an app with an input field and a keyboard - // UiAutomator doesn't support to launch the multiple Activities in a task. - // So use launchActivity() for the Keyboard Activity. - keyboardApp.launchViaIntent() - helper.waitForAppTransitionIdle() - helper.waitForFullScreenApp(keyboardComponent) - } - } - teardown { - test { - keyboardApp.exit() - - if (device.hasPipWindow()) { - device.closePipWindow() + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): Collection<Array<Any>> { + val imeApp = ImeAppHelper(instrumentation) + val baseConfig = getTransitionLaunch(eachRun = false) + val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration -> + setup { + test { + imeApp.launchViaIntent(wmHelper) + setRotation(configuration.startRotation) } - testApp.exit() - this.setRotation(Surface.ROTATION_0) } - } - } - - /** Ensure the pip window remains visible throughout any keyboard interactions. */ - @Test - fun pipWindow_doesNotLeaveTheScreen_onKeyboardOpenClose() { - val testTag = "pipWindow_doesNotLeaveTheScreen_onKeyboardOpenClose" - runWithFlicker(keyboardScenario) { - withTestName { testTag } - transitions { - // open the soft keyboard - keyboardApp.openIME(device, wmHelper) - helper.waitImeWindowShown() - - // then close it again - keyboardApp.closeIME(device, wmHelper) - helper.waitImeWindowGone() - } - assertions { - windowManagerTrace { - all("PiP window must remain inside visible bounds") { - val displayBounds = WindowUtils.getDisplayBounds(rotation) - coversAtMostRegion(testApp.defaultWindowName, displayBounds) + teardown { + test { + imeApp.exit() + setRotation(Surface.ROTATION_0) } } - } - } - } + transitions { + // open the soft keyboard + imeApp.openIME(wmHelper) + createTag(TAG_IME_VISIBLE) - /** Ensure the pip window does not obscure the keyboard. */ - @Test - fun pipWindow_doesNotObscure_keyboard() { - val testTag = "pipWindow_doesNotObscure_keyboard" - runWithFlicker(keyboardScenario) { - withTestName { testTag } - transitions { - // open the soft keyboard - keyboardApp.openIME(device, wmHelper) - helper.waitImeWindowShown() - } - teardown { - eachRun { - // close the keyboard - keyboardApp.closeIME(device, wmHelper) - helper.waitImeWindowGone() + // then close it again + imeApp.closeIME(wmHelper) } - } - assertions { - windowManagerTrace { - end("imeWindowAboveApp") { - isAboveWindow(IME_WINDOW_NAME, testApp.defaultWindowName) + assertions { + presubmit { + windowManagerTrace { + // Ensure the pip window remains visible throughout + // any keyboard interactions + all("pipInVisibleBounds") { + val displayBounds = WindowUtils.getDisplayBounds( + configuration.startRotation) + coversAtMostRegion(pipApp.defaultWindowName, displayBounds) + } + // Ensure that the pip window does not obscure the keyboard + tag(TAG_IME_VISIBLE) { + isAboveWindow(IME_WINDOW_NAME, pipApp.defaultWindowName) + } + } } } } - } - } - - companion object { - private const val TEST_REPETITIONS = 5 - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection<Array<Any>> { - val supportedRotations = intArrayOf(Surface.ROTATION_0) - return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) } + return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation, + baseConfig, testSpec, supportedRotations = listOf(Surface.ROTATION_0), + repetitions = 5) } } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt index e5790962c025..f10bd7f1e45a 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt @@ -32,6 +32,7 @@ import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible +import com.android.wm.shell.flicker.removeAllTasksButHome import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP import org.junit.FixMethodOrder import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipOrientationTest.kt deleted file mode 100644 index 5e0760ceeda7..000000000000 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipOrientationTest.kt +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright (C) 2020 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.content.Intent -import android.platform.test.annotations.Presubmit -import android.view.Surface -import androidx.test.filters.RequiresDevice -import com.android.server.wm.flicker.dsl.runFlicker -import com.android.server.wm.flicker.helpers.WindowUtils -import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen -import com.android.wm.shell.flicker.helpers.FixedAppHelper -import com.android.wm.shell.flicker.helpers.PipAppHelper -import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible -import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible -import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible -import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible -import com.android.wm.shell.flicker.testapp.Components.PipActivity.ACTION_ENTER_PIP -import com.android.wm.shell.flicker.testapp.Components.PipActivity.ACTION_SET_REQUESTED_ORIENTATION -import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP -import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_PIP_ORIENTATION -import com.android.wm.shell.flicker.testapp.Components.FixedActivity.EXTRA_FIXED_ORIENTATION -import org.junit.Assert.assertEquals -import org.junit.FixMethodOrder -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.MethodSorters -import org.junit.runners.Parameterized - -/** - * Test Pip with orientation changes. - * To run this test: `atest WMShellFlickerTests:PipOrientationTest` - */ -@Presubmit -@RequiresDevice -@RunWith(Parameterized::class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -class PipOrientationTest( - rotationName: String, - rotation: Int -) : AppTestBase(rotationName, rotation) { - // Helper class to process test actions by broadcast. - private inner class BroadcastActionTrigger { - private fun createIntentWithAction(broadcastAction: String): Intent { - return Intent(broadcastAction).setFlags(Intent.FLAG_RECEIVER_FOREGROUND) - } - fun doAction(broadcastAction: String) { - instrumentation.getContext().sendBroadcast(createIntentWithAction(broadcastAction)) - } - fun requestOrientationForPip(orientation: Int) { - instrumentation.getContext() - .sendBroadcast(createIntentWithAction(ACTION_SET_REQUESTED_ORIENTATION) - .putExtra(EXTRA_PIP_ORIENTATION, orientation.toString())) - } - } - private val broadcastActionTrigger = BroadcastActionTrigger() - - // Corresponds to ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE - private val ORIENTATION_LANDSCAPE = 0 - // Corresponds to ActivityInfo.SCREEN_ORIENTATION_PORTRAIT - private val ORIENTATION_PORTRAIT = 1 - - private val testApp = FixedAppHelper(instrumentation) - private val pipApp = PipAppHelper(instrumentation) - - @Test - fun testEnterPipToOtherOrientation() { - runFlicker(instrumentation) { - withTestName { "testEnterPipToOtherOrientation" } - setup { - test { - removeAllTasksButHome() - device.wakeUpAndGoToHomeScreen() - // Launch a portrait only app on the fullscreen stack - testApp.launchViaIntent(stringExtras = mapOf( - EXTRA_FIXED_ORIENTATION to ORIENTATION_PORTRAIT.toString())) - waitForAnimationComplete() - // Launch the PiP activity fixed as landscape - pipApp.launchViaIntent(stringExtras = mapOf( - EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString())) - waitForAnimationComplete() - } - } - transitions { - // Enter PiP, and assert that the PiP is within bounds now that the device is back - // in portrait - broadcastActionTrigger.doAction(ACTION_ENTER_PIP) - waitForAnimationComplete() - } - teardown { - test { - removeAllTasksButHome() - } - } - assertions { - windowManagerTrace { - all("pipApp window is always on top") { - showsAppWindowOnTop(pipApp.defaultWindowName) - } - start("pipApp window hides testApp") { - isInvisible(testApp.defaultWindowName) - } - end("testApp windows is shown") { - isVisible(testApp.defaultWindowName) - } - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() - } - layersTrace { - val startingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_90) - val endingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_0) - start("pipApp layer hides testApp") { - hasVisibleRegion(pipApp.defaultWindowName, startingBounds) - isInvisible(testApp.defaultWindowName) - } - end("testApp layer covers fullscreen", enabled = false) { - hasVisibleRegion(testApp.defaultWindowName, endingBounds) - } - navBarLayerIsAlwaysVisible(bugId = 140855415) - statusBarLayerIsAlwaysVisible(bugId = 140855415) - } - } - } - } - - @Test - fun testSetRequestedOrientationWhilePinned() { - runFlicker(instrumentation) { - withTestName { "testSetRequestedOrientationWhilePinned" } - setup { - test { - removeAllTasksButHome() - device.wakeUpAndGoToHomeScreen() - // Launch the PiP activity fixed as landscape - pipApp.launchViaIntent(stringExtras = mapOf( - EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString(), - EXTRA_ENTER_PIP to "true")) - waitForAnimationComplete() - assertEquals(Surface.ROTATION_0, device.displayRotation) - } - } - transitions { - // Request that the orientation is set to landscape - broadcastActionTrigger.requestOrientationForPip(ORIENTATION_LANDSCAPE) - - // Launch the activity back into fullscreen and ensure that it is now in landscape - pipApp.launchViaIntent() - waitForAnimationComplete() - assertEquals(Surface.ROTATION_90, device.displayRotation) - } - teardown { - test { - removeAllTasksButHome() - } - } - assertions { - val startingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_0) - val endingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_90) - windowManagerTrace { - start("PIP window must remain inside display") { - coversAtMostRegion(pipApp.defaultWindowName, startingBounds) - } - end("pipApp shows on top") { - showsAppWindowOnTop(pipApp.defaultWindowName) - } - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() - } - layersTrace { - start("PIP layer must remain inside display") { - coversAtMostRegion(startingBounds, pipApp.defaultWindowName) - } - end("pipApp layer covers fullscreen") { - hasVisibleRegion(pipApp.defaultWindowName, endingBounds) - } - navBarLayerIsAlwaysVisible(bugId = 140855415) - statusBarLayerIsAlwaysVisible(bugId = 140855415) - } - } - } - } - - companion object { - @Parameterized.Parameters(name = "{0}") - @JvmStatic - fun getParams(): Collection<Array<Any>> { - val supportedRotations = intArrayOf(Surface.ROTATION_0) - return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) } - } - } -}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt index a00c5f463a50..adab5e81b32d 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt @@ -16,21 +16,18 @@ package com.android.wm.shell.flicker.pip -import android.platform.test.annotations.Presubmit +import android.os.Bundle import android.view.Surface import androidx.test.filters.RequiresDevice import androidx.test.platform.app.InstrumentationRegistry import com.android.server.wm.flicker.FlickerTestRunner import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.endRotation import com.android.server.wm.flicker.helpers.WindowUtils -import com.android.server.wm.flicker.helpers.buildTestTag import com.android.server.wm.flicker.helpers.setRotation -import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen -import com.android.server.wm.flicker.repetitions import com.android.server.wm.flicker.startRotation import com.android.wm.shell.flicker.helpers.FixedAppHelper -import com.android.wm.shell.flicker.helpers.PipAppHelper import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible @@ -38,7 +35,6 @@ import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible import com.android.server.wm.flicker.noUncoveredRegions import com.android.server.wm.flicker.navBarLayerRotatesAndScales import com.android.server.wm.flicker.statusBarLayerRotatesScales -import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP import org.junit.FixMethodOrder import org.junit.runner.RunWith import org.junit.runners.MethodSorters @@ -48,80 +44,77 @@ import org.junit.runners.Parameterized * Test Pip Stack in bounds after rotations. * To run this test: `atest WMShellFlickerTests:PipRotationTest` */ -@Presubmit @RequiresDevice @RunWith(Parameterized::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) class PipRotationTest( testSpec: FlickerTestRunnerFactory.TestSpec ) : FlickerTestRunner(testSpec) { - companion object { + companion object : PipTransitionBase(InstrumentationRegistry.getInstrumentation()) { @Parameterized.Parameters(name = "{0}") @JvmStatic fun getParams(): Collection<Array<Any>> { - val instrumentation = InstrumentationRegistry.getInstrumentation() - val testApp = FixedAppHelper(instrumentation) - val pipApp = PipAppHelper(instrumentation) - return FlickerTestRunnerFactory.getInstance().buildRotationTest(instrumentation, - supportedRotations = listOf(Surface.ROTATION_0, Surface.ROTATION_90)) { - configuration -> - withTestName { buildTestTag("PipRotationTest", testApp, configuration) } - repeat { configuration.repetitions } - setup { - test { - AppTestBase.removeAllTasksButHome() - device.wakeUpAndGoToHomeScreen() - pipApp.launchViaIntent(stringExtras = mapOf( - EXTRA_ENTER_PIP to "true")) - testApp.launchViaIntent() - AppTestBase.waitForAnimationComplete() - } - eachRun { - setRotation(configuration.startRotation) - } - } - transitions { - setRotation(configuration.endRotation) + val fixedApp = FixedAppHelper(instrumentation) + val baseConfig = getTransitionLaunch(eachRun = false) + val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration -> + setup { + test { + fixedApp.launchViaIntent(wmHelper) + } + eachRun { + setRotation(configuration.startRotation) + } + } + transitions { + setRotation(configuration.endRotation) + } + teardown { + eachRun { + setRotation(Surface.ROTATION_0) + } + } + assertions { + val startingBounds = WindowUtils.getDisplayBounds(configuration.startRotation) + val endingBounds = WindowUtils.getDisplayBounds(configuration.endRotation) + + presubmit { + windowManagerTrace { + navBarWindowIsAlwaysVisible() + statusBarWindowIsAlwaysVisible() } - teardown { - eachRun { - setRotation(Surface.ROTATION_0) - } - test { - AppTestBase.removeAllTasksButHome() - } + + layersTrace { + noUncoveredRegions(configuration.startRotation, + configuration.endRotation, allStates = false) } - assertions { - windowManagerTrace { - navBarWindowIsAlwaysVisible() - statusBarWindowIsAlwaysVisible() - } - layersTrace { - navBarLayerIsAlwaysVisible(bugId = 140855415) - statusBarLayerIsAlwaysVisible(bugId = 140855415) - noUncoveredRegions(configuration.startRotation, - configuration.endRotation, allStates = false) - navBarLayerRotatesAndScales(configuration.startRotation, - configuration.endRotation, bugId = 140855415) - statusBarLayerRotatesScales(configuration.startRotation, - configuration.endRotation, bugId = 140855415) + } + + flaky { + layersTrace { + navBarLayerIsAlwaysVisible(bugId = 140855415) + statusBarLayerIsAlwaysVisible(bugId = 140855415) + navBarLayerRotatesAndScales(configuration.startRotation, + configuration.endRotation, bugId = 140855415) + statusBarLayerRotatesScales(configuration.startRotation, + configuration.endRotation, bugId = 140855415) + + start("appLayerRotates_StartingBounds", bugId = 140855415) { + hasVisibleRegion(fixedApp.defaultWindowName, startingBounds) + coversAtMostRegion(startingBounds, pipApp.defaultWindowName) } - layersTrace { - val startingBounds = WindowUtils.getDisplayBounds( - configuration.startRotation) - val endingBounds = WindowUtils.getDisplayBounds( - configuration.endRotation) - start("appLayerRotates_StartingBounds", bugId = 140855415) { - hasVisibleRegion(testApp.defaultWindowName, startingBounds) - coversAtMostRegion(startingBounds, pipApp.defaultWindowName) - } - end("appLayerRotates_EndingBounds", bugId = 140855415) { - hasVisibleRegion(testApp.defaultWindowName, endingBounds) - coversAtMostRegion(endingBounds, pipApp.defaultWindowName) - } + end("appLayerRotates_EndingBounds", bugId = 140855415) { + hasVisibleRegion(fixedApp.defaultWindowName, endingBounds) + coversAtMostRegion(endingBounds, pipApp.defaultWindowName) } } } + } + } + + return FlickerTestRunnerFactory.getInstance().buildRotationTest(instrumentation, + baseConfig, testSpec, + supportedRotations = listOf(Surface.ROTATION_0, Surface.ROTATION_90), + repetitions = 5) } } }
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt index 3e7eb134e627..4b826ffd646d 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt @@ -16,29 +16,23 @@ package com.android.wm.shell.flicker.pip +import android.os.Bundle import android.view.Surface -import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import androidx.test.platform.app.InstrumentationRegistry import com.android.server.wm.flicker.FlickerTestRunner import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.focusChanges -import com.android.server.wm.flicker.helpers.buildTestTag -import com.android.server.wm.flicker.helpers.closePipWindow -import com.android.server.wm.flicker.helpers.expandPipWindow -import com.android.server.wm.flicker.helpers.hasPipWindow import com.android.server.wm.flicker.helpers.setRotation -import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible import com.android.server.wm.flicker.navBarLayerRotatesAndScales import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible import com.android.server.wm.flicker.noUncoveredRegions -import com.android.server.wm.flicker.repetitions import com.android.server.wm.flicker.startRotation import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible import com.android.server.wm.flicker.statusBarLayerRotatesScales import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible -import com.android.wm.shell.flicker.helpers.PipAppHelper import org.junit.FixMethodOrder import org.junit.runner.RunWith import org.junit.runners.MethodSorters @@ -51,48 +45,30 @@ import org.junit.runners.Parameterized @RequiresDevice @RunWith(Parameterized::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -@FlakyTest(bugId = 152738416) class PipToAppTest( testSpec: FlickerTestRunnerFactory.TestSpec ) : FlickerTestRunner(testSpec) { - companion object { + companion object : PipTransitionBase(InstrumentationRegistry.getInstrumentation()) { @Parameterized.Parameters(name = "{0}") @JvmStatic fun getParams(): List<Array<Any>> { - val instrumentation = InstrumentationRegistry.getInstrumentation() - val testApp = PipAppHelper(instrumentation) - return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation, - supportedRotations = listOf(Surface.ROTATION_0)) { configuration -> - withTestName { buildTestTag("exitPipModeToApp", testApp, configuration) } - repeat { configuration.repetitions } - setup { - test { - device.wakeUpAndGoToHomeScreen() - device.pressHome() - testApp.launchViaIntent(wmHelper) - } - eachRun { - this.setRotation(configuration.startRotation) - testApp.clickEnterPipButton() - device.hasPipWindow() - } - } - teardown { - eachRun { - this.setRotation(Surface.ROTATION_0) - } - test { - if (device.hasPipWindow()) { - device.closePipWindow() - } - testApp.exit() - } + val baseConfig = getTransitionLaunch(eachRun = true) + val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration -> + setup { + eachRun { + this.setRotation(configuration.startRotation) } - transitions { - device.expandPipWindow() - device.waitForIdle() + } + teardown { + eachRun { + this.setRotation(Surface.ROTATION_0) } - assertions { + } + transitions { + pipApp.expandPipWindowToApp(wmHelper) + } + assertions { + presubmit { windowManagerTrace { navBarWindowIsAlwaysVisible() statusBarWindowIsAlwaysVisible() @@ -100,34 +76,42 @@ class PipToAppTest( all("appReplacesPipWindow") { this.showsAppWindow(PIP_WINDOW_TITLE) .then() - .showsAppWindowOnTop(testApp.launcherName) + .showsAppWindowOnTop(pipApp.launcherName) } } layersTrace { - navBarLayerIsAlwaysVisible(bugId = 140855415) statusBarLayerIsAlwaysVisible() - noUncoveredRegions(configuration.startRotation, Surface.ROTATION_0, - enabled = false) - navBarLayerRotatesAndScales(configuration.startRotation, - Surface.ROTATION_0, bugId = 140855415) statusBarLayerRotatesScales(configuration.startRotation, Surface.ROTATION_0) all("appReplacesPipLayer") { this.showsLayer(PIP_WINDOW_TITLE) .then() - .showsLayer(testApp.launcherName) + .showsLayer(pipApp.launcherName) } } + } + + flaky { + layersTrace { + navBarLayerIsAlwaysVisible(bugId = 140855415) + noUncoveredRegions(configuration.startRotation, Surface.ROTATION_0) + navBarLayerRotatesAndScales(configuration.startRotation, + Surface.ROTATION_0, bugId = 140855415) + } eventLog { focusChanges( - "NexusLauncherActivity", testApp.launcherName, + "NexusLauncherActivity", pipApp.launcherName, "NexusLauncherActivity", bugId = 151179149) } } } + } + + return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation, baseConfig, + testSpec, supportedRotations = listOf(Surface.ROTATION_0), repetitions = 5) } } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToHomeTest.kt index 5d3bc1388686..62e82212b1d1 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToHomeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToHomeTest.kt @@ -16,28 +16,23 @@ package com.android.wm.shell.flicker.pip +import android.os.Bundle import android.view.Surface -import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import androidx.test.platform.app.InstrumentationRegistry import com.android.server.wm.flicker.FlickerTestRunner import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.dsl.FlickerBuilder import com.android.server.wm.flicker.focusChanges -import com.android.server.wm.flicker.helpers.buildTestTag -import com.android.server.wm.flicker.helpers.closePipWindow -import com.android.server.wm.flicker.helpers.hasPipWindow import com.android.server.wm.flicker.helpers.setRotation -import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible import com.android.server.wm.flicker.navBarLayerRotatesAndScales import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible import com.android.server.wm.flicker.noUncoveredRegions -import com.android.server.wm.flicker.repetitions import com.android.server.wm.flicker.startRotation import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible import com.android.server.wm.flicker.statusBarLayerRotatesScales import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible -import com.android.wm.shell.flicker.helpers.PipAppHelper import org.junit.FixMethodOrder import org.junit.runner.RunWith import org.junit.runners.MethodSorters @@ -50,50 +45,30 @@ import org.junit.runners.Parameterized @RequiresDevice @RunWith(Parameterized::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) -@FlakyTest(bugId = 152738416) class PipToHomeTest( testSpec: FlickerTestRunnerFactory.TestSpec ) : FlickerTestRunner(testSpec) { - companion object { + companion object : PipTransitionBase(InstrumentationRegistry.getInstrumentation()) { @Parameterized.Parameters(name = "{0}") @JvmStatic fun getParams(): List<Array<Any>> { - val instrumentation = InstrumentationRegistry.getInstrumentation() - val testApp = PipAppHelper(instrumentation) - return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation, - supportedRotations = listOf(Surface.ROTATION_0)) { configuration -> - withTestName { buildTestTag("exitPipModeToApp", testApp, configuration) } - repeat { configuration.repetitions } - setup { - test { - device.wakeUpAndGoToHomeScreen() - device.pressHome() - } - eachRun { - testApp.launchViaIntent(wmHelper) - this.setRotation(configuration.startRotation) - testApp.clickEnterPipButton() - device.hasPipWindow() - } - } - teardown { - eachRun { - this.setRotation(Surface.ROTATION_0) - if (device.hasPipWindow()) { - device.closePipWindow() - } - } - test { - if (device.hasPipWindow()) { - device.closePipWindow() - } - testApp.exit() - } + val baseConfig = getTransitionLaunch(eachRun = true) + val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration -> + setup { + eachRun { + this.setRotation(configuration.startRotation) } - transitions { - testApp.closePipWindow() + } + teardown { + eachRun { + this.setRotation(Surface.ROTATION_0) } - assertions { + } + transitions { + pipApp.closePipWindow(wmHelper) + } + assertions { + presubmit { windowManagerTrace { navBarWindowIsAlwaysVisible() statusBarWindowIsAlwaysVisible() @@ -106,12 +81,7 @@ class PipToHomeTest( } layersTrace { - navBarLayerIsAlwaysVisible(bugId = 140855415) statusBarLayerIsAlwaysVisible() - noUncoveredRegions(configuration.startRotation, Surface.ROTATION_0, - enabled = false) - navBarLayerRotatesAndScales(configuration.startRotation, - Surface.ROTATION_0, bugId = 140855415) statusBarLayerRotatesScales(configuration.startRotation, Surface.ROTATION_0) @@ -121,13 +91,28 @@ class PipToHomeTest( .hidesLayer(PIP_WINDOW_TITLE) } } + } + postsubmit { + layersTrace { + navBarLayerIsAlwaysVisible() + noUncoveredRegions(configuration.startRotation, Surface.ROTATION_0) + navBarLayerRotatesAndScales(configuration.startRotation, + Surface.ROTATION_0) + } + } + + flaky { eventLog { - focusChanges(testApp.launcherName, "NexusLauncherActivity", + focusChanges(pipApp.launcherName, "NexusLauncherActivity", bugId = 151179149) } } } + } + + return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation, baseConfig, + testSpec, supportedRotations = listOf(Surface.ROTATION_0), repetitions = 5) } } }
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransitionBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransitionBase.kt new file mode 100644 index 000000000000..eb7bae160577 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransitionBase.kt @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2021 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.app.Instrumentation +import android.content.Intent +import android.os.Bundle +import android.view.Surface +import com.android.server.wm.flicker.dsl.FlickerBuilder +import com.android.server.wm.flicker.helpers.buildTestTag +import com.android.server.wm.flicker.helpers.closePipWindow +import com.android.server.wm.flicker.helpers.hasPipWindow +import com.android.server.wm.flicker.helpers.setRotation +import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen +import com.android.server.wm.flicker.repetitions +import com.android.wm.shell.flicker.helpers.PipAppHelper +import com.android.wm.shell.flicker.removeAllTasksButHome +import com.android.wm.shell.flicker.testapp.Components + +abstract class PipTransitionBase(protected val instrumentation: Instrumentation) { + // Helper class to process test actions by broadcast. + protected class BroadcastActionTrigger(private val instrumentation: Instrumentation) { + private fun createIntentWithAction(broadcastAction: String): Intent { + return Intent(broadcastAction).setFlags(Intent.FLAG_RECEIVER_FOREGROUND) + } + + fun doAction(broadcastAction: String) { + instrumentation.context + .sendBroadcast(createIntentWithAction(broadcastAction)) + } + + fun requestOrientationForPip(orientation: Int) { + instrumentation.context.sendBroadcast( + createIntentWithAction(Components.PipActivity.ACTION_SET_REQUESTED_ORIENTATION) + .putExtra(Components.PipActivity.EXTRA_PIP_ORIENTATION, orientation.toString()) + ) + } + + companion object { + // Corresponds to ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE + @JvmStatic + val ORIENTATION_LANDSCAPE = 0 + + // Corresponds to ActivityInfo.SCREEN_ORIENTATION_PORTRAIT + @JvmStatic + val ORIENTATION_PORTRAIT = 1 + } + } + + protected val pipApp = PipAppHelper(instrumentation) + protected val broadcastActionTrigger = BroadcastActionTrigger(instrumentation) + + /** + * Gets a configuration that handles basic setup and teardown of pip tests + */ + protected val setupAndTeardown: FlickerBuilder.(Bundle) -> Unit + get() = { configuration -> + withTestName { buildTestTag(configuration) } + repeat { configuration.repetitions } + setup { + test { + removeAllTasksButHome() + device.wakeUpAndGoToHomeScreen() + } + } + teardown { + eachRun { + setRotation(Surface.ROTATION_0) + } + test { + removeAllTasksButHome() + + if (device.hasPipWindow()) { + device.closePipWindow() + } + pipApp.exit() + } + } + } + + /** + * Gets a configuration that handles basic setup and teardown of pip tests and that + * launches the Pip app for test + * + * @param eachRun If the pip app should be launched in each run (otherwise only 1x per test) + * @param stringExtras Arguments to pass to the PIP launch intent + */ + @JvmOverloads + fun getTransitionLaunch( + eachRun: Boolean, + stringExtras: Map<String, String> = mapOf(Components.PipActivity.EXTRA_ENTER_PIP to "true") + ): FlickerBuilder.(Bundle) -> Unit { + return { configuration -> + setupAndTeardown(this, configuration) + + setup { + test { + removeAllTasksButHome() + if (!eachRun) { + pipApp.launchViaIntent(wmHelper, stringExtras = stringExtras) + wmHelper.waitPipWindowShown() + } + } + eachRun { + if (eachRun) { + pipApp.launchViaIntent(wmHelper, stringExtras = stringExtras) + wmHelper.waitPipWindowShown() + } + } + } + teardown { + eachRun { + if (eachRun) { + pipApp.exit() + } + } + test { + if (!eachRun) { + pipApp.exit() + } + removeAllTasksButHome() + } + } + } + } +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt new file mode 100644 index 000000000000..c01bc94151e9 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2020 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.view.Surface +import androidx.test.filters.RequiresDevice +import androidx.test.platform.app.InstrumentationRegistry +import com.android.server.wm.flicker.FlickerTestRunner +import com.android.server.wm.flicker.FlickerTestRunnerFactory +import com.android.server.wm.flicker.helpers.WindowUtils +import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible +import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible +import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible +import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible +import com.android.wm.shell.flicker.pip.PipTransitionBase.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE +import com.android.wm.shell.flicker.testapp.Components.FixedActivity.EXTRA_FIXED_ORIENTATION +import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP +import org.junit.Assert.assertEquals +import org.junit.FixMethodOrder +import org.junit.runner.RunWith +import org.junit.runners.MethodSorters +import org.junit.runners.Parameterized + +/** + * Test Pip with orientation changes. + * To run this test: `atest WMShellFlickerTests:PipOrientationTest` + */ +@RequiresDevice +@RunWith(Parameterized::class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +class SetRequestedOrientationWhilePinnedTest( + testSpec: FlickerTestRunnerFactory.TestSpec +) : FlickerTestRunner(testSpec) { + companion object : PipTransitionBase(InstrumentationRegistry.getInstrumentation()) { + @Parameterized.Parameters(name = "{0}") + @JvmStatic + fun getParams(): Collection<Array<Any>> { + return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation, + supportedRotations = listOf(Surface.ROTATION_0), + repetitions = 1) { configuration -> + setupAndTeardown(this, configuration) + + setup { + eachRun { + // Launch the PiP activity fixed as landscape + pipApp.launchViaIntent(wmHelper, stringExtras = mapOf( + EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString(), + EXTRA_ENTER_PIP to "true")) + } + } + teardown { + eachRun { + pipApp.exit() + } + } + transitions { + // Request that the orientation is set to landscape + broadcastActionTrigger.requestOrientationForPip(ORIENTATION_LANDSCAPE) + + // Launch the activity back into fullscreen and + // ensure that it is now in landscape + pipApp.launchViaIntent(wmHelper) + wmHelper.waitForFullScreenApp(pipApp.component) + wmHelper.waitForRotation(Surface.ROTATION_90) + assertEquals(Surface.ROTATION_90, device.displayRotation) + } + assertions { + val startingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_0) + val endingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_90) + presubmit { + windowManagerTrace { + start("PIP window must remain inside display") { + coversAtMostRegion(pipApp.defaultWindowName, startingBounds) + } + end("pipApp shows on top") { + showsAppWindowOnTop(pipApp.defaultWindowName) + } + navBarWindowIsAlwaysVisible() + statusBarWindowIsAlwaysVisible() + } + layersTrace { + start("PIP layer must remain inside display") { + coversAtMostRegion(startingBounds, pipApp.defaultWindowName) + } + end("pipApp layer covers fullscreen") { + hasVisibleRegion(pipApp.defaultWindowName, endingBounds) + } + } + } + + flaky { + layersTrace { + navBarLayerIsAlwaysVisible(bugId = 140855415) + statusBarLayerIsAlwaysVisible(bugId = 140855415) + } + } + } + } + } + } +}
\ No newline at end of file |