diff options
14 files changed, 339 insertions, 58 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java index 55e90e74a404..bec75b3d865c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java @@ -664,10 +664,12 @@ public class PipAnimationController { // TODO(b/375977163): polish the animation to restoring the PIP task back from // swipe-pip-to-home. Ideally we should send the transitionInfo after reparenting // the PIP activity back to the original task. - if (shouldUseMainWindowFrame) { + if (shouldUseMainWindowFrame && isOutPipDirection) { // If we should animate the main window frame, set it to the rotatedRect // instead. The end bounds reported by transitionInfo is the bounds before // rotation, while main window frame is calculated after the rotation. + // Note that we only override main window frame for leaving pip animation as + // the pip activity should match parent. rotatedEndRect.set(mainWindowFrame); } else { // Rotate the end bounds according to the rotation delta because the display @@ -810,11 +812,19 @@ public class PipAnimationController { } } final Rect sourceBounds = new Rect(initialContainerRect); + Rect relativeEndWindowFrame = null; + if (isOutPipDirection) { + relativeEndWindowFrame = rotatedEndRect; + } + if (relativeEndWindowFrame != null) { + relativeEndWindowFrame.offset(leashOffset.x, leashOffset.y); + } sourceBounds.inset(insets); getSurfaceTransactionHelper() .rotateAndScaleWithCrop(tx, leash, initialContainerRect, bounds, insets, degree, x, y, isOutPipDirection, - rotationDelta == ROTATION_270 /* clockwise */) + rotationDelta == ROTATION_270 /* clockwise */, + relativeEndWindowFrame) .round(tx, leash, sourceBounds, bounds) .shadow(tx, leash, shouldApplyShadowRadius()); if (!handlePipTransaction(leash, tx, bounds, 1f /* alpha */)) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java index b02bd0ffec6c..955a981799f5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java @@ -25,6 +25,8 @@ import android.graphics.RectF; import android.view.Choreographer; import android.view.SurfaceControl; +import androidx.annotation.Nullable; + import com.android.wm.shell.R; import com.android.wm.shell.transition.Transitions; @@ -224,12 +226,17 @@ public class PipSurfaceTransactionHelper { /** * Operates the rotation according to the given degrees and scale (setMatrix) according to the * source bounds and rotated destination bounds. The crop will be the unscaled source bounds. + * + * @param relativeEndWindowFrame specified if + * {@link android.app.TaskInfo#topActivityMainWindowFrame} is provided. It's only applied for + * the animation that {@code isExpanding} PIP to original task. * @return same {@link PipSurfaceTransactionHelper} instance for method chaining */ - public PipSurfaceTransactionHelper rotateAndScaleWithCrop(SurfaceControl.Transaction tx, - SurfaceControl leash, Rect sourceBounds, Rect destinationBounds, Rect insets, + public PipSurfaceTransactionHelper rotateAndScaleWithCrop( + @NonNull SurfaceControl.Transaction tx, @NonNull SurfaceControl leash, + @NonNull Rect sourceBounds, @NonNull Rect destinationBounds, @NonNull Rect insets, float degrees, float positionX, float positionY, boolean isExpanding, - boolean clockwise) { + boolean clockwise, @Nullable Rect relativeEndWindowFrame) { mTmpDestinationRect.set(sourceBounds); mTmpDestinationRect.inset(insets); final int srcW = mTmpDestinationRect.width(); @@ -240,23 +247,31 @@ public class PipSurfaceTransactionHelper { // destination are different. final float scale = srcW <= srcH ? (float) destW / srcW : (float) destH / srcH; final Rect crop = mTmpDestinationRect; - crop.set(0, 0, Transitions.SHELL_TRANSITIONS_ROTATION ? destH - : destW, Transitions.SHELL_TRANSITIONS_ROTATION ? destW : destH); - // Inverse scale for crop to fit in screen coordinates. - crop.scale(1 / scale); - crop.offset(insets.left, insets.top); - if (isExpanding) { - // Expand bounds (shrink insets) in source orientation. - positionX -= insets.left * scale; - positionY -= insets.top * scale; + if (isExpanding && relativeEndWindowFrame != null) { + // If relative end window frame is provided, it usually means the top activity chooses + // a customized layout which may not match parent. In this case, we should crop the + // task surface with the window frame. Note that we don't need to consider the insets + // because the main window frame excludes the insets. + crop.set(relativeEndWindowFrame); } else { - // Shrink bounds (expand insets) in destination orientation. - if (clockwise) { - positionX -= insets.top * scale; - positionY += insets.left * scale; + crop.set(0, 0, Transitions.SHELL_TRANSITIONS_ROTATION ? destH + : destW, Transitions.SHELL_TRANSITIONS_ROTATION ? destW : destH); + // Inverse scale for crop to fit in screen coordinates. + crop.scale(1 / scale); + crop.offset(insets.left, insets.top); + if (isExpanding) { + // Expand bounds (shrink insets) in source orientation. + positionX -= insets.left * scale; + positionY -= insets.top * scale; } else { - positionX += insets.top * scale; - positionY -= insets.left * scale; + // Shrink bounds (expand insets) in destination orientation. + if (clockwise) { + positionX -= insets.top * scale; + positionY += insets.left * scale; + } else { + positionX += insets.top * scale; + positionY -= insets.left * scale; + } } } mTmpTransform.setScale(scale, scale); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java index 0042ec954f32..bd676ce69cfe 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java @@ -844,7 +844,8 @@ public class PipTransition extends PipTransitionController { } mSurfaceTransactionHelper.rotateAndScaleWithCrop(finishTransaction, pipLeash, endBounds, endBounds, new Rect(), degree, x, y, - true /* isExpanding */, rotationDelta == ROTATION_270 /* clockwise */); + true /* isExpanding */, rotationDelta == ROTATION_270 /* clockwise */, + null /* relativeEndWindowFrame */); } else { rotationDelta = Surface.ROTATION_0; } @@ -868,7 +869,9 @@ public class PipTransition extends PipTransitionController { // Get the start bounds in new orientation. final Rect startBounds = new Rect(pipChange.getStartAbsBounds()); rotateBounds(startBounds, displayRotationChange.getStartAbsBounds(), rotateDelta); - final Rect endBounds = new Rect(pipChange.getEndAbsBounds()); + final Rect windowFrame = taskInfo.topActivityMainWindowFrame; + final Rect endBounds = new Rect(windowFrame != null + ? windowFrame : pipChange.getEndAbsBounds()); startBounds.offset(-offset.x, -offset.y); endBounds.offset(-offset.x, -offset.y); @@ -888,7 +891,7 @@ public class PipTransition extends PipTransitionController { } mSurfaceTransactionHelper.rotateAndScaleWithCrop(startTransaction, pipChange.getLeash(), endBounds, startBounds, new Rect(), degree, x, y, true /* isExpanding */, - pipRotateDelta == ROTATION_270 /* clockwise */); + pipRotateDelta == ROTATION_270 /* clockwise */, null /* relativeEndWindowFrame */); startTransaction.apply(); rotator.cleanUp(finishTransaction); diff --git a/libs/WindowManager/Shell/tests/flicker/pip/Android.bp b/libs/WindowManager/Shell/tests/flicker/pip/Android.bp index 6e0dcdb21fa8..c760cf1d2094 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/Android.bp +++ b/libs/WindowManager/Shell/tests/flicker/pip/Android.bp @@ -75,8 +75,8 @@ android_test { ], static_libs: ["WMShellFlickerTestsBase"], test_suites: [ - "device-tests", "csuite", + "device-tests", ], data: ["trace_config/*"], } @@ -117,9 +117,11 @@ test_module_config { "com.android.wm.shell.flicker.pip.ShowPipAndRotateDisplay", "com.android.wm.shell.flicker.pip.nonmatchparent.BottomHalfAutoEnterPipOnGoToHomeTest", "com.android.wm.shell.flicker.pip.nonmatchparent.BottomHalfEnterPipOnUserLeaveHintTest", + "com.android.wm.shell.flicker.pip.nonmatchparent.BottomHalfEnterPipToOtherOrientation", "com.android.wm.shell.flicker.pip.nonmatchparent.BottomHalfEnterPipViaAppUiButtonTest", "com.android.wm.shell.flicker.pip.nonmatchparent.BottomHalfExitPipToAppViaExpandButtonTest", "com.android.wm.shell.flicker.pip.nonmatchparent.BottomHalfExitPipToAppViaIntentTest", + "com.android.wm.shell.flicker.pip.nonmatchparent.BottomHalfSetRequestedOrientationWhilePinned", ], test_suites: ["device-tests"], } @@ -308,5 +310,19 @@ test_module_config { test_suites: ["device-tests"], } +test_module_config { + name: "WMShellFlickerTestsPip-BottomHalfEnterPipToOtherOrientation", + base: "WMShellFlickerTestsPip", + include_filters: ["com.android.wm.shell.flicker.pip.nonmatchparent.BottomHalfEnterPipToOtherOrientation"], + test_suites: ["device-tests"], +} + +test_module_config { + name: "WMShellFlickerTestsPip-BottomHalfSetRequestedOrientationWhilePinned", + base: "WMShellFlickerTestsPip", + include_filters: ["com.android.wm.shell.flicker.pip.nonmatchparent.BottomHalfSetRequestedOrientationWhilePinned"], + test_suites: ["device-tests"], +} + // End breakdowns for WMShellFlickerTestsPip module //////////////////////////////////////////////////////////////////////////////// diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt index 49efd1d56256..636549fa0662 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt @@ -16,7 +16,6 @@ package com.android.wm.shell.flicker.pip -import android.app.Activity import android.platform.test.annotations.Postsubmit import android.platform.test.annotations.Presubmit import android.platform.test.annotations.RequiresFlagsDisabled @@ -38,9 +37,10 @@ import com.android.wm.shell.Flags import com.android.wm.shell.flicker.pip.common.PipTransition import com.android.wm.shell.flicker.pip.common.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE import com.android.wm.shell.flicker.pip.common.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_PORTRAIT -import org.junit.Assume -import org.junit.Before +import org.junit.Assume.assumeFalse +import org.junit.Assume.assumeTrue import org.junit.FixMethodOrder +import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters @@ -72,10 +72,10 @@ import org.junit.runners.Parameterized @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) @RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) -class EnterPipToOtherOrientation(flicker: LegacyFlickerTest) : PipTransition(flicker) { +open class EnterPipToOtherOrientation(flicker: LegacyFlickerTest) : PipTransition(flicker) { override val pipApp: PipAppHelper = PipAppHelper(instrumentation) - private val testApp = FixedOrientationAppHelper(instrumentation) - private val startingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_90) + internal val testApp = FixedOrientationAppHelper(instrumentation) + internal val startingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_90) private val endingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_0) override val thisTransition: FlickerBuilder.() -> Unit = { @@ -112,32 +112,27 @@ class EnterPipToOtherOrientation(flicker: LegacyFlickerTest) : PipTransition(fli } /** - * This test is not compatible with Tablets. When using [Activity.setRequestedOrientation] to - * fix a orientation, Tablets instead keep the same orientation and add letterboxes - */ - @Before - fun setup() { - Assume.assumeFalse(tapl.isTablet) - } - - /** * Checks that all parts of the screen are covered at the start and end of the transition */ @Presubmit @Test - fun entireScreenCoveredAtStartAndEnd() = flicker.entireScreenCovered() + fun entireScreenCoveredAtStartAndEnd() { + assumeFalse(tapl.isTablet) + flicker.entireScreenCovered() + } /** Checks [pipApp] window remains visible and on top throughout the transition */ @Presubmit @Test fun pipAppWindowIsAlwaysOnTop() { + assumeFalse(tapl.isTablet) flicker.assertWm { isAppWindowOnTop(pipApp) } } /** Checks that [testApp] window is not visible at the start */ @Presubmit @Test - fun testAppWindowInvisibleOnStart() { + open fun testAppWindowInvisibleOnStart() { flicker.assertWmStart { isAppWindowInvisible(testApp) } } @@ -145,13 +140,15 @@ class EnterPipToOtherOrientation(flicker: LegacyFlickerTest) : PipTransition(fli @Presubmit @Test fun testAppWindowVisibleOnEnd() { + assumeFalse(tapl.isTablet) flicker.assertWmEnd { isAppWindowVisible(testApp) } } /** Checks that [testApp] layer is not visible at the start */ @Presubmit @Test - fun testAppLayerInvisibleOnStart() { + open fun testAppLayerInvisibleOnStart() { + assumeFalse(tapl.isTablet) flicker.assertLayersStart { isInvisible(testApp) } } @@ -159,6 +156,7 @@ class EnterPipToOtherOrientation(flicker: LegacyFlickerTest) : PipTransition(fli @Presubmit @Test fun testAppLayerVisibleOnEnd() { + assumeFalse(tapl.isTablet) flicker.assertLayersEnd { isVisible(testApp) } } @@ -168,8 +166,8 @@ class EnterPipToOtherOrientation(flicker: LegacyFlickerTest) : PipTransition(fli */ @Presubmit @Test - fun pipAppLayerCoversFullScreenOnStart() { - Assume.assumeFalse(tapl.isTablet) + open fun pipAppLayerCoversFullScreenOnStart() { + assumeFalse(tapl.isTablet) flicker.assertLayersStart { visibleRegion(pipApp).coversExactly(startingBounds) } } @@ -177,10 +175,11 @@ class EnterPipToOtherOrientation(flicker: LegacyFlickerTest) : PipTransition(fli * Checks that the visible region of [pipApp] covers the full display area at the start of the * transition */ + @Ignore("TODO(b/356277166): enable the tablet test") @Postsubmit @Test - fun pipAppLayerPlusLetterboxCoversFullScreenOnStartTablet() { - Assume.assumeFalse(tapl.isTablet) + open fun pipAppLayerPlusLetterboxCoversFullScreenOnStartTablet() { + assumeTrue(tapl.isTablet) flicker.assertLayersStart { visibleRegion(pipApp.or(ComponentNameMatcher.LETTERBOX)).coversExactly(startingBounds) } @@ -193,6 +192,7 @@ class EnterPipToOtherOrientation(flicker: LegacyFlickerTest) : PipTransition(fli @Presubmit @Test fun testAppPlusPipLayerCoversFullScreenOnEnd() { + assumeFalse(tapl.isTablet) flicker.assertLayersEnd { val pipRegion = visibleRegion(pipApp).region visibleRegion(testApp).plus(pipRegion).coversExactly(endingBounds) @@ -202,6 +202,7 @@ class EnterPipToOtherOrientation(flicker: LegacyFlickerTest) : PipTransition(fli @Postsubmit @Test fun menuOverlayMatchesTaskSurface() { + assumeFalse(tapl.isTablet) flicker.assertLayersEnd { val pipAppRegion = visibleRegion(pipApp) val pipMenuRegion = visibleRegion(ComponentNameMatcher.PIP_MENU_OVERLAY) @@ -212,6 +213,7 @@ class EnterPipToOtherOrientation(flicker: LegacyFlickerTest) : PipTransition(fli @Presubmit @Test fun pipLayerRemainInsideVisibleBounds() { + assumeFalse(tapl.isTablet) // during the transition we assert the center point is within the display bounds, since it // might go outside of bounds as we resize from landscape fullscreen to destination bounds, // and once the animation is over we assert that it's fully within the display bounds, at diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt index f9a9df43a009..2f4c8008f220 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt @@ -64,7 +64,7 @@ class ExitPipToAppViaIntentTest(flicker: LegacyFlickerTest) : ExitPipToAppTransi } transitions { // This will bring PipApp to fullscreen - pipApp.exitPipToFullScreenViaIntent(wmHelper) + pipApp.exitPipToOriginalTaskViaIntent(wmHelper) // Wait until the other app is no longer visible wmHelper.StateSyncBuilder().withWindowSurfaceDisappeared(testApp).waitForAndVerify() } diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt index 9d46ac1d6e00..86c32de6461d 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt @@ -43,8 +43,26 @@ import org.junit.runners.MethodSorters import org.junit.runners.Parameterized /** - * Test exiting Pip with orientation changes. To run this test: - * `atest WMShellFlickerTestsPip1:SetRequestedOrientationWhilePinned` + * Test leaving pip while changing orientation (from pip window in portrait to app in landscape) + * + * To run this test: `atest WMShellFlickerTestsPip:SetRequestedOrientationWhilePinned` + * + * Actions: + * ``` + * Launch [pipApp] on a fixed landscape orientation + * Broadcast action [ACTION_ENTER_PIP] to enter pip mode in portrait + * Restore PIP from the original task to landscape + * ``` + * + * Notes: + * ``` + * 1. Some default assertions (e.g., nav bar, status bar and screen covered) + * are inherited [PipTransition] + * 2. Part of the test setup occurs automatically via + * [android.tools.flicker.legacy.runner.TransitionRunner], + * including configuring navigation mode, initial orientation and ensuring no + * apps are running before setup + * ``` */ @RequiresDevice @RunWith(Parameterized::class) @@ -53,7 +71,7 @@ import org.junit.runners.Parameterized @RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) open class SetRequestedOrientationWhilePinned(flicker: LegacyFlickerTest) : PipTransition(flicker) { private val startingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_0) - private val endingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_90) + internal open val endingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_90) override val thisTransition: FlickerBuilder.() -> Unit = { transitions { @@ -131,7 +149,7 @@ open class SetRequestedOrientationWhilePinned(flicker: LegacyFlickerTest) : PipT @Presubmit @Test - fun pipAppLayerCoversFullScreen() { + open fun pipAppLayerCoversDisplayBoundsOnEnd() { flicker.assertLayersEnd { visibleRegion(pipApp).coversExactly(endingBounds) } } diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/nonmatchparent/BottomHalfEnterPipToOtherOrientation.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/nonmatchparent/BottomHalfEnterPipToOtherOrientation.kt new file mode 100644 index 000000000000..4987ab7b9344 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/nonmatchparent/BottomHalfEnterPipToOtherOrientation.kt @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2024 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.nonmatchparent + +import android.platform.test.annotations.Presubmit +import android.platform.test.annotations.RequiresFlagsDisabled +import android.platform.test.annotations.RequiresFlagsEnabled +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.traces.component.ComponentNameMatcher +import com.android.server.wm.flicker.helpers.BottomHalfPipAppHelper +import com.android.server.wm.flicker.helpers.PipAppHelper +import com.android.wm.shell.Flags +import com.android.wm.shell.flicker.pip.EnterPipToOtherOrientation +import org.junit.Assume.assumeFalse +import org.junit.Assume.assumeTrue +import org.junit.FixMethodOrder +import org.junit.Ignore +import org.junit.Test +import org.junit.runners.MethodSorters +import org.junit.runners.Parameterized + +/** + * Test entering pip while changing orientation (from bottom half app in landscape to pip window in + * portrait) + * + * To run this test: `atest WMShellFlickerTestsPip:BottomHalfEnterPipToOtherOrientation` + * + * Actions: + * ``` + * Launch [testApp] on a fixed portrait orientation + * Launch [pipApp] on a fixed landscape orientation + * Broadcast action [ACTION_ENTER_PIP] to enter pip mode + * ``` + * + * Notes: + * ``` + * 1. Some default assertions (e.g., nav bar, status bar and screen covered) + * are inherited [PipTransition] + * 2. Part of the test setup occurs automatically via + * [android.tools.flicker.legacy.runner.TransitionRunner], + * including configuring navigation mode, initial orientation and ensuring no + * apps are running before setup + * ``` + */ +// TODO(b/380796448): re-enable tests after the support of non-match parent PIP animation for PIP2. +@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) +@RequiresFlagsEnabled(com.android.window.flags.Flags.FLAG_BETTER_SUPPORT_NON_MATCH_PARENT_ACTIVITY) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +class BottomHalfEnterPipToOtherOrientation(flicker: LegacyFlickerTest) : + EnterPipToOtherOrientation(flicker) +{ + override val pipApp: PipAppHelper = BottomHalfPipAppHelper(instrumentation) + + @Presubmit + @Test + override fun pipAppLayerCoversFullScreenOnStart() { + // Test app and pip app should covers the entire screen on start. + assumeFalse(tapl.isTablet) + flicker.assertLayersStart { + visibleRegion(pipApp.or(testApp)).coversExactly(startingBounds) + } + } + + @Ignore("TODO(b/356277166): enable the tablet test") + @Presubmit + @Test + override fun pipAppLayerPlusLetterboxCoversFullScreenOnStartTablet() { + // Test app and pip app should covers the entire screen on start. + assumeTrue(tapl.isTablet) + flicker.assertLayersStart { + visibleRegion(pipApp.or(ComponentNameMatcher.LETTERBOX)).coversExactly(startingBounds) + } + } + + @Presubmit + @Test + override fun testAppWindowInvisibleOnStart() { + // Test app and pip app should covers the entire screen on start. + } + + @Presubmit + @Test + override fun testAppLayerInvisibleOnStart() { + // Test app and pip app should covers the entire screen on start. + } +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/nonmatchparent/BottomHalfExitPipToAppViaIntentTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/nonmatchparent/BottomHalfExitPipToAppViaIntentTest.kt index 8ed9cd23005b..8a10c78465bc 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/nonmatchparent/BottomHalfExitPipToAppViaIntentTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/nonmatchparent/BottomHalfExitPipToAppViaIntentTest.kt @@ -67,7 +67,7 @@ class BottomHalfExitPipToAppViaIntentTest(flicker: LegacyFlickerTest) : } transitions { // This will bring PipApp to fullscreen - pipApp.exitPipToFullScreenViaIntent(wmHelper) + pipApp.exitPipToOriginalTaskViaIntent(wmHelper) // Wait until the transition idle and test and pip app still shows. wmHelper.StateSyncBuilder().withLayerVisible(testApp).withLayerVisible(pipApp) .withAppTransitionIdle().waitForAndVerify() diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/nonmatchparent/BottomHalfSetRequestedOrientationWhilePinned.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/nonmatchparent/BottomHalfSetRequestedOrientationWhilePinned.kt new file mode 100644 index 000000000000..42f5a50c3310 --- /dev/null +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/nonmatchparent/BottomHalfSetRequestedOrientationWhilePinned.kt @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2024 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.nonmatchparent + +import android.platform.test.annotations.Presubmit +import android.platform.test.annotations.RequiresFlagsDisabled +import android.platform.test.annotations.RequiresFlagsEnabled +import android.tools.Rotation +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.traces.parsers.toFlickerComponent +import com.android.server.wm.flicker.helpers.BottomHalfPipAppHelper +import com.android.server.wm.flicker.helpers.PipAppHelper +import com.android.server.wm.flicker.testapp.ActivityOptions.BottomHalfPip +import com.android.wm.shell.Flags +import com.android.wm.shell.flicker.pip.SetRequestedOrientationWhilePinned +import org.junit.FixMethodOrder +import org.junit.Test +import org.junit.runners.MethodSorters +import org.junit.runners.Parameterized + +/** + * Test leaving pip while changing orientation (from pip window in portrait to bottom half app in + * landscape) + * + * To run this test: `atest WMShellFlickerTestsPip:BottomHalfSetRequestedOrientationWhilePinned` + * + * Actions: + * ``` + * Launch bottom half [pipApp] on a fixed landscape orientation via launching app + * Broadcast action [ACTION_ENTER_PIP] to enter pip mode + * Restore PIP from the original task to landscape + * ``` + * + * Notes: + * ``` + * 1. Some default assertions (e.g., nav bar, status bar and screen covered) + * are inherited [PipTransition] + * 2. Part of the test setup occurs automatically via + * [android.tools.flicker.legacy.runner.TransitionRunner], + * including configuring navigation mode, initial orientation and ensuring no + * apps are running before setup + * ``` + */ +// TODO(b/380796448): re-enable tests after the support of non-match parent PIP animation for PIP2. +@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) +@RequiresFlagsEnabled(com.android.window.flags.Flags.FLAG_BETTER_SUPPORT_NON_MATCH_PARENT_ACTIVITY) +@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +class BottomHalfSetRequestedOrientationWhilePinned(flicker: LegacyFlickerTest) : + SetRequestedOrientationWhilePinned(flicker) +{ + override val pipApp: PipAppHelper = BottomHalfPipAppHelper( + instrumentation, + useLaunchingActivity = true + ) + + override val thisTransition: FlickerBuilder.() -> Unit = { + transitions { + // Launch the activity back into fullscreen and ensure that it is now in landscape + pipApp.exitPipToOriginalTaskViaIntent(wmHelper) + // System bar may fade out during fixed rotation. + wmHelper + .StateSyncBuilder() + .withTopVisibleApp(pipApp) + .withRotation(Rotation.ROTATION_90) + .withNavOrTaskBarVisible() + .withStatusBarVisible() + .waitForAndVerify() + } + } + + @Presubmit + @Test + override fun pipAppLayerCoversDisplayBoundsOnEnd() { + flicker.assertLayersEnd { + visibleRegion(pipApp + .or(BottomHalfPip.LAUNCHING_APP_COMPONENT.toFlickerComponent())) + .coversExactly(endingBounds) + } + } +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java index 6d37ed766aef..53f6cda62f55 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java @@ -189,7 +189,7 @@ public class PipAnimationControllerTest extends ShellTestCase { // Apply fraction 1 to compute the end value. animator.applySurfaceControlTransaction(mLeash, tx, 1); - assertEquals("Expect use main window frame", mTaskInfo.topActivityMainWindowFrame, + assertEquals("Expect main window frame", mTaskInfo.topActivityMainWindowFrame, animator.mCurrentValue); // PiP to fullscreen. @@ -200,9 +200,11 @@ public class PipAnimationControllerTest extends ShellTestCase { endBounds, null, TRANSITION_DIRECTION_TO_PIP, 0, ROTATION_270, false /* alwaysAnimateTaskBounds */); animator.applySurfaceControlTransaction(mLeash, tx, 1); + final Rect rotatedEndBounds = new Rect(endBounds); + rotateBounds(rotatedEndBounds, startBounds, ROTATION_270); - assertEquals("Expect use main window frame", mTaskInfo.topActivityMainWindowFrame, - animator.mCurrentValue); + assertEquals("Expect rotated bounds. We only use main window frame for " + + "leave-pip animation", rotatedEndBounds, animator.mCurrentValue); } @Test diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/BottomHalfPipAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/BottomHalfPipAppHelper.kt index 6573c2c83f20..ed2cff4a9515 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/BottomHalfPipAppHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/BottomHalfPipAppHelper.kt @@ -19,6 +19,7 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation import android.content.Intent import android.tools.traces.parsers.toFlickerComponent +import android.tools.traces.parsers.WindowManagerStateHelper import com.android.server.wm.flicker.testapp.ActivityOptions class BottomHalfPipAppHelper( @@ -38,4 +39,14 @@ class BottomHalfPipAppHelper( ActivityOptions.BottomHalfPip.COMPONENT } } + + override fun exitPipToOriginalTaskViaIntent(wmHelper: WindowManagerStateHelper) { + launchViaIntent( + wmHelper, + Intent().apply { + component = ActivityOptions.BottomHalfPip.COMPONENT + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + } + ) + } }
\ No newline at end of file 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 de17bf422c0c..344cac1ac7e5 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 @@ -75,8 +75,9 @@ open class PipAppHelper( .waitForAndVerify() } - /** Expand the PIP window back to full screen via intent and wait until the app is visible */ - fun exitPipToFullScreenViaIntent(wmHelper: WindowManagerStateHelper) = launchViaIntent(wmHelper) + /** Expand the PIP window back to original task via intent and wait until the app is visible */ + open fun exitPipToOriginalTaskViaIntent(wmHelper: WindowManagerStateHelper) = + launchViaIntent(wmHelper) fun changeAspectRatio(wmHelper: WindowManagerStateHelper) { val intent = Intent("com.android.wm.shell.flicker.testapp.ASPECT_RATIO") diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/BottomHalfPipLaunchingActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/BottomHalfPipLaunchingActivity.java index d9d4361411bb..209f71e4f307 100644 --- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/BottomHalfPipLaunchingActivity.java +++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/BottomHalfPipLaunchingActivity.java @@ -24,8 +24,12 @@ public class BottomHalfPipLaunchingActivity extends SimpleActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - final Intent intent = new Intent(this, BottomHalfPipActivity.class); + // Pass extras to BottomHalfPipActivity. + final Bundle extras = getIntent().getExtras(); + if (extras != null) { + intent.putExtras(extras); + } startActivity(intent); } } |