1 /*
2  * Copyright (C) 2022 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.ime
18 
19 import android.platform.test.annotations.Postsubmit
20 import android.platform.test.annotations.Presubmit
21 import android.tools.common.Rotation
22 import android.tools.common.Timestamp
23 import android.tools.common.flicker.subject.exceptions.ExceptionMessageBuilder
24 import android.tools.common.flicker.subject.exceptions.InvalidPropertyException
25 import android.tools.common.traces.component.ComponentNameMatcher
26 import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
27 import android.tools.device.flicker.legacy.FlickerBuilder
28 import android.tools.device.flicker.legacy.LegacyFlickerTest
29 import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
30 import androidx.test.filters.RequiresDevice
31 import com.android.server.wm.flicker.BaseTest
32 import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper
33 import com.android.server.wm.flicker.helpers.setRotation
34 import com.android.server.wm.flicker.snapshotStartingWindowLayerCoversExactlyOnApp
35 import org.junit.FixMethodOrder
36 import org.junit.Test
37 import org.junit.runner.RunWith
38 import org.junit.runners.MethodSorters
39 import org.junit.runners.Parameterized
40 
41 /**
42  * Test IME window layer will become visible when switching from the fixed orientation activity
43  * (e.g. Launcher activity). To run this test: `atest
44  * FlickerTests:ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest`
45  */
46 @RequiresDevice
47 @RunWith(Parameterized::class)
48 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
49 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
50 open class ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest(flicker: LegacyFlickerTest) :
51     BaseTest(flicker) {
52     private val imeTestApp =
53         ImeShownOnAppStartHelper(instrumentation, flicker.scenario.startRotation)
54 
55     /** {@inheritDoc} */
56     override val transition: FlickerBuilder.() -> Unit = {
57         setup {
58             tapl.setExpectedRotationCheckEnabled(false)
59 
60             // Launch the activity with expecting IME will be shown.
61             imeTestApp.launchViaIntent(wmHelper)
62 
63             // Swiping out the IME activity to home.
64             tapl.goHome()
65             wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify()
66         }
67         transitions {
68             // Bring the existing IME activity to the front in landscape mode device rotation.
69             setRotation(Rotation.ROTATION_90)
70             imeTestApp.launchViaIntent(wmHelper)
71         }
72         teardown { imeTestApp.exit(wmHelper) }
73     }
74 
75     @Presubmit @Test fun imeWindowBecomesVisible() = flicker.imeWindowBecomesVisible()
76 
77     @Presubmit @Test fun imeLayerBecomesVisible() = flicker.imeLayerBecomesVisible()
78 
79     @Presubmit
80     @Test
81     fun snapshotStartingWindowLayerCoversExactlyOnApp() {
82         flicker.snapshotStartingWindowLayerCoversExactlyOnApp(imeTestApp)
83     }
84 
85     @Postsubmit
86     @Test
87     fun imeLayerAlphaOneAfterSnapshotStartingWindowRemoval() {
88         // Check if the snapshot appeared during the trace
89         var imeSnapshotRemovedTimestamp: Timestamp? = null
90 
91         val layerTrace = flicker.reader.readLayersTrace()
92         val layerTraceEntries = layerTrace?.entries?.toList() ?: emptyList()
93 
94         layerTraceEntries.zipWithNext { prev, next ->
95             val prevSnapshotLayerVisible =
96                 ComponentNameMatcher.SNAPSHOT.layerMatchesAnyOf(prev.visibleLayers)
97             val nextSnapshotLayerVisible =
98                 ComponentNameMatcher.SNAPSHOT.layerMatchesAnyOf(next.visibleLayers)
99 
100             if (
101                 imeSnapshotRemovedTimestamp == null &&
102                     (prevSnapshotLayerVisible && !nextSnapshotLayerVisible)
103             ) {
104                 imeSnapshotRemovedTimestamp = next.timestamp
105             }
106         }
107 
108         // if so, make an assertion
109         imeSnapshotRemovedTimestamp?.let { timestamp ->
110             val stateAfterSnapshot =
111                 layerTrace?.getEntryAt(timestamp) ?: error("State not found for $timestamp")
112 
113             val imeLayers =
114                 ComponentNameMatcher.IME.filterLayers(stateAfterSnapshot.visibleLayers.toList())
115 
116             require(imeLayers.isNotEmpty()) { "IME layer not found" }
117             if (imeLayers.any { it.color.a != 1.0f }) {
118                 val errorMsgBuilder =
119                     ExceptionMessageBuilder()
120                         .setTimestamp(timestamp)
121                         .forInvalidProperty("IME layer alpha")
122                         .setExpected("is 1.0")
123                         .setActual("not 1.0")
124                         .addExtraDescription("Filter", ComponentNameMatcher.IME.toLayerIdentifier())
125                 throw InvalidPropertyException(errorMsgBuilder)
126             }
127         }
128     }
129 
130     companion object {
131         /**
132          * Creates the test configurations.
133          *
134          * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
135          * navigation modes.
136          */
137         @Parameterized.Parameters(name = "{0}")
138         @JvmStatic
139         fun getParams() =
140             LegacyFlickerTestFactory.nonRotationTests(
141                 supportedRotations = listOf(Rotation.ROTATION_90)
142             )
143     }
144 }
145