1 /*
2  * Copyright (C) 2020 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 @file:JvmName("CommonAssertions")
18 
19 package com.android.wm.shell.flicker.utils
20 
21 import android.graphics.Region
22 import android.tools.Rotation
23 import android.tools.flicker.legacy.LegacyFlickerTest
24 import android.tools.flicker.subject.layers.LayerTraceEntrySubject
25 import android.tools.flicker.subject.layers.LayersTraceSubject
26 import android.tools.helpers.WindowUtils
27 import android.tools.traces.component.IComponentMatcher
28 
LegacyFlickerTestnull29 fun LegacyFlickerTest.appPairsDividerIsVisibleAtEnd() {
30     assertLayersEnd { this.isVisible(APP_PAIR_SPLIT_DIVIDER_COMPONENT) }
31 }
32 
LegacyFlickerTestnull33 fun LegacyFlickerTest.appPairsDividerIsInvisibleAtEnd() {
34     assertLayersEnd { this.notContains(APP_PAIR_SPLIT_DIVIDER_COMPONENT) }
35 }
36 
appPairsDividerBecomesVisiblenull37 fun LegacyFlickerTest.appPairsDividerBecomesVisible() {
38     assertLayers {
39         this.isInvisible(DOCKED_STACK_DIVIDER_COMPONENT)
40             .then()
41             .isVisible(DOCKED_STACK_DIVIDER_COMPONENT)
42     }
43 }
44 
splitScreenEnterednull45 fun LegacyFlickerTest.splitScreenEntered(
46     component1: IComponentMatcher,
47     component2: IComponentMatcher,
48     fromOtherApp: Boolean,
49     appExistAtStart: Boolean = true
50 ) {
51     if (fromOtherApp) {
52         if (appExistAtStart) {
53             appWindowIsInvisibleAtStart(component1)
54         } else {
55             appWindowIsNotContainAtStart(component1)
56         }
57     } else {
58         appWindowIsVisibleAtStart(component1)
59     }
60     if (appExistAtStart) {
61         appWindowIsInvisibleAtStart(component2)
62     } else {
63         appWindowIsNotContainAtStart(component2)
64     }
65     splitScreenDividerIsInvisibleAtStart()
66 
67     appWindowIsVisibleAtEnd(component1)
68     appWindowIsVisibleAtEnd(component2)
69     splitScreenDividerIsVisibleAtEnd()
70 }
71 
splitScreenDismissednull72 fun LegacyFlickerTest.splitScreenDismissed(
73     component1: IComponentMatcher,
74     component2: IComponentMatcher,
75     toHome: Boolean
76 ) {
77     appWindowIsVisibleAtStart(component1)
78     appWindowIsVisibleAtStart(component2)
79     splitScreenDividerIsVisibleAtStart()
80 
81     appWindowIsInvisibleAtEnd(component1)
82     if (toHome) {
83         appWindowIsInvisibleAtEnd(component2)
84     } else {
85         appWindowIsVisibleAtEnd(component2)
86     }
87     splitScreenDividerIsInvisibleAtEnd()
88 }
89 
LegacyFlickerTestnull90 fun LegacyFlickerTest.splitScreenDividerIsVisibleAtStart() {
91     assertLayersStart { this.isVisible(SPLIT_SCREEN_DIVIDER_COMPONENT) }
92 }
93 
LegacyFlickerTestnull94 fun LegacyFlickerTest.splitScreenDividerIsVisibleAtEnd() {
95     assertLayersEnd { this.isVisible(SPLIT_SCREEN_DIVIDER_COMPONENT) }
96 }
97 
splitScreenDividerIsInvisibleAtStartnull98 fun LegacyFlickerTest.splitScreenDividerIsInvisibleAtStart() {
99     assertLayersStart { this.isInvisible(SPLIT_SCREEN_DIVIDER_COMPONENT) }
100 }
101 
splitScreenDividerIsInvisibleAtEndnull102 fun LegacyFlickerTest.splitScreenDividerIsInvisibleAtEnd() {
103     assertLayersEnd { this.isInvisible(SPLIT_SCREEN_DIVIDER_COMPONENT) }
104 }
105 
LegacyFlickerTestnull106 fun LegacyFlickerTest.splitScreenDividerBecomesVisible() {
107     layerBecomesVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
108 }
109 
splitScreenDividerBecomesInvisiblenull110 fun LegacyFlickerTest.splitScreenDividerBecomesInvisible() {
111     assertLayers {
112         this.isVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
113             .then()
114             .isInvisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
115     }
116 }
117 
layerBecomesVisiblenull118 fun LegacyFlickerTest.layerBecomesVisible(component: IComponentMatcher) {
119     assertLayers { this.isInvisible(component).then().isVisible(component) }
120 }
121 
LegacyFlickerTestnull122 fun LegacyFlickerTest.layerBecomesInvisible(component: IComponentMatcher) {
123     assertLayers { this.isVisible(component).then().isInvisible(component) }
124 }
125 
LegacyFlickerTestnull126 fun LegacyFlickerTest.layerIsVisibleAtEnd(component: IComponentMatcher) {
127     assertLayersEnd { this.isVisible(component) }
128 }
129 
LegacyFlickerTestnull130 fun LegacyFlickerTest.layerKeepVisible(component: IComponentMatcher) {
131     assertLayers { this.isVisible(component) }
132 }
133 
LegacyFlickerTestnull134 fun LegacyFlickerTest.splitAppLayerBoundsBecomesVisible(
135     component: IComponentMatcher,
136     landscapePosLeft: Boolean,
137     portraitPosTop: Boolean
138 ) {
139     assertLayers {
140         this.notContains(SPLIT_SCREEN_DIVIDER_COMPONENT.or(component), isOptional = true)
141             .then()
142             .isInvisible(SPLIT_SCREEN_DIVIDER_COMPONENT.or(component))
143             .then()
144             .splitAppLayerBoundsSnapToDivider(
145                 component,
146                 landscapePosLeft,
147                 portraitPosTop,
148                 scenario.endRotation
149             )
150     }
151 }
152 
splitAppLayerBoundsBecomesVisibleByDragnull153 fun LegacyFlickerTest.splitAppLayerBoundsBecomesVisibleByDrag(component: IComponentMatcher) {
154     assertLayers {
155         this.notContains(SPLIT_SCREEN_DIVIDER_COMPONENT.or(component), isOptional = true)
156             .then()
157             .isInvisible(SPLIT_SCREEN_DIVIDER_COMPONENT.or(component))
158             .then()
159             // TODO(b/245472831): Verify the component should snap to divider.
160             .isVisible(component)
161     }
162 }
163 
splitAppLayerBoundsBecomesInvisiblenull164 fun LegacyFlickerTest.splitAppLayerBoundsBecomesInvisible(
165     component: IComponentMatcher,
166     landscapePosLeft: Boolean,
167     portraitPosTop: Boolean
168 ) {
169     assertLayers {
170         this.splitAppLayerBoundsSnapToDivider(
171                 component,
172                 landscapePosLeft,
173                 portraitPosTop,
174                 scenario.endRotation
175             )
176             .then()
177             .isVisible(component, true)
178             .then()
179             .isInvisible(component)
180     }
181 }
182 
splitAppLayerBoundsIsVisibleAtEndnull183 fun LegacyFlickerTest.splitAppLayerBoundsIsVisibleAtEnd(
184     component: IComponentMatcher,
185     landscapePosLeft: Boolean,
186     portraitPosTop: Boolean
187 ) {
188     assertLayersEnd {
189         splitAppLayerBoundsSnapToDivider(
190             component,
191             landscapePosLeft,
192             portraitPosTop,
193             scenario.endRotation
194         )
195     }
196 }
197 
splitAppLayerBoundsKeepVisiblenull198 fun LegacyFlickerTest.splitAppLayerBoundsKeepVisible(
199     component: IComponentMatcher,
200     landscapePosLeft: Boolean,
201     portraitPosTop: Boolean
202 ) {
203     assertLayers {
204         splitAppLayerBoundsSnapToDivider(
205             component,
206             landscapePosLeft,
207             portraitPosTop,
208             scenario.endRotation
209         )
210     }
211 }
212 
splitAppLayerBoundsChangesnull213 fun LegacyFlickerTest.splitAppLayerBoundsChanges(
214     component: IComponentMatcher,
215     landscapePosLeft: Boolean,
216     portraitPosTop: Boolean
217 ) {
218     assertLayers {
219         if (landscapePosLeft) {
220             splitAppLayerBoundsSnapToDivider(
221                 component,
222                 landscapePosLeft,
223                 portraitPosTop,
224                 scenario.endRotation
225             )
226         } else {
227             splitAppLayerBoundsSnapToDivider(
228                     component,
229                     landscapePosLeft,
230                     portraitPosTop,
231                     scenario.endRotation
232                 )
233                 .then()
234                 .isInvisible(component)
235                 .then()
236                 .splitAppLayerBoundsSnapToDivider(
237                     component,
238                     landscapePosLeft,
239                     portraitPosTop,
240                     scenario.endRotation
241                 )
242         }
243     }
244 }
245 
splitAppLayerBoundsSnapToDividernull246 fun LayersTraceSubject.splitAppLayerBoundsSnapToDivider(
247     component: IComponentMatcher,
248     landscapePosLeft: Boolean,
249     portraitPosTop: Boolean,
250     rotation: Rotation
251 ): LayersTraceSubject {
252     return invoke("splitAppLayerBoundsSnapToDivider") {
253         it.splitAppLayerBoundsSnapToDivider(component, landscapePosLeft, portraitPosTop, rotation)
254     }
255 }
256 
LayerTraceEntrySubjectnull257 fun LayerTraceEntrySubject.splitAppLayerBoundsSnapToDivider(
258     component: IComponentMatcher,
259     landscapePosLeft: Boolean,
260     portraitPosTop: Boolean,
261     rotation: Rotation
262 ): LayerTraceEntrySubject {
263     val displayBounds = WindowUtils.getDisplayBounds(rotation)
264     return invoke {
265         val dividerRegion =
266             layer(SPLIT_SCREEN_DIVIDER_COMPONENT)?.visibleRegion?.region?.bounds
267                 ?: error("$SPLIT_SCREEN_DIVIDER_COMPONENT component not found")
268         visibleRegion(component).isNotEmpty()
269         visibleRegion(component)
270             .coversAtMost(
271                 if (displayBounds.width() > displayBounds.height()) {
272                     if (landscapePosLeft) {
273                         Region(
274                             0,
275                             0,
276                             (dividerRegion.left + dividerRegion.right) / 2,
277                             displayBounds.bottom
278                         )
279                     } else {
280                         Region(
281                             (dividerRegion.left + dividerRegion.right) / 2,
282                             0,
283                             displayBounds.right,
284                             displayBounds.bottom
285                         )
286                     }
287                 } else {
288                     if (portraitPosTop) {
289                         Region(
290                             0,
291                             0,
292                             displayBounds.right,
293                             (dividerRegion.top + dividerRegion.bottom) / 2
294                         )
295                     } else {
296                         Region(
297                             0,
298                             (dividerRegion.top + dividerRegion.bottom) / 2,
299                             displayBounds.right,
300                             displayBounds.bottom
301                         )
302                     }
303                 }
304             )
305     }
306 }
307 
appWindowBecomesVisiblenull308 fun LegacyFlickerTest.appWindowBecomesVisible(component: IComponentMatcher) {
309     assertWm {
310         this.isAppWindowInvisible(component)
311             .then()
312             .notContains(component, isOptional = true)
313             .then()
314             .isAppWindowInvisible(component, isOptional = true)
315             .then()
316             .isAppWindowVisible(component)
317     }
318 }
319 
appWindowBecomesInvisiblenull320 fun LegacyFlickerTest.appWindowBecomesInvisible(component: IComponentMatcher) {
321     assertWm { this.isAppWindowVisible(component).then().isAppWindowInvisible(component) }
322 }
323 
LegacyFlickerTestnull324 fun LegacyFlickerTest.appWindowIsVisibleAtStart(component: IComponentMatcher) {
325     assertWmStart { this.isAppWindowVisible(component) }
326 }
327 
LegacyFlickerTestnull328 fun LegacyFlickerTest.appWindowIsVisibleAtEnd(component: IComponentMatcher) {
329     assertWmEnd { this.isAppWindowVisible(component) }
330 }
331 
appWindowIsInvisibleAtStartnull332 fun LegacyFlickerTest.appWindowIsInvisibleAtStart(component: IComponentMatcher) {
333     assertWmStart { this.isAppWindowInvisible(component) }
334 }
335 
appWindowIsInvisibleAtEndnull336 fun LegacyFlickerTest.appWindowIsInvisibleAtEnd(component: IComponentMatcher) {
337     assertWmEnd { this.isAppWindowInvisible(component) }
338 }
339 
LegacyFlickerTestnull340 fun LegacyFlickerTest.appWindowIsNotContainAtStart(component: IComponentMatcher) {
341     assertWmStart { this.notContains(component) }
342 }
343 
appWindowKeepVisiblenull344 fun LegacyFlickerTest.appWindowKeepVisible(component: IComponentMatcher) {
345     assertWm { this.isAppWindowVisible(component) }
346 }
347 
dockedStackDividerIsVisibleAtEndnull348 fun LegacyFlickerTest.dockedStackDividerIsVisibleAtEnd() {
349     assertLayersEnd { this.isVisible(DOCKED_STACK_DIVIDER_COMPONENT) }
350 }
351 
dockedStackDividerBecomesVisiblenull352 fun LegacyFlickerTest.dockedStackDividerBecomesVisible() {
353     assertLayers {
354         this.isInvisible(DOCKED_STACK_DIVIDER_COMPONENT)
355             .then()
356             .isVisible(DOCKED_STACK_DIVIDER_COMPONENT)
357     }
358 }
359 
dockedStackDividerBecomesInvisiblenull360 fun LegacyFlickerTest.dockedStackDividerBecomesInvisible() {
361     assertLayers {
362         this.isVisible(DOCKED_STACK_DIVIDER_COMPONENT)
363             .then()
364             .isInvisible(DOCKED_STACK_DIVIDER_COMPONENT)
365     }
366 }
367 
dockedStackDividerNotExistsAtEndnull368 fun LegacyFlickerTest.dockedStackDividerNotExistsAtEnd() {
369     assertLayersEnd { this.notContains(DOCKED_STACK_DIVIDER_COMPONENT) }
370 }
371 
LegacyFlickerTestnull372 fun LegacyFlickerTest.appPairsPrimaryBoundsIsVisibleAtEnd(
373     rotation: Rotation,
374     primaryComponent: IComponentMatcher
375 ) {
376     assertLayersEnd {
377         val dividerRegion =
378             layer(APP_PAIR_SPLIT_DIVIDER_COMPONENT)?.visibleRegion?.region
379                 ?: error("$APP_PAIR_SPLIT_DIVIDER_COMPONENT component not found")
380         visibleRegion(primaryComponent).overlaps(getPrimaryRegion(dividerRegion, rotation))
381     }
382 }
383 
dockedStackPrimaryBoundsIsVisibleAtEndnull384 fun LegacyFlickerTest.dockedStackPrimaryBoundsIsVisibleAtEnd(
385     rotation: Rotation,
386     primaryComponent: IComponentMatcher
387 ) {
388     assertLayersEnd {
389         val dividerRegion =
390             layer(DOCKED_STACK_DIVIDER_COMPONENT)?.visibleRegion?.region
391                 ?: error("$DOCKED_STACK_DIVIDER_COMPONENT component not found")
392         visibleRegion(primaryComponent).overlaps(getPrimaryRegion(dividerRegion, rotation))
393     }
394 }
395 
appPairsSecondaryBoundsIsVisibleAtEndnull396 fun LegacyFlickerTest.appPairsSecondaryBoundsIsVisibleAtEnd(
397     rotation: Rotation,
398     secondaryComponent: IComponentMatcher
399 ) {
400     assertLayersEnd {
401         val dividerRegion =
402             layer(APP_PAIR_SPLIT_DIVIDER_COMPONENT)?.visibleRegion?.region
403                 ?: error("$APP_PAIR_SPLIT_DIVIDER_COMPONENT component not found")
404         visibleRegion(secondaryComponent).overlaps(getSecondaryRegion(dividerRegion, rotation))
405     }
406 }
407 
LegacyFlickerTestnull408 fun LegacyFlickerTest.dockedStackSecondaryBoundsIsVisibleAtEnd(
409     rotation: Rotation,
410     secondaryComponent: IComponentMatcher
411 ) {
412     assertLayersEnd {
413         val dividerRegion =
414             layer(DOCKED_STACK_DIVIDER_COMPONENT)?.visibleRegion?.region
415                 ?: error("$DOCKED_STACK_DIVIDER_COMPONENT component not found")
416         visibleRegion(secondaryComponent).overlaps(getSecondaryRegion(dividerRegion, rotation))
417     }
418 }
419 
getPrimaryRegionnull420 fun getPrimaryRegion(dividerRegion: Region, rotation: Rotation): Region {
421     val displayBounds = WindowUtils.getDisplayBounds(rotation)
422     return if (rotation.isRotated()) {
423         Region(
424             0,
425             0,
426             dividerRegion.bounds.left + WindowUtils.dockedStackDividerInset,
427             displayBounds.bottom
428         )
429     } else {
430         Region(
431             0,
432             0,
433             displayBounds.right,
434             dividerRegion.bounds.top + WindowUtils.dockedStackDividerInset
435         )
436     }
437 }
438 
getSecondaryRegionnull439 fun getSecondaryRegion(dividerRegion: Region, rotation: Rotation): Region {
440     val displayBounds = WindowUtils.getDisplayBounds(rotation)
441     return if (rotation.isRotated()) {
442         Region(
443             dividerRegion.bounds.right - WindowUtils.dockedStackDividerInset,
444             0,
445             displayBounds.right,
446             displayBounds.bottom
447         )
448     } else {
449         Region(
450             0,
451             dividerRegion.bounds.bottom - WindowUtils.dockedStackDividerInset,
452             displayBounds.right,
453             displayBounds.bottom
454         )
455     }
456 }
457