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

Commit 573555ff authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Migrate Pip tests to new DSL format" into sc-dev

parents 0cc57111 068156db
Loading
Loading
Loading
Loading
+32 −0
Original line number Original line Diff line number Diff line
/*
 * 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)
}
+6 −8
Original line number Original line Diff line number Diff line
@@ -32,13 +32,12 @@ open class ImeAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
    /**
    /**
     * Opens the IME and wait for it to be displayed
     * 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
     * @param wmHelper Helper used to wait for WindowManager states
     */
     */
    @JvmOverloads
    @JvmOverloads
    open fun openIME(device: UiDevice, wmHelper: WindowManagerStateHelper? = null) {
    open fun openIME(wmHelper: WindowManagerStateHelper? = null) {
        if (!isTelevision) {
        if (!isTelevision) {
            val editText = device.wait(
            val editText = uiDevice.wait(
                Until.findObject(By.res(getPackage(), "plain_text_input")),
                Until.findObject(By.res(getPackage(), "plain_text_input")),
                FIND_TIMEOUT)
                FIND_TIMEOUT)


@@ -47,7 +46,7 @@ open class ImeAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
                    "was left in an unknown state (e.g. in split screen)"
                    "was left in an unknown state (e.g. in split screen)"
            }
            }
            editText.click()
            editText.click()
            waitAndAssertIMEShown(device, wmHelper)
            waitAndAssertIMEShown(uiDevice, wmHelper)
        } else {
        } else {
            // If we do the same thing as above - editText.click() - on TV, that's going to force TV
            // 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.
            // 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
     * 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
     * @param wmHelper Helper used to wait for WindowManager states
     */
     */
    @JvmOverloads
    @JvmOverloads
    open fun closeIME(device: UiDevice, wmHelper: WindowManagerStateHelper? = null) {
    open fun closeIME(wmHelper: WindowManagerStateHelper? = null) {
        if (!isTelevision) {
        if (!isTelevision) {
            device.pressBack()
            uiDevice.pressBack()
            // Using only the AccessibilityInfo it is not possible to identify if the IME is active
            // Using only the AccessibilityInfo it is not possible to identify if the IME is active
            if (wmHelper == null) {
            if (wmHelper == null) {
                device.waitForIdle()
                uiDevice.waitForIdle()
            } else {
            } else {
                require(wmHelper.waitImeWindowGone()) { "IME did did not close" }
                require(wmHelper.waitImeWindowGone()) { "IME did did not close" }
            }
            }
+81 −12
Original line number Original line Diff line number Diff line
@@ -17,17 +17,20 @@
package com.android.wm.shell.flicker.helpers
package com.android.wm.shell.flicker.helpers


import android.app.Instrumentation
import android.app.Instrumentation
import android.graphics.Point
import android.media.session.MediaController
import android.media.session.MediaController
import android.media.session.MediaSessionManager
import android.media.session.MediaSessionManager
import android.os.SystemClock
import android.os.SystemClock
import androidx.test.uiautomator.By
import androidx.test.uiautomator.By
import androidx.test.uiautomator.BySelector
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.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.closeTvPipWindow
import com.android.wm.shell.flicker.pip.tv.isFocusedOrHasFocusedChild
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 com.android.wm.shell.flicker.testapp.Components
import org.junit.Assert.fail


class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
    instrumentation,
    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 {
    private fun focusOnObject(selector: BySelector): Boolean {
        // We expect all the focusable UI elements to be arranged in a way so that it is possible
        // 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"
        // 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
        return false
    }
    }


    fun clickEnterPipButton() {
    @JvmOverloads
    fun clickEnterPipButton(wmHelper: WindowManagerStateHelper? = null) {
        clickObject(ENTER_PIP_BUTTON_ID)
        clickObject(ENTER_PIP_BUTTON_ID)


        // TODO(b/172321238): remove this check once hasPipWindow is fixed on TVs
        // Wait on WMHelper or simply wait for 3 seconds
        if (!isTelevision) {
        wmHelper?.waitPipWindowShown() ?: SystemClock.sleep(3_000)
            uiDevice.hasPipWindow()
        } else {
            // Simply wait for 3 seconds
            SystemClock.sleep(3_000)
        }
    }
    }


    fun clickStartMediaSessionButton() {
    fun clickStartMediaSessionButton() {
@@ -97,16 +107,75 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
    fun stopMedia() = mediaController?.transportControls?.stop()
    fun stopMedia() = mediaController?.transportControls?.stop()
            ?: error("No active media session found")
            ?: error("No active media session found")


    @Deprecated("Use PipAppHelper.closePipWindow(wmHelper) instead",
        ReplaceWith("closePipWindow(wmHelper)"))
    fun closePipWindow() {
    fun closePipWindow() {
        if (isTelevision) {
        if (isTelevision) {
            uiDevice.closeTvPipWindow()
            uiDevice.closeTvPipWindow()
        } else {
        } else {
            uiDevice.closePipWindow()
            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 {
    companion object {
+0 −13
Original line number Original line Diff line number Diff line
@@ -16,11 +16,6 @@


package com.android.wm.shell.flicker.pip
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 android.os.SystemClock
import com.android.wm.shell.flicker.NonRotationTestBase
import com.android.wm.shell.flicker.NonRotationTestBase


@@ -29,14 +24,6 @@ abstract class AppTestBase(
    rotation: Int
    rotation: Int
) : NonRotationTestBase(rotationName, rotation) {
) : NonRotationTestBase(rotationName, rotation) {
    companion object {
    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() {
        fun waitForAnimationComplete() {
            // TODO: UiDevice doesn't have reliable way to wait for the completion of animation.
            // TODO: UiDevice doesn't have reliable way to wait for the completion of animation.
            // Consider to introduce WindowManagerStateHelper to access Activity state.
            // Consider to introduce WindowManagerStateHelper to access Activity state.
+58 −73
Original line number Original line Diff line number Diff line
@@ -16,21 +16,21 @@


package com.android.wm.shell.flicker.pip
package com.android.wm.shell.flicker.pip


import android.platform.test.annotations.Presubmit
import android.os.Bundle
import android.view.Surface
import android.view.Surface
import androidx.test.filters.RequiresDevice
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.WindowUtils
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
import com.android.wm.shell.flicker.helpers.FixedAppHelper
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.navBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
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.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
import org.junit.runners.Parameterized
@@ -39,42 +39,31 @@ import org.junit.runners.Parameterized
 * Test Pip launch and exit.
 * Test Pip launch and exit.
 * To run this test: `atest WMShellFlickerTests:EnterExitPipTest`
 * To run this test: `atest WMShellFlickerTests:EnterExitPipTest`
 */
 */
@Presubmit
@RequiresDevice
@RequiresDevice
@RunWith(Parameterized::class)
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class EnterExitPipTest(
class EnterExitPipTest(
    rotationName: String,
    testSpec: FlickerTestRunnerFactory.TestSpec
    rotation: Int
) : FlickerTestRunner(testSpec) {
) : AppTestBase(rotationName, rotation) {
    companion object : PipTransitionBase(InstrumentationRegistry.getInstrumentation()) {
    private val pipApp = PipAppHelper(instrumentation)
        @Parameterized.Parameters(name = "{0}")
    private val testApp = FixedAppHelper(instrumentation)
        @JvmStatic

        fun getParams(): List<Array<Any>> {
    @Test
            val testApp = FixedAppHelper(instrumentation)
    fun testDisplayMetricsPinUnpin() {
            val baseConfig = getTransitionLaunch(eachRun = true)
        runFlicker(instrumentation) {
            val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration ->
            withTestName { "testDisplayMetricsPinUnpin" }
                setup {
                setup {
                test {
                    eachRun {
                    removeAllTasksButHome()
                        testApp.launchViaIntent(wmHelper)
                    device.wakeUpAndGoToHomeScreen()
                    pipApp.launchViaIntent(stringExtras = mapOf(EXTRA_ENTER_PIP to "true"))
                    testApp.launchViaIntent()
                    waitForAnimationComplete()
                    }
                    }
                }
                }
                transitions {
                transitions {
                    // This will bring PipApp to fullscreen
                    // This will bring PipApp to fullscreen
                pipApp.launchViaIntent()
                    pipApp.launchViaIntent(wmHelper)
                waitForAnimationComplete()
            }
            teardown {
                test {
                    removeAllTasksButHome()
                }
                }
                }
                assertions {
                assertions {
                val displayBounds = WindowUtils.getDisplayBounds(rotation)
                    val displayBounds = WindowUtils.getDisplayBounds(configuration.startRotation)
                    presubmit {
                        windowManagerTrace {
                        windowManagerTrace {
                            all("pipApp must remain inside visible bounds") {
                            all("pipApp must remain inside visible bounds") {
                                coversAtMostRegion(pipApp.defaultWindowName, displayBounds)
                                coversAtMostRegion(pipApp.defaultWindowName, displayBounds)
@@ -108,13 +97,9 @@ class EnterExitPipTest(
                    }
                    }
                }
                }
            }
            }

            return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation, baseConfig,
    companion object {
                testSpec, supportedRotations = listOf(Surface.ROTATION_0),
        @Parameterized.Parameters(name = "{0}")
                repetitions = 5)
        @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
Loading