1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wm.flicker.activityembedding.pip 18 19 import android.platform.test.annotations.Presubmit 20 import android.tools.common.datatypes.Rect 21 import android.tools.common.traces.component.ComponentNameMatcher 22 import android.tools.common.traces.component.ComponentNameMatcher.Companion.TRANSITION_SNAPSHOT 23 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory 24 import android.tools.device.flicker.legacy.FlickerBuilder 25 import android.tools.device.flicker.legacy.LegacyFlickerTest 26 import android.tools.device.flicker.legacy.LegacyFlickerTestFactory 27 import androidx.test.filters.RequiresDevice 28 import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase 29 import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper 30 import org.junit.FixMethodOrder 31 import org.junit.Test 32 import org.junit.runner.RunWith 33 import org.junit.runners.MethodSorters 34 import org.junit.runners.Parameterized 35 36 /** 37 * Test launching a secondary Activity into Picture-In-Picture mode. 38 * 39 * Setup: Start from a split A|B. 40 * Transition: B enters PIP, observe the window shrink to the bottom right corner on screen. 41 * 42 * To run this test: `atest FlickerTestsOther:SecondaryActivityEnterPipTest` 43 * 44 */ 45 @RequiresDevice 46 @RunWith(Parameterized::class) 47 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) 48 @FixMethodOrder(MethodSorters.NAME_ASCENDING) 49 class SecondaryActivityEnterPipTest (flicker: LegacyFlickerTest) : 50 ActivityEmbeddingTestBase(flicker) { 51 override val transition: FlickerBuilder.() -> Unit = { 52 setup { 53 tapl.setExpectedRotationCheckEnabled(false) 54 testApp.launchViaIntent(wmHelper) 55 testApp.launchSecondaryActivity(wmHelper) 56 startDisplayBounds = 57 wmHelper.currentState.layerState.physicalDisplayBounds 58 ?: error("Can't get display bounds") 59 } 60 transitions { 61 testApp.secondaryActivityEnterPip(wmHelper) 62 } 63 teardown { 64 tapl.goHome() 65 testApp.exit(wmHelper) 66 } 67 } 68 69 /** 70 * Main and secondary activity start from a split each taking half of the screen. 71 */ 72 @Presubmit 73 @Test 74 fun layersStartFromEqualSplit() { 75 flicker.assertLayersStart { 76 val leftLayerRegion = 77 visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT) 78 val rightLayerRegion = 79 visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT) 80 // Compare dimensions of two splits, given we're using default split attributes, 81 // both activities take up the same visible size on the display. 82 check { "height" } 83 .that(leftLayerRegion.region.height).isEqual(rightLayerRegion.region.height) 84 check { "width" } 85 .that(leftLayerRegion.region.width).isEqual(rightLayerRegion.region.width) 86 leftLayerRegion.notOverlaps(rightLayerRegion.region) 87 leftLayerRegion.plus(rightLayerRegion.region).coversExactly(startDisplayBounds) 88 } 89 flicker.assertLayersEnd { 90 visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT) 91 .coversExactly(startDisplayBounds) 92 } 93 } 94 95 /** 96 * Main Activity is visible throughout the transition and becomes fullscreen. 97 */ 98 @Presubmit 99 @Test 100 fun mainActivityWindowBecomesFullScreen() { 101 flicker.assertWm { isAppWindowVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT) } 102 flicker.assertWmEnd { 103 visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT) 104 .coversExactly(startDisplayBounds) 105 } 106 } 107 108 /** 109 * Main Activity is visible throughout the transition and becomes fullscreen. 110 */ 111 @Presubmit 112 @Test 113 fun mainActivityLayerBecomesFullScreen() { 114 flicker.assertLayers { 115 isVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT) 116 .then() 117 .isVisible(TRANSITION_SNAPSHOT) 118 .isInvisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT) 119 .then() 120 .isVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT) 121 } 122 flicker.assertLayersEnd { 123 visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT) 124 .coversExactly(startDisplayBounds) 125 } 126 } 127 128 /** 129 * Secondary Activity is visible throughout the transition and shrinks to the bottom right 130 * corner. 131 */ 132 @Presubmit 133 @Test 134 fun secondaryWindowShrinks() { 135 flicker.assertWm { 136 isAppWindowVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT) 137 } 138 flicker.assertWmEnd { 139 val pipWindowRegion = 140 visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT) 141 check{"height"} 142 .that(pipWindowRegion.region.height) 143 .isLower(startDisplayBounds.height / 2) 144 check{"width"} 145 .that(pipWindowRegion.region.width).isLower(startDisplayBounds.width) 146 } 147 } 148 149 /** 150 * During the transition Secondary Activity shrinks to the bottom right corner. 151 */ 152 @Presubmit 153 @Test 154 fun secondaryLayerShrinks() { 155 flicker.assertLayers { 156 val pipLayerList = layers { 157 ComponentNameMatcher.PIP_CONTENT_OVERLAY.layerMatchesAnyOf(it) && it.isVisible 158 } 159 pipLayerList.zipWithNext { previous, current -> 160 // TODO(b/290987990): Add checks for visibleRegion. 161 current.screenBounds.isToTheRightBottom(previous.screenBounds.region, 3) 162 current.screenBounds.notBiggerThan(previous.screenBounds.region) 163 } 164 } 165 flicker.assertLayersEnd { 166 val pipRegion = visibleRegion( 167 ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT) 168 check { "height" } 169 .that(pipRegion.region.height) 170 .isLower(startDisplayBounds.height / 2) 171 check { "width" } 172 .that(pipRegion.region.width).isLower(startDisplayBounds.width) 173 } 174 } 175 176 companion object { 177 /** {@inheritDoc} */ 178 private var startDisplayBounds = Rect.EMPTY 179 /** 180 * Creates the test configurations. 181 * 182 * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and 183 * navigation modes. 184 */ 185 @Parameterized.Parameters(name = "{0}") 186 @JvmStatic 187 fun getParams() = LegacyFlickerTestFactory.nonRotationTests() 188 } 189 }