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.splitscreen
18 
19 import android.graphics.Rect
20 import android.platform.test.annotations.Presubmit
21 import android.platform.test.annotations.RequiresDevice
22 import android.tools.flicker.junit.FlickerParametersRunnerFactory
23 import android.tools.flicker.legacy.FlickerBuilder
24 import android.tools.flicker.legacy.LegacyFlickerTest
25 import android.tools.flicker.legacy.LegacyFlickerTestFactory
26 import android.tools.traces.parsers.toFlickerComponent
27 import androidx.test.filters.FlakyTest
28 import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
29 import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
30 import com.android.server.wm.flicker.testapp.ActivityOptions
31 import com.android.wm.shell.flicker.utils.SPLIT_SCREEN_DIVIDER_COMPONENT
32 import com.android.wm.shell.flicker.utils.SplitScreenUtils
33 import com.android.wm.shell.flicker.utils.appWindowIsVisibleAtEnd
34 import com.android.wm.shell.flicker.utils.splitAppLayerBoundsIsVisibleAtEnd
35 import com.android.wm.shell.flicker.utils.splitScreenDividerBecomesVisible
36 import kotlin.math.abs
37 import org.junit.FixMethodOrder
38 import org.junit.Ignore
39 import org.junit.Test
40 import org.junit.runner.RunWith
41 import org.junit.runners.MethodSorters
42 import org.junit.runners.Parameterized
43 
44 /**
45  * Test entering System SplitScreen with Activity Embedding Split and another app.
46  *
47  * Setup: Launch A|B in split and secondaryApp, return to home. Transitions: Let AE Split A|B enter
48  * splitscreen with secondaryApp. Resulting in A|B|secondaryApp.
49  *
50  * To run this test: `atest FlickerTestsActivityEmbedding:EnterSystemSplitTest`
51  */
52 @RequiresDevice
53 @RunWith(Parameterized::class)
54 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
55 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
56 class EnterSystemSplitTest(flicker: LegacyFlickerTest) : ActivityEmbeddingTestBase(flicker) {
57 
58     private val secondaryApp = SplitScreenUtils.getPrimary(instrumentation)
<lambda>null59     override val transition: FlickerBuilder.() -> Unit = {
60         setup {
61             testApp.launchViaIntent(wmHelper)
62             testApp.launchSecondaryActivity(wmHelper)
63             secondaryApp.launchViaIntent(wmHelper)
64             startDisplayBounds =
65                 wmHelper.currentState.layerState.physicalDisplayBounds ?: error("Display not found")
66 
67             // Record the displayBounds before `goHome()` in case the launcher is fixed-portrait.
68             tapl.goHome()
69             wmHelper
70                     .StateSyncBuilder()
71                     .withAppTransitionIdle()
72                     .withHomeActivityVisible()
73                     .waitForAndVerify()
74         }
75         transitions {
76             SplitScreenUtils.enterSplit(
77                 wmHelper,
78                 tapl,
79                 device,
80                 testApp,
81                 secondaryApp,
82                 flicker.scenario.startRotation
83             )
84             SplitScreenUtils.waitForSplitComplete(wmHelper, testApp, secondaryApp)
85         }
86     }
87 
88     @Presubmit
89     @Test
splitScreenDividerBecomesVisiblenull90     fun splitScreenDividerBecomesVisible() = flicker.splitScreenDividerBecomesVisible()
91 
92     @Presubmit
93     @Test
94     fun activityEmbeddingSplitLayerBecomesVisible() {
95         flicker.splitAppLayerBoundsIsVisibleAtEnd(
96             testApp,
97             landscapePosLeft = tapl.isTablet,
98             portraitPosTop = false
99         )
100     }
101 
102     @Presubmit
103     @Test
activityEmbeddingSplitWindowBecomesVisiblenull104     fun activityEmbeddingSplitWindowBecomesVisible() = flicker.appWindowIsVisibleAtEnd(testApp)
105 
106     @Presubmit
107     @Test
108     fun secondaryLayerBecomesVisible() {
109         flicker.splitAppLayerBoundsIsVisibleAtEnd(
110             secondaryApp,
111             landscapePosLeft = !tapl.isTablet,
112             portraitPosTop = true
113         )
114     }
115 
116     @Presubmit
117     @Test
secondaryAppWindowBecomesVisiblenull118     fun secondaryAppWindowBecomesVisible() = flicker.appWindowIsVisibleAtEnd(secondaryApp)
119 
120     /**
121      * After the transition there should be both ActivityEmbedding activities,
122      * SplitScreenPrimaryActivity and the system split divider on screen. Verify the layers are in
123      * expected sizes.
124      */
125     @Presubmit
126     @Test
127     fun activityEmbeddingSplitSurfaceAreEven() {
128         flicker.assertLayersEnd {
129             val leftAELayerRegion =
130                 visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
131             val rightAELayerRegion =
132                 visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
133             val secondaryAppLayerRegion =
134                 visibleRegion(ActivityOptions.SplitScreen.Primary.COMPONENT.toFlickerComponent())
135             val systemDivider = visibleRegion(SPLIT_SCREEN_DIVIDER_COMPONENT)
136             leftAELayerRegion
137                 .plus(rightAELayerRegion.region)
138                 .plus(secondaryAppLayerRegion.region)
139                 .plus(systemDivider.region)
140                 .coversExactly(startDisplayBounds)
141             check { "ActivityEmbeddingSplitHeight" }
142                 .that(leftAELayerRegion.region.bounds.height())
143                 .isEqual(rightAELayerRegion.region.bounds.height())
144             check { "ActivityEmbeddingSplitWidth" }
145                 .that(
146                     abs(
147                         leftAELayerRegion.region.bounds.width() -
148                             rightAELayerRegion.region.bounds.width()
149                     )
150                 )
151                 .isLower(2)
152         }
153     }
154 
155     /** Verify the windows are in expected sizes. */
156     @Presubmit
157     @Test
activityEmbeddingSplitWindowsAreEvennull158     fun activityEmbeddingSplitWindowsAreEven() {
159         flicker.assertWmEnd {
160             val leftAEWindowRegion =
161                 visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
162             val rightAEWindowRegion =
163                 visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
164             check { "ActivityEmbeddingSplitHeight" }
165                 .that(leftAEWindowRegion.region.bounds.height())
166                 .isEqual(rightAEWindowRegion.region.bounds.height())
167             check { "ActivityEmbeddingSplitWidth" }
168                 .that(
169                     abs(
170                         leftAEWindowRegion.region.bounds.width() -
171                             rightAEWindowRegion.region.bounds.width()
172                     )
173                 )
174                 .isLower(2)
175         }
176     }
177 
178     @Ignore("Not applicable to this CUJ.")
visibleLayersShownMoreThanOneConsecutiveEntrynull179     override fun visibleLayersShownMoreThanOneConsecutiveEntry() {}
180 
181     @FlakyTest(bugId = 342596801)
entireScreenCoverednull182     override fun entireScreenCovered() = super.entireScreenCovered()
183 
184     @FlakyTest(bugId = 342596801)
185     override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
186         super.visibleWindowsShownMoreThanOneConsecutiveEntry()
187 
188     companion object {
189         /** {@inheritDoc} */
190         private var startDisplayBounds = Rect()
191         /**
192          * Creates the test configurations.
193          *
194          * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
195          * navigation modes.
196          */
197         @Parameterized.Parameters(name = "{0}")
198         @JvmStatic
199         fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
200     }
201 }
202