Migrate Pip tests to new DSL format
Make sure the test can run multiple times and is stable on flame Introduce methods to allow waitForPipWindowShow/Gone using the WindowManagerState to determine if a PIP window is active (windowingMode = PINNED), since the UiDevice method is unstable and doesn't work on TVs. Bug: 171049720 Bug: 172321238 Bug: 171049762 Test: atest WMShellFlickerTests Change-Id: Iade19fadeb0ba07e047eb5f64479e592920ca11e
This commit is contained in:
@@ -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)
|
||||
}
|
||||
@@ -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" }
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
if (!waitUntilClosed()) {
|
||||
fail("Couldn't close Pip")
|
||||
/**
|
||||
* 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()
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
testSpec: FlickerTestRunnerFactory.TestSpec
|
||||
) : FlickerTestRunner(testSpec) {
|
||||
companion object : PipTransitionBase(InstrumentationRegistry.getInstrumentation()) {
|
||||
@Parameterized.Parameters(name = "{0}")
|
||||
@JvmStatic
|
||||
fun getParams(): Collection<Array<Any>> {
|
||||
val supportedRotations = intArrayOf(Surface.ROTATION_0)
|
||||
return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
|
||||
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)
|
||||
}
|
||||
}
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation, baseConfig,
|
||||
testSpec, supportedRotations = listOf(Surface.ROTATION_0),
|
||||
repetitions = 5)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
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()
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 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()
|
||||
}
|
||||
}
|
||||
assertions {
|
||||
windowManagerTrace {
|
||||
end("imeWindowAboveApp") {
|
||||
isAboveWindow(IME_WINDOW_NAME, testApp.defaultWindowName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TEST_REPETITIONS = 5
|
||||
class PipKeyboardTest(testSpec: FlickerTestRunnerFactory.TestSpec) : FlickerTestRunner(testSpec) {
|
||||
companion object : PipTransitionBase(InstrumentationRegistry.getInstrumentation()) {
|
||||
private const val TAG_IME_VISIBLE = "imeIsVisible"
|
||||
|
||||
@Parameterized.Parameters(name = "{0}")
|
||||
@JvmStatic
|
||||
fun getParams(): Collection<Array<Any>> {
|
||||
val supportedRotations = intArrayOf(Surface.ROTATION_0)
|
||||
return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
|
||||
val imeApp = ImeAppHelper(instrumentation)
|
||||
val baseConfig = getTransitionLaunch(eachRun = false)
|
||||
val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration ->
|
||||
setup {
|
||||
test {
|
||||
imeApp.launchViaIntent(wmHelper)
|
||||
setRotation(configuration.startRotation)
|
||||
}
|
||||
}
|
||||
teardown {
|
||||
test {
|
||||
imeApp.exit()
|
||||
setRotation(Surface.ROTATION_0)
|
||||
}
|
||||
}
|
||||
transitions {
|
||||
// open the soft keyboard
|
||||
imeApp.openIME(wmHelper)
|
||||
createTag(TAG_IME_VISIBLE)
|
||||
|
||||
// then close it again
|
||||
imeApp.closeIME(wmHelper)
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation,
|
||||
baseConfig, testSpec, supportedRotations = listOf(Surface.ROTATION_0),
|
||||
repetitions = 5)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
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()
|
||||
}
|
||||
transitions {
|
||||
setRotation(configuration.endRotation)
|
||||
|
||||
layersTrace {
|
||||
noUncoveredRegions(configuration.startRotation,
|
||||
configuration.endRotation, allStates = false)
|
||||
}
|
||||
teardown {
|
||||
eachRun {
|
||||
setRotation(Surface.ROTATION_0)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
test {
|
||||
AppTestBase.removeAllTasksButHome()
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
val baseConfig = getTransitionLaunch(eachRun = true)
|
||||
val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration ->
|
||||
setup {
|
||||
eachRun {
|
||||
this.setRotation(configuration.startRotation)
|
||||
}
|
||||
teardown {
|
||||
eachRun {
|
||||
this.setRotation(Surface.ROTATION_0)
|
||||
}
|
||||
test {
|
||||
if (device.hasPipWindow()) {
|
||||
device.closePipWindow()
|
||||
}
|
||||
testApp.exit()
|
||||
}
|
||||
}
|
||||
teardown {
|
||||
eachRun {
|
||||
this.setRotation(Surface.ROTATION_0)
|
||||
}
|
||||
transitions {
|
||||
device.expandPipWindow()
|
||||
device.waitForIdle()
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
val baseConfig = getTransitionLaunch(eachRun = true)
|
||||
val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration ->
|
||||
setup {
|
||||
eachRun {
|
||||
this.setRotation(configuration.startRotation)
|
||||
}
|
||||
teardown {
|
||||
eachRun {
|
||||
this.setRotation(Surface.ROTATION_0)
|
||||
if (device.hasPipWindow()) {
|
||||
device.closePipWindow()
|
||||
}
|
||||
}
|
||||
test {
|
||||
if (device.hasPipWindow()) {
|
||||
device.closePipWindow()
|
||||
}
|
||||
testApp.exit()
|
||||
}
|
||||
}
|
||||
teardown {
|
||||
eachRun {
|
||||
this.setRotation(Surface.ROTATION_0)
|
||||
}
|
||||
transitions {
|
||||
testApp.closePipWindow()
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user