diff options
author | 2024-11-10 23:30:05 +0000 | |
---|---|---|
committer | 2024-11-26 18:41:04 +0000 | |
commit | bb088a214bc5f031949d340d248e6af0156a90cb (patch) | |
tree | eb866f154bfecbffb33a432e2d8d2d3049756653 /tests/FlickerTests | |
parent | fd1963788edc5a96206745e02f48428a6ef87a92 (diff) |
Stabilize real apps pip tests
Test: atest WMShellFlickerTestsPipAppsCSuite
Flag: TEST_ONLY
Bug: 377889094
Change-Id: Id6288a6db2e4d760c7687627835227e0aefa8e49
Diffstat (limited to 'tests/FlickerTests')
3 files changed, 11 insertions, 624 deletions
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GestureHelper.java b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GestureHelper.java deleted file mode 100644 index eeee7b4dfc6b..000000000000 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GestureHelper.java +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.wm.flicker.helpers; - -import android.annotation.NonNull; -import android.app.Instrumentation; -import android.app.UiAutomation; -import android.os.SystemClock; -import android.view.InputDevice; -import android.view.InputEvent; -import android.view.MotionEvent; -import android.view.MotionEvent.PointerCoords; -import android.view.MotionEvent.PointerProperties; - -import androidx.annotation.Nullable; - -/** - * Injects gestures given an {@link Instrumentation} object. - */ -public class GestureHelper { - // Inserted after each motion event injection. - private static final int MOTION_EVENT_INJECTION_DELAY_MILLIS = 5; - - private final UiAutomation mUiAutomation; - - /** - * Primary pointer should be cached here for separate release - */ - @Nullable private PointerProperties mPrimaryPtrProp; - @Nullable private PointerCoords mPrimaryPtrCoord; - private long mPrimaryPtrDownTime; - - /** - * A pair of floating point values. - */ - public static class Tuple { - public float x; - public float y; - - public Tuple(float x, float y) { - this.x = x; - this.y = y; - } - } - - public GestureHelper(Instrumentation instrumentation) { - mUiAutomation = instrumentation.getUiAutomation(); - } - - /** - * Injects a series of {@link MotionEvent}s to simulate tapping. - * - * @param point coordinates of pointer to tap - * @param times the number of times to tap - */ - public boolean tap(@NonNull Tuple point, int times) throws InterruptedException { - PointerProperties ptrProp = getPointerProp(0, MotionEvent.TOOL_TYPE_FINGER); - PointerCoords ptrCoord = getPointerCoord(point.x, point.y, 1, 1); - - for (int i = 0; i <= times; i++) { - // If already tapped, inject delay in between movements - if (times > 0) { - SystemClock.sleep(50L); - } - if (!primaryPointerDown(ptrProp, ptrCoord, SystemClock.uptimeMillis())) { - return false; - } - // Delay before releasing tap - SystemClock.sleep(100L); - if (!primaryPointerUp(ptrProp, ptrCoord, SystemClock.uptimeMillis())) { - return false; - } - } - return true; - } - - /** - * Injects a series of {@link MotionEvent}s to simulate a drag gesture without pointer release. - * - * Simulates a drag gesture without releasing the primary pointer. The primary pointer info - * will be cached for potential release later on by {@code releasePrimaryPointer()} - * - * @param startPoint initial coordinates of the primary pointer - * @param endPoint final coordinates of the primary pointer - * @param steps number of steps to take to animate dragging - * @return true if gesture is injected successfully - */ - public boolean dragWithoutRelease(@NonNull Tuple startPoint, - @NonNull Tuple endPoint, int steps) { - PointerProperties ptrProp = getPointerProp(0, MotionEvent.TOOL_TYPE_FINGER); - PointerCoords ptrCoord = getPointerCoord(startPoint.x, startPoint.y, 1, 1); - - PointerProperties[] ptrProps = new PointerProperties[] { ptrProp }; - PointerCoords[] ptrCoords = new PointerCoords[] { ptrCoord }; - - long downTime = SystemClock.uptimeMillis(); - - if (!primaryPointerDown(ptrProp, ptrCoord, downTime)) { - return false; - } - - // cache the primary pointer info for later potential release - mPrimaryPtrProp = ptrProp; - mPrimaryPtrCoord = ptrCoord; - mPrimaryPtrDownTime = downTime; - - return movePointers(ptrProps, ptrCoords, new Tuple[] { endPoint }, downTime, steps); - } - - /** - * Release primary pointer if previous gesture has cached the primary pointer info. - * - * @return true if the release was injected successfully - */ - public boolean releasePrimaryPointer() { - if (mPrimaryPtrProp != null && mPrimaryPtrCoord != null) { - return primaryPointerUp(mPrimaryPtrProp, mPrimaryPtrCoord, mPrimaryPtrDownTime); - } - - return false; - } - - /** - * Injects a series of {@link MotionEvent} objects to simulate a pinch gesture. - * - * @param startPoint1 initial coordinates of the first pointer - * @param startPoint2 initial coordinates of the second pointer - * @param endPoint1 final coordinates of the first pointer - * @param endPoint2 final coordinates of the second pointer - * @param steps number of steps to take to animate pinching - * @return true if gesture is injected successfully - */ - public boolean pinch(@NonNull Tuple startPoint1, @NonNull Tuple startPoint2, - @NonNull Tuple endPoint1, @NonNull Tuple endPoint2, int steps) { - PointerProperties ptrProp1 = getPointerProp(0, MotionEvent.TOOL_TYPE_FINGER); - PointerProperties ptrProp2 = getPointerProp(1, MotionEvent.TOOL_TYPE_FINGER); - - PointerCoords ptrCoord1 = getPointerCoord(startPoint1.x, startPoint1.y, 1, 1); - PointerCoords ptrCoord2 = getPointerCoord(startPoint2.x, startPoint2.y, 1, 1); - - PointerProperties[] ptrProps = new PointerProperties[] { - ptrProp1, ptrProp2 - }; - - PointerCoords[] ptrCoords = new PointerCoords[] { - ptrCoord1, ptrCoord2 - }; - - long downTime = SystemClock.uptimeMillis(); - - if (!primaryPointerDown(ptrProp1, ptrCoord1, downTime)) { - return false; - } - - if (!nonPrimaryPointerDown(ptrProps, ptrCoords, downTime, 1)) { - return false; - } - - if (!movePointers(ptrProps, ptrCoords, new Tuple[] { endPoint1, endPoint2 }, - downTime, steps)) { - return false; - } - - if (!nonPrimaryPointerUp(ptrProps, ptrCoords, downTime, 1)) { - return false; - } - - return primaryPointerUp(ptrProp1, ptrCoord1, downTime); - } - - private boolean primaryPointerDown(@NonNull PointerProperties prop, - @NonNull PointerCoords coord, long downTime) { - MotionEvent event = getMotionEvent(downTime, downTime, MotionEvent.ACTION_DOWN, 1, - new PointerProperties[]{ prop }, new PointerCoords[]{ coord }); - - return injectEventSync(event); - } - - private boolean nonPrimaryPointerDown(@NonNull PointerProperties[] props, - @NonNull PointerCoords[] coords, long downTime, int index) { - // at least 2 pointers are needed - if (props.length != coords.length || coords.length < 2) { - return false; - } - - long eventTime = SystemClock.uptimeMillis(); - - MotionEvent event = getMotionEvent(downTime, eventTime, MotionEvent.ACTION_POINTER_DOWN - + (index << MotionEvent.ACTION_POINTER_INDEX_SHIFT), coords.length, props, coords); - - return injectEventSync(event); - } - - private boolean movePointers(@NonNull PointerProperties[] props, - @NonNull PointerCoords[] coords, @NonNull Tuple[] endPoints, long downTime, int steps) { - // the number of endpoints should be the same as the number of pointers - if (props.length != coords.length || coords.length != endPoints.length) { - return false; - } - - // prevent division by 0 and negative number of steps - if (steps < 1) { - steps = 1; - } - - // save the starting points before updating any pointers - Tuple[] startPoints = new Tuple[coords.length]; - - for (int i = 0; i < coords.length; i++) { - startPoints[i] = new Tuple(coords[i].x, coords[i].y); - } - - MotionEvent event; - long eventTime; - - for (int i = 0; i < steps; i++) { - // inject a delay between movements - SystemClock.sleep(MOTION_EVENT_INJECTION_DELAY_MILLIS); - - // update the coordinates - for (int j = 0; j < coords.length; j++) { - coords[j].x += (endPoints[j].x - startPoints[j].x) / steps; - coords[j].y += (endPoints[j].y - startPoints[j].y) / steps; - } - - eventTime = SystemClock.uptimeMillis(); - - event = getMotionEvent(downTime, eventTime, MotionEvent.ACTION_MOVE, - coords.length, props, coords); - - boolean didInject = injectEventSync(event); - - if (!didInject) { - return false; - } - } - - return true; - } - - private boolean primaryPointerUp(@NonNull PointerProperties prop, - @NonNull PointerCoords coord, long downTime) { - long eventTime = SystemClock.uptimeMillis(); - - MotionEvent event = getMotionEvent(downTime, eventTime, MotionEvent.ACTION_UP, 1, - new PointerProperties[]{ prop }, new PointerCoords[]{ coord }); - - return injectEventSync(event); - } - - private boolean nonPrimaryPointerUp(@NonNull PointerProperties[] props, - @NonNull PointerCoords[] coords, long downTime, int index) { - // at least 2 pointers are needed - if (props.length != coords.length || coords.length < 2) { - return false; - } - - long eventTime = SystemClock.uptimeMillis(); - - MotionEvent event = getMotionEvent(downTime, eventTime, MotionEvent.ACTION_POINTER_UP - + (index << MotionEvent.ACTION_POINTER_INDEX_SHIFT), coords.length, props, coords); - - return injectEventSync(event); - } - - private PointerCoords getPointerCoord(float x, float y, float pressure, float size) { - PointerCoords ptrCoord = new PointerCoords(); - ptrCoord.x = x; - ptrCoord.y = y; - ptrCoord.pressure = pressure; - ptrCoord.size = size; - return ptrCoord; - } - - private PointerProperties getPointerProp(int id, int toolType) { - PointerProperties ptrProp = new PointerProperties(); - ptrProp.id = id; - ptrProp.toolType = toolType; - return ptrProp; - } - - private static MotionEvent getMotionEvent(long downTime, long eventTime, int action, - int pointerCount, PointerProperties[] ptrProps, PointerCoords[] ptrCoords) { - return MotionEvent.obtain(downTime, eventTime, action, pointerCount, - ptrProps, ptrCoords, 0, 0, 1.0f, 1.0f, - 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0); - } - - private boolean injectEventSync(InputEvent event) { - return mUiAutomation.injectInputEvent(event, true); - } -} diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt index fd13d14074d4..d5334cbd541c 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt @@ -21,6 +21,7 @@ import android.graphics.Rect import android.graphics.Region import android.tools.device.apphelpers.StandardAppHelper import android.tools.helpers.FIND_TIMEOUT +import android.tools.helpers.GestureHelper import android.tools.helpers.SYSTEMUI_PACKAGE import android.tools.traces.component.ComponentNameMatcher import android.tools.traces.parsers.WindowManagerStateHelper @@ -38,7 +39,8 @@ constructor( ActivityOptions.NonResizeableFixedAspectRatioPortraitActivity.COMPONENT.toFlickerComponent() ) : StandardAppHelper(instr, launcherName, component) { - private val gestureHelper: GestureHelper = GestureHelper(instrumentation) + private val gestureHelper: GestureHelper = + GestureHelper(instrumentation) fun clickRestart(wmHelper: WindowManagerStateHelper) { val restartButton = diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt index db4838ee6092..de17bf422c0c 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt @@ -18,29 +18,26 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation import android.content.Intent -import android.graphics.Rect import android.graphics.Region import android.media.session.MediaController import android.media.session.MediaSessionManager -import android.tools.datatypes.coversMoreThan -import android.tools.device.apphelpers.StandardAppHelper +import android.tools.device.apphelpers.BasePipAppHelper import android.tools.helpers.FIND_TIMEOUT import android.tools.helpers.SYSTEMUI_PACKAGE import android.tools.traces.ConditionsFactory +import android.tools.traces.component.ComponentNameMatcher import android.tools.traces.component.IComponentMatcher import android.tools.traces.parsers.WindowManagerStateHelper import android.tools.traces.parsers.toFlickerComponent -import android.util.Log import androidx.test.uiautomator.By import androidx.test.uiautomator.Until import com.android.server.wm.flicker.testapp.ActivityOptions -open class PipAppHelper(instrumentation: Instrumentation) : - StandardAppHelper( - instrumentation, - ActivityOptions.Pip.LABEL, - ActivityOptions.Pip.COMPONENT.toFlickerComponent() - ) { +open class PipAppHelper( + instrumentation: Instrumentation, + appName: String = ActivityOptions.Pip.LABEL, + componentNameMatcher: ComponentNameMatcher = ActivityOptions.Pip.COMPONENT.toFlickerComponent(), +) : BasePipAppHelper(instrumentation, appName, componentNameMatcher) { private val mediaSessionManager: MediaSessionManager get() = context.getSystemService(MediaSessionManager::class.java) @@ -52,189 +49,6 @@ open class PipAppHelper(instrumentation: Instrumentation) : it.packageName == packageName } - private val gestureHelper: GestureHelper = GestureHelper(instrumentation) - - open fun clickObject(resId: String) { - val selector = By.res(packageName, resId) - val obj = uiDevice.findObject(selector) ?: error("Could not find `$resId` object") - - obj.click() - } - - /** Drags the PIP window to the provided final coordinates without releasing the pointer. */ - fun dragPipWindowAwayFromEdgeWithoutRelease(wmHelper: WindowManagerStateHelper, steps: Int) { - val initWindowRect = Rect(getWindowRect(wmHelper)) - - // initial pointer at the center of the window - val initialCoord = - GestureHelper.Tuple( - initWindowRect.centerX().toFloat(), - initWindowRect.centerY().toFloat() - ) - - // the offset to the right (or left) of the window center to drag the window to - val offset = 50 - - // the actual final x coordinate with the offset included; - // if the pip window is closer to the right edge of the display the offset is negative - // otherwise the offset is positive - val endX = - initWindowRect.centerX() + offset * (if (isCloserToRightEdge(wmHelper)) -1 else 1) - val finalCoord = GestureHelper.Tuple(endX.toFloat(), initWindowRect.centerY().toFloat()) - - // drag to the final coordinate - gestureHelper.dragWithoutRelease(initialCoord, finalCoord, steps) - } - - /** - * Releases the primary pointer. - * - * Injects the release of the primary pointer if the primary pointer info was cached after - * another gesture was injected without pointer release. - */ - fun releasePipAfterDragging() { - gestureHelper.releasePrimaryPointer() - } - - /** - * Drags the PIP window away from the screen edge while not crossing the display center. - * - * @throws IllegalStateException if default display bounds are not available - */ - fun dragPipWindowAwayFromEdge(wmHelper: WindowManagerStateHelper, steps: Int) { - val initWindowRect = Rect(getWindowRect(wmHelper)) - - // initial pointer at the center of the window - val startX = initWindowRect.centerX() - val y = initWindowRect.centerY() - - val displayRect = - wmHelper.currentState.wmState.getDefaultDisplay()?.displayRect - ?: throw IllegalStateException("Default display is null") - - // the offset to the right (or left) of the display center to drag the window to - val offset = 20 - - // the actual final x coordinate with the offset included; - // if the pip window is closer to the right edge of the display the offset is positive - // otherwise the offset is negative - val endX = displayRect.centerX() + offset * (if (isCloserToRightEdge(wmHelper)) 1 else -1) - - // drag the window to the left but not beyond the center of the display - uiDevice.drag(startX, y, endX, y, steps) - } - - /** - * Returns true if PIP window is closer to the right edge of the display than left. - * - * @throws IllegalStateException if default display bounds are not available - */ - fun isCloserToRightEdge(wmHelper: WindowManagerStateHelper): Boolean { - val windowRect = getWindowRect(wmHelper) - - val displayRect = - wmHelper.currentState.wmState.getDefaultDisplay()?.displayRect - ?: throw IllegalStateException("Default display is null") - - return windowRect.centerX() > displayRect.centerX() - } - - /** - * Expands the PIP window by using the pinch out gesture. - * - * @param percent The percentage by which to increase the pip window size. - * @throws IllegalArgumentException if percentage isn't between 0.0f and 1.0f - */ - fun pinchOpenPipWindow(wmHelper: WindowManagerStateHelper, percent: Float, steps: Int) { - // the percentage must be between 0.0f and 1.0f - if (percent <= 0.0f || percent > 1.0f) { - throw IllegalArgumentException("Percent must be between 0.0f and 1.0f") - } - - val windowRect = getWindowRect(wmHelper) - - // first pointer's initial x coordinate is halfway between the left edge and the center - val initLeftX = (windowRect.centerX() - windowRect.width() / 4).toFloat() - // second pointer's initial x coordinate is halfway between the right edge and the center - val initRightX = (windowRect.centerX() + windowRect.width() / 4).toFloat() - - // horizontal distance the window should increase by - val distIncrease = windowRect.width() * percent - - // final x-coordinates - val finalLeftX = initLeftX - (distIncrease / 2) - val finalRightX = initRightX + (distIncrease / 2) - - // y-coordinate is the same throughout this animation - val yCoord = windowRect.centerY().toFloat() - - var adjustedSteps = MIN_STEPS_TO_ANIMATE - - // if distance per step is at least 1, then we can use the number of steps requested - if (distIncrease.toInt() / (steps * 2) >= 1) { - adjustedSteps = steps - } - - // if the distance per step is less than 1, carry out the animation in two steps - gestureHelper.pinch( - GestureHelper.Tuple(initLeftX, yCoord), - GestureHelper.Tuple(initRightX, yCoord), - GestureHelper.Tuple(finalLeftX, yCoord), - GestureHelper.Tuple(finalRightX, yCoord), - adjustedSteps - ) - - waitForPipWindowToExpandFrom(wmHelper, Region(windowRect)) - } - - /** - * Minimizes the PIP window by using the pinch in gesture. - * - * @param percent The percentage by which to decrease the pip window size. - * @throws IllegalArgumentException if percentage isn't between 0.0f and 1.0f - */ - fun pinchInPipWindow(wmHelper: WindowManagerStateHelper, percent: Float, steps: Int) { - // the percentage must be between 0.0f and 1.0f - if (percent <= 0.0f || percent > 1.0f) { - throw IllegalArgumentException("Percent must be between 0.0f and 1.0f") - } - - val windowRect = getWindowRect(wmHelper) - - // first pointer's initial x coordinate is halfway between the left edge and the center - val initLeftX = (windowRect.centerX() - windowRect.width() / 4).toFloat() - // second pointer's initial x coordinate is halfway between the right edge and the center - val initRightX = (windowRect.centerX() + windowRect.width() / 4).toFloat() - - // decrease by the distance specified through the percentage - val distDecrease = windowRect.width() * percent - - // get the final x-coordinates and make sure they are not passing the center of the window - val finalLeftX = Math.min(initLeftX + (distDecrease / 2), windowRect.centerX().toFloat()) - val finalRightX = Math.max(initRightX - (distDecrease / 2), windowRect.centerX().toFloat()) - - // y-coordinate is the same throughout this animation - val yCoord = windowRect.centerY().toFloat() - - var adjustedSteps = MIN_STEPS_TO_ANIMATE - - // if distance per step is at least 1, then we can use the number of steps requested - if (distDecrease.toInt() / (steps * 2) >= 1) { - adjustedSteps = steps - } - - // if the distance per step is less than 1, carry out the animation in two steps - gestureHelper.pinch( - GestureHelper.Tuple(initLeftX, yCoord), - GestureHelper.Tuple(initRightX, yCoord), - GestureHelper.Tuple(finalLeftX, yCoord), - GestureHelper.Tuple(finalRightX, yCoord), - adjustedSteps - ) - - waitForPipWindowToMinimizeFrom(wmHelper, Region(windowRect)) - } - /** * Launches the app through an intent instead of interacting with the launcher and waits until * the app window is in PIP mode @@ -331,126 +145,6 @@ open class PipAppHelper(instrumentation: Instrumentation) : closePipWindow(WindowManagerStateHelper(instrumentation)) } - /** Returns the pip window bounds. */ - fun getWindowRect(wmHelper: WindowManagerStateHelper): Rect { - val windowRegion = wmHelper.getWindowRegion(this) - require(!windowRegion.isEmpty) { "Unable to find a PIP window in the current state" } - return windowRegion.bounds - } - - /** Taps the pip window and dismisses it by clicking on the X button. */ - open fun closePipWindow(wmHelper: WindowManagerStateHelper) { - val windowRect = getWindowRect(wmHelper) - uiDevice.click(windowRect.centerX(), windowRect.centerY()) - // search and interact with the dismiss button - val dismissSelector = By.res(SYSTEMUI_PACKAGE, "dismiss") - uiDevice.wait(Until.hasObject(dismissSelector), FIND_TIMEOUT) - val dismissPipObject = - uiDevice.findObject(dismissSelector) ?: error("PIP window dismiss button not found") - val dismissButtonBounds = dismissPipObject.visibleBounds - uiDevice.click(dismissButtonBounds.centerX(), dismissButtonBounds.centerY()) - - // Wait for animation to complete. - wmHelper.StateSyncBuilder().withPipGone().withHomeActivityVisible().waitForAndVerify() - } - - open fun tapPipToShowMenu(wmHelper: WindowManagerStateHelper) { - val windowRect = getWindowRect(wmHelper) - uiDevice.click(windowRect.centerX(), windowRect.centerY()) - // search and interact with the dismiss button - val dismissSelector = By.res(SYSTEMUI_PACKAGE, "dismiss") - uiDevice.wait(Until.hasObject(dismissSelector), FIND_TIMEOUT) - } - - /** Close the pip window by pressing the expand button */ - fun expandPipWindowToApp(wmHelper: WindowManagerStateHelper) { - val windowRect = getWindowRect(wmHelper) - uiDevice.click(windowRect.centerX(), windowRect.centerY()) - // search and interact with the expand button - val expandSelector = By.res(SYSTEMUI_PACKAGE, "expand_button") - uiDevice.wait(Until.hasObject(expandSelector), FIND_TIMEOUT) - val expandPipObject = - uiDevice.findObject(expandSelector) ?: error("PIP window expand button not found") - val expandButtonBounds = expandPipObject.visibleBounds - uiDevice.click(expandButtonBounds.centerX(), expandButtonBounds.centerY()) - wmHelper.StateSyncBuilder().withPipGone().withFullScreenApp(this).waitForAndVerify() - } - - /** Double click on the PIP window to expand it */ - fun doubleClickPipWindow(wmHelper: WindowManagerStateHelper) { - val windowRect = getWindowRect(wmHelper) - Log.d(TAG, "First click") - uiDevice.click(windowRect.centerX(), windowRect.centerY()) - Log.d(TAG, "Second click") - uiDevice.click(windowRect.centerX(), windowRect.centerY()) - Log.d(TAG, "Wait for app transition to end") - wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify() - waitForPipWindowToExpandFrom(wmHelper, Region(windowRect)) - } - - private fun waitForPipWindowToExpandFrom( - wmHelper: WindowManagerStateHelper, - windowRect: Region - ) { - wmHelper - .StateSyncBuilder() - .add("pipWindowExpanded") { - val pipAppWindow = - it.wmState.visibleWindows.firstOrNull { window -> - this.windowMatchesAnyOf(window) - } - ?: return@add false - val pipRegion = pipAppWindow.frameRegion - return@add pipRegion.coversMoreThan(windowRect) - } - .waitForAndVerify() - } - - private fun waitForPipWindowToMinimizeFrom( - wmHelper: WindowManagerStateHelper, - windowRect: Region - ) { - wmHelper - .StateSyncBuilder() - .add("pipWindowMinimized") { - val pipAppWindow = - it.wmState.visibleWindows.firstOrNull { window -> - this.windowMatchesAnyOf(window) - } - Log.d(TAG, "window " + pipAppWindow) - if (pipAppWindow == null) return@add false - val pipRegion = pipAppWindow.frameRegion - Log.d( - TAG, - "region " + pipRegion + " covers " + windowRect.coversMoreThan(pipRegion) - ) - return@add windowRect.coversMoreThan(pipRegion) - } - .waitForAndVerify() - } - - /** - * Waits until the PIP window snaps horizontally to the provided bounds. - * - * @param finalBounds the bounds to wait for PIP window to snap to - */ - fun waitForPipToSnapTo(wmHelper: WindowManagerStateHelper, finalBounds: android.graphics.Rect) { - wmHelper - .StateSyncBuilder() - .add("pipWindowSnapped") { - val pipAppWindow = - it.wmState.visibleWindows.firstOrNull { window -> - this.windowMatchesAnyOf(window) - } - ?: return@add false - val pipRegionBounds = pipAppWindow.frameRegion.bounds - return@add pipRegionBounds.left == finalBounds.left && - pipRegionBounds.right == finalBounds.right - } - .add(ConditionsFactory.isWMStateComplete()) - .waitForAndVerify() - } - companion object { private const val TAG = "PipAppHelper" private const val ENTER_PIP_BUTTON_ID = "enter_pip" @@ -459,8 +153,5 @@ open class PipAppHelper(instrumentation: Instrumentation) : private const val ENTER_PIP_ON_USER_LEAVE_HINT = "enter_pip_on_leave_manual" private const val ENTER_PIP_AUTOENTER = "enter_pip_on_leave_autoenter" private const val SOURCE_RECT_HINT = "set_source_rect_hint" - // minimum number of steps to take, when animating gestures, needs to be 2 - // so that there is at least a single intermediate layer that flicker tests can check - private const val MIN_STEPS_TO_ANIMATE = 2 } -} +}
\ No newline at end of file |