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.rotation
18 
19 import android.platform.test.annotations.Presubmit
20 import android.tools.common.traces.component.ComponentNameMatcher
21 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
22 import android.tools.device.flicker.legacy.FlickerBuilder
23 import android.tools.device.flicker.legacy.LegacyFlickerTest
24 import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
25 import androidx.test.filters.RequiresDevice
26 import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
27 import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
28 import com.android.server.wm.flicker.rotation.RotationTransition
29 import org.junit.FixMethodOrder
30 import org.junit.Test
31 import org.junit.runner.RunWith
32 import org.junit.runners.MethodSorters
33 import org.junit.runners.Parameterized
34 
35 /**
36  * Tests rotating two activities in an Activity Embedding split.
37  *
38  * Setup: Launch A|B in split with B being the secondary activity. Transitions: Rotate display, and
39  * expect A and B to split evenly in new rotation.
40  *
41  * To run this test: `atest FlickerTestsOther:RotateSplitNoChangeTest`
42  */
43 @RequiresDevice
44 @RunWith(Parameterized::class)
45 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
46 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
47 open class RotateSplitNoChangeTest(flicker: LegacyFlickerTest) : RotationTransition(flicker) {
48 
49     override val testApp = ActivityEmbeddingAppHelper(instrumentation)
50     override val transition: FlickerBuilder.() -> Unit
51         get() = {
52             super.transition(this)
53             setup {
54                 testApp.launchViaIntent(wmHelper)
55                 testApp.launchSecondaryActivity(wmHelper)
56             }
57         }
58 
59     /**
60      * Checks that the [ComponentNameMatcher.ROTATION] layer appears during the transition, doesn't
61      * flicker, and disappears before the transition is complete
62      */
63     @Presubmit
64     @Test
65     fun rotationLayerAppearsAndVanishes() {
66         flicker.assertLayers {
67             this.isVisible(testApp)
68                 .then()
69                 .isVisible(ComponentNameMatcher.ROTATION)
70                 .then()
71                 .isVisible(testApp)
72                 .isInvisible(ComponentNameMatcher.ROTATION)
73         }
74     }
75 
76     /**
77      * Overrides inherited assertion because in AE Split, the main and secondary activity are
78      * separate layers, each covering up exactly half of the display.
79      */
80     @Presubmit
81     @Test
82     override fun appLayerRotates_StartingPos() {
83         flicker.assertLayersStart {
84             this.entry.displays.map { display ->
85                 val leftLayerRegion =
86                     this.visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
87                 val rightLayerRegion =
88                     this.visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
89                 // Compare dimensions of two splits, given we're using default split attributes,
90                 // both activities take up the same visible size on the display.
91                 check { "height" }
92                     .that(leftLayerRegion.region.height)
93                     .isEqual(rightLayerRegion.region.height)
94                 check { "width" }
95                     .that(leftLayerRegion.region.width)
96                     .isEqual(rightLayerRegion.region.width)
97                 leftLayerRegion.notOverlaps(rightLayerRegion.region)
98                 // Layers of two activities sum to be fullscreen size on display.
99                 leftLayerRegion.plus(rightLayerRegion.region).coversExactly(display.layerStackSpace)
100             }
101         }
102     }
103 
104     /** Verifies dimensions of both split activities hold their invariance after transition too. */
105     @Presubmit
106     @Test
107     override fun appLayerRotates_EndingPos() {
108         flicker.assertLayersEnd {
109             this.entry.displays.map { display ->
110                 val leftLayerRegion =
111                     this.visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
112                 val rightLayerRegion =
113                     this.visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
114                 check { "height" }
115                     .that(leftLayerRegion.region.height)
116                     .isEqual(rightLayerRegion.region.height)
117                 check { "width" }
118                     .that(leftLayerRegion.region.width)
119                     .isEqual(rightLayerRegion.region.width)
120                 leftLayerRegion.notOverlaps(rightLayerRegion.region)
121                 leftLayerRegion.plus(rightLayerRegion.region).coversExactly(display.layerStackSpace)
122             }
123         }
124     }
125 
126     /** Both activities in split should remain visible during rotation. */
127     @Presubmit
128     @Test
129     fun bothActivitiesAreAlwaysVisible() {
130         flicker.assertWm { isAppWindowVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT) }
131         flicker.assertWm {
132             isAppWindowVisible(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
133         }
134     }
135 
136     companion object {
137         /**
138          * Creates the test configurations.
139          *
140          * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
141          * navigation modes.
142          */
143         @Parameterized.Parameters(name = "{0}")
144         @JvmStatic
145         fun getParams() = LegacyFlickerTestFactory.rotationTests()
146     }
147 }
148