1 /*
<lambda>null2  * 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.wm.shell.flicker.pip
18 
19 import android.platform.test.annotations.FlakyTest
20 import android.platform.test.annotations.Postsubmit
21 import android.platform.test.annotations.Presubmit
22 import android.platform.test.annotations.RequiresDevice
23 import android.platform.test.annotations.RequiresFlagsDisabled
24 import android.tools.flicker.junit.FlickerParametersRunnerFactory
25 import android.tools.flicker.legacy.FlickerBuilder
26 import android.tools.flicker.legacy.LegacyFlickerTest
27 import android.tools.flicker.subject.exceptions.ExceptionMessageBuilder
28 import android.tools.flicker.subject.exceptions.IncorrectRegionException
29 import android.tools.flicker.subject.layers.LayerSubject
30 import com.android.server.wm.flicker.helpers.PipAppHelper
31 import com.android.wm.shell.Flags
32 import com.android.wm.shell.flicker.pip.common.EnterPipTransition
33 import org.junit.Assume
34 import org.junit.FixMethodOrder
35 import org.junit.Test
36 import org.junit.runner.RunWith
37 import org.junit.runners.MethodSorters
38 import org.junit.runners.Parameterized
39 import kotlin.math.abs
40 
41 
42 /**
43  * Test entering pip from an app via auto-enter property when navigating to home.
44  *
45  * To run this test: `atest WMShellFlickerTestsPip:AutoEnterPipOnGoToHomeTest`
46  *
47  * Actions:
48  * ```
49  *     Launch an app in full screen
50  *     Select "Auto-enter PiP" radio button
51  *     Press Home button or swipe up to go Home and put [pipApp] in pip mode
52  * ```
53  *
54  * Notes:
55  * ```
56  *     1. All assertions are inherited from [EnterPipTest]
57  *     2. Part of the test setup occurs automatically via
58  *        [android.tools.flicker.legacy.runner.TransitionRunner],
59  *        including configuring navigation mode, initial orientation and ensuring no
60  *        apps are running before setup
61  * ```
62  */
63 @RequiresDevice
64 @RunWith(Parameterized::class)
65 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
66 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
67 @RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2)
68 open class AutoEnterPipOnGoToHomeTest(flicker: LegacyFlickerTest) : EnterPipTransition(flicker) {
69     override val pipApp: PipAppHelper = PipAppHelper(instrumentation)
70 
71     override val thisTransition: FlickerBuilder.() -> Unit = { transitions { tapl.goHome() } }
72 
73     override val defaultEnterPip: FlickerBuilder.() -> Unit = {
74         setup {
75             pipApp.launchViaIntent(wmHelper)
76             pipApp.enableAutoEnterForPipActivity()
77         }
78     }
79 
80     override val defaultTeardown: FlickerBuilder.() -> Unit = { teardown { pipApp.exit(wmHelper) } }
81 
82     private val widthNotSmallerThan: LayerSubject.(LayerSubject) -> Unit = {
83         val width = visibleRegion.region.bounds.width()
84         val otherWidth = it.visibleRegion.region.bounds.width()
85         if (width < otherWidth && abs(width - otherWidth) > EPSILON) {
86             val errorMsgBuilder =
87                 ExceptionMessageBuilder()
88                     .forSubject(this)
89                     .forIncorrectRegion("width. $width smaller than $otherWidth")
90                     .setExpected(width)
91                     .setActual(otherWidth)
92             throw IncorrectRegionException(errorMsgBuilder)
93         }
94     }
95 
96     @Postsubmit
97     @Test
98     override fun pipLayerReduces() {
99         Assume.assumeFalse(flicker.scenario.isGesturalNavigation)
100         flicker.assertLayers {
101             val pipLayerList = this.layers { pipApp.layerMatchesAnyOf(it) && it.isVisible }
102             pipLayerList.zipWithNext { previous, current ->
103                 current.visibleRegion.notBiggerThan(previous.visibleRegion.region)
104             }
105         }
106     }
107 
108     /** Checks that [pipApp] window's width is first decreasing then increasing. */
109     @Postsubmit
110     @Test
111     fun pipLayerWidthDecreasesThenIncreases() {
112         Assume.assumeTrue(flicker.scenario.isGesturalNavigation)
113         flicker.assertLayers {
114             val pipLayerList = this.layers { pipApp.layerMatchesAnyOf(it) && it.isVisible }
115             var previousLayer = pipLayerList[0]
116             var currentLayer = previousLayer
117             var i = 0
118             invoke("layer area is decreasing") {
119                 if (i < pipLayerList.size - 1) {
120                     previousLayer = currentLayer
121                     currentLayer = pipLayerList[++i]
122                     previousLayer.widthNotSmallerThan(currentLayer)
123                 }
124             }.then().invoke("layer are is increasing", true /* isOptional */) {
125                 if (i < pipLayerList.size - 1) {
126                     previousLayer = currentLayer
127                     currentLayer = pipLayerList[++i]
128                     currentLayer.widthNotSmallerThan(previousLayer)
129                 }
130             }
131         }
132     }
133 
134     /** Checks that [pipApp] window is animated towards default position in right bottom corner */
135     @FlakyTest(bugId = 255578530)
136     @Test
137     fun pipLayerMovesTowardsRightBottomCorner() {
138         // in gestural nav the swipe makes PiP first go upwards
139         Assume.assumeFalse(flicker.scenario.isGesturalNavigation)
140         flicker.assertLayers {
141             val pipLayerList = this.layers { pipApp.layerMatchesAnyOf(it) && it.isVisible }
142             // Pip animates towards the right bottom corner, but because it is being resized at the
143             // same time, it is possible it shrinks first quickly below the default position and get
144             // moved up after that in just few last frames
145             pipLayerList.zipWithNext { previous, current ->
146                 current.visibleRegion.isToTheRightBottom(previous.visibleRegion.region, 3)
147             }
148         }
149     }
150 
151     @Presubmit
152     @Test
153     override fun focusChanges() {
154         // in gestural nav the focus goes to different activity on swipe up
155         Assume.assumeFalse(flicker.scenario.isGesturalNavigation)
156         super.focusChanges()
157     }
158 
159     @FlakyTest(bugId = 289943985)
160     @Test
161     override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
162         super.visibleLayersShownMoreThanOneConsecutiveEntry()
163     }
164 
165     companion object {
166         // TODO(b/363080056): A margin of error allowed on certain layer size calculations.
167         const val EPSILON = 1
168     }
169 }
170