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

Commit 7789c031 authored by Ikram Gabiyev's avatar Ikram Gabiyev
Browse files

Implement drag then snap flicker test

Add a flicker test for dragging the pip window
away from the edge and verifying that it snaps
back to that same edge

Bug: 264555500

Test: atest WMShellFlickerTests:PipDragThenSnapTest
Change-Id: I3397f7f47198b33f4d0250704ef5f2fd54446517
(cherry picked from commit d389b970)
parent 580c875e
Loading
Loading
Loading
Loading
+95 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

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

import android.platform.test.annotations.Postsubmit
import android.tools.common.Rotation
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.graphics.Rect
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.FlickerTest
import android.tools.device.flicker.legacy.FlickerTestFactory
import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.testapp.ActivityOptions
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized

/**
 * Test the snapping of a PIP window via dragging, releasing, and checking its final location.
 */
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class PipDragThenSnapTest(flicker: FlickerTest) : PipTransition(flicker){
    override val transition: FlickerBuilder.() -> Unit
        get() = {
            val stringExtras: Map<String, String> =
                mapOf(ActivityOptions.Pip.EXTRA_ENTER_PIP to "true")

            // cache the starting bounds here
            val startBounds = Rect()

            setup {
                // Launch the PIP activity and wait for it to enter PiP mode
                setRotation(Rotation.ROTATION_0)
                RemoveAllTasksButHomeRule.removeAllTasksButHome()
                pipApp.launchViaIntentAndWaitForPip(wmHelper, stringExtras = stringExtras)

                val initRegion = pipApp.dragPipWindowAwayFromEdge(wmHelper, 50)
                startBounds
                    .set(initRegion.left, initRegion.top, initRegion.right, initRegion.bottom)
            }
            transitions {
                // continue the transition until the PIP snaps
                pipApp.waitForPipToSnapTo(wmHelper, startBounds)
            }
        }

    /** Checks that the visible region area of [pipApp] always moves right during the animation. */
    @Postsubmit
    @Test
    fun pipLayerMovesRight() {
        flicker.assertLayers {
            val pipLayerList = layers { pipApp.layerMatchesAnyOf(it) && it.isVisible }
            pipLayerList.zipWithNext { previous, current ->
                current.visibleRegion.isToTheRight(previous.visibleRegion.region)
            }
        }
    }

    companion object {
        /**
         * Creates the test configurations.
         *
         * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
         * navigation modes.
         */
        @Parameterized.Parameters(name = "{0}")
        @JvmStatic
        fun getParams(): List<FlickerTest> {
            return FlickerTestFactory.nonRotationTests(
                supportedRotations = listOf(Rotation.ROTATION_0)
            )
        }
    }
}
 No newline at end of file
+67 −2
Original line number Diff line number Diff line
@@ -58,7 +58,51 @@ open class PipAppHelper(instrumentation: Instrumentation) :
    }

    /**
     * Expands the PIP window my using the pinch out gesture.
     * Drags the PIP window away from the screen edge while not crossing the display center.
     *
     * @throws IllegalStateException if default display bounds are not available
     * @return initial bounds of the PIP window
     */
    fun dragPipWindowAwayFromEdge(wmHelper: WindowManagerStateHelper, steps: Int): Rect {
        val initWindowRect = getWindowRect(wmHelper).clone()

        // initial pointer at the center of the window
        val startX = initWindowRect.centerX()
        val y = initWindowRect.centerY()

        val displayRect = wmHelper.currentState.wmState.getDefaultDisplay()?.displayRect
                ?: throw IllegalStateException("Default display is null")

        // the offset to the right of the display center to drag the window to
        val offset = 20

        // the actual final x coordinate with the offset included
        // if the pip window is closer to the right edge of the display the offset is positive
        // otherwise the offset is negative
        val endX = displayRect.centerX() + offset * (if (isCloserToRightEdge(wmHelper)) 1 else -1)

        // drag the window to the left but not beyond the center of the display
        uiDevice.drag(startX, y, endX, y, steps)

        return initWindowRect
    }

    /**
     * Returns true if PIP window is closer to the right edge of the display than left.
     *
     * @throws IllegalStateException if default display bounds are not available
     */
    private fun isCloserToRightEdge(wmHelper: WindowManagerStateHelper): Boolean {
        val windowRect = getWindowRect(wmHelper)

        val displayRect = wmHelper.currentState.wmState.getDefaultDisplay()?.displayRect
                ?: throw IllegalStateException("Default display is null")

        return windowRect.centerX() > displayRect.centerX()
    }

    /**
     * Expands the PIP window by using the pinch out gesture.
     *
     * @param percent The percentage by which to increase the pip window size.
     * @throws IllegalArgumentException if percentage isn't between 0.0f and 1.0f
@@ -106,7 +150,7 @@ open class PipAppHelper(instrumentation: Instrumentation) :
    }

    /**
     * Minimizes the PIP window my using the pinch in gesture.
     * Minimizes the PIP window by using the pinch in gesture.
     *
     * @param percent The percentage by which to decrease the pip window size.
     * @throws IllegalArgumentException if percentage isn't between 0.0f and 1.0f
@@ -307,6 +351,27 @@ open class PipAppHelper(instrumentation: Instrumentation) :
            .waitForAndVerify()
    }

    /**
     * Waits until the PIP window snaps horizontally to the provided bounds.
     *
     * @param finalRightX the final x coordinate of the right edge of the pip window
     */
    fun waitForPipToSnapTo(wmHelper: WindowManagerStateHelper, finalBounds: android.graphics.Rect) {
        wmHelper
            .StateSyncBuilder()
            .add("pipWindowSnapped") {
                val pipAppWindow =
                    it.wmState.visibleWindows.firstOrNull { window ->
                        this.windowMatchesAnyOf(window)
                    }
                        ?: return@add false
                val pipRegionBounds = pipAppWindow.frameRegion.bounds
                return@add pipRegionBounds.left == finalBounds.left &&
                    pipRegionBounds.right == finalBounds.right
            }
            .waitForAndVerify()
    }

    companion object {
        private const val TAG = "PipAppHelper"
        private const val ENTER_PIP_BUTTON_ID = "enter_pip"