[AE FlickerTest] Enter PIP test

Test: atest
Bug: 238043427

Change-Id: I02933348d2be62cb31b9ee30177f7c4e47a59ef3
This commit is contained in:
An An Yu
2023-06-01 20:49:54 +00:00
parent f29c879cdc
commit 2e34a9a471
6 changed files with 222 additions and 1 deletions

View File

@@ -42,7 +42,7 @@ import com.android.server.wm.flicker.testapp.ActivityOptions
import com.android.server.wm.flicker.testapp.ActivityOptions.SplitScreen.Primary
import org.junit.Assert.assertNotNull
internal object SplitScreenUtils {
object SplitScreenUtils {
private const val TIMEOUT_MS = 3_000L
private const val DRAG_DURATION_MS = 1_000L
private const val NOTIFICATION_SCROLLER = "notification_stack_scroller"

View File

@@ -0,0 +1,188 @@
/*
* 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.server.wm.flicker.activityembedding
import android.platform.test.annotations.Presubmit
import android.tools.common.datatypes.Rect
import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.common.traces.component.ComponentNameMatcher.Companion.TRANSITION_SNAPSHOT
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
/**
* Test launching a secondary Activity into Picture-In-Picture mode.
*
* Setup: Start from a split A|B.
* Transition: B enters PIP, observe the window shrink to the bottom right corner on screen.
*
* To run this test: `atest FlickerTests:SecondaryActivityEnterPipTest`
*
*/
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class SecondaryActivityEnterPipTest (flicker: LegacyFlickerTest) :
ActivityEmbeddingTestBase(flicker) {
override val transition: FlickerBuilder.() -> Unit = {
setup {
tapl.setExpectedRotationCheckEnabled(false)
testApp.launchViaIntent(wmHelper)
testApp.launchSecondaryActivity(wmHelper)
startDisplayBounds =
wmHelper.currentState.layerState.physicalDisplayBounds
?: error("Can't get display bounds")
}
transitions {
testApp.secondaryActivityEnterPip(wmHelper)
}
teardown {
tapl.goHome()
testApp.exit(wmHelper)
}
}
/**
* Main and secondary activity start from a split each taking half of the screen.
*/
@Presubmit
@Test
fun layersStartFromEqualSplit() {
flicker.assertLayersStart {
val leftLayerRegion =
visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
val rightLayerRegion =
visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
// Compare dimensions of two splits, given we're using default split attributes,
// both activities take up the same visible size on the display.
check { "height" }
.that(leftLayerRegion.region.height).isEqual(rightLayerRegion.region.height)
check { "width" }
.that(leftLayerRegion.region.width).isEqual(rightLayerRegion.region.width)
leftLayerRegion.notOverlaps(rightLayerRegion.region)
leftLayerRegion.plus(rightLayerRegion.region).coversExactly(startDisplayBounds)
}
flicker.assertLayersEnd {
visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
.coversExactly(startDisplayBounds)
}
}
/**
* Main Activity is visible throughout the transition and becomes fullscreen.
*/
@Presubmit
@Test
fun mainActivityWindowBecomesFullScreen() {
flicker.assertWm { isAppWindowVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT) }
flicker.assertWmEnd {
visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
.coversExactly(startDisplayBounds)
}
}
/**
* Main Activity is visible throughout the transition and becomes fullscreen.
*/
@Presubmit
@Test
fun mainActivityLayerBecomesFullScreen() {
flicker.assertLayers {
isVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
.then()
.isVisible(TRANSITION_SNAPSHOT)
.isInvisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
.then()
.isVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
}
flicker.assertLayersEnd {
visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
.coversExactly(startDisplayBounds)
}
}
/**
* Secondary Activity is visible throughout the transition and shrinks to the bottom right
* corner.
*/
@Presubmit
@Test
fun secondaryWindowShrinks() {
flicker.assertWm {
isAppWindowVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
}
flicker.assertWmEnd {
val pipWindowRegion =
visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
check{"height"}
.that(pipWindowRegion.region.height)
.isLower(startDisplayBounds.height / 2)
check{"width"}
.that(pipWindowRegion.region.width).isLower(startDisplayBounds.width)
}
}
/**
* During the transition Secondary Activity shrinks to the bottom right corner.
*/
@Presubmit
@Test
fun secondaryLayerShrinks() {
flicker.assertLayers {
val pipLayerList = layers {
ComponentNameMatcher.PIP_CONTENT_OVERLAY.layerMatchesAnyOf(it) && it.isVisible
}
pipLayerList.zipWithNext { previous, current ->
// TODO(b/290987990): Add checks for visibleRegion.
current.screenBounds.isToTheRightBottom(previous.screenBounds.region, 3)
current.screenBounds.notBiggerThan(previous.screenBounds.region)
}
}
flicker.assertLayersEnd {
val pipRegion = visibleRegion(
ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
check { "height" }
.that(pipRegion.region.height)
.isLower(startDisplayBounds.height / 2)
check { "width" }
.that(pipRegion.region.width).isLower(startDisplayBounds.width)
}
}
companion object {
/** {@inheritDoc} */
private var startDisplayBounds = Rect.EMPTY
/**
* Creates the test configurations.
*
* See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
* navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
}
}

View File

@@ -113,6 +113,21 @@ constructor(
.waitForAndVerify()
}
fun secondaryActivityEnterPip(wmHelper: WindowManagerStateHelper) {
val pipButton =
uiDevice.wait(
Until.findObject(By.res(getPackage(), "secondary_enter_pip_button")),
FIND_TIMEOUT
)
require(pipButton != null) { "Can't find enter pip button on screen." }
pipButton.click()
wmHelper
.StateSyncBuilder()
.withAppTransitionIdle()
.withPipShown()
.waitForAndVerify()
}
/**
* Clicks the button to launch a secondary activity with alwaysExpand enabled, which will launch
* a fullscreen window on top of the visible region.

View File

@@ -206,6 +206,7 @@
android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding"
android:theme="@style/CutoutShortEdges"
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
android:supportsPictureInPicture="true"
android:exported="false"/>
<activity
android:name=".ActivityEmbeddingThirdActivity"

View File

@@ -35,4 +35,10 @@
android:onClick="launchThirdActivity"
android:text="Launch a third activity" />
<Button
android:id="@+id/secondary_enter_pip_button"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:text="Enter pip" />
</LinearLayout>

View File

@@ -18,6 +18,7 @@ package com.android.server.wm.flicker.testapp;
import android.app.Activity;
import android.content.Intent;
import android.app.PictureInPictureParams;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
@@ -40,6 +41,16 @@ public class ActivityEmbeddingSecondaryActivity extends Activity {
finish();
}
});
findViewById(R.id.secondary_enter_pip_button).setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
PictureInPictureParams.Builder picInPicParamsBuilder =
new PictureInPictureParams.Builder();
enterPictureInPictureMode(picInPicParamsBuilder.build());
}
}
);
}
public void launchThirdActivity(View view) {