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 package com.android.server.wm.flicker.helpers
18 
19 import android.app.Instrumentation
20 import android.tools.common.Rotation
21 import android.tools.common.traces.Condition
22 import android.tools.common.traces.DeviceStateDump
23 import android.tools.common.traces.component.ComponentNameMatcher
24 import android.tools.common.traces.component.IComponentMatcher
25 import android.tools.device.helpers.FIND_TIMEOUT
26 import android.tools.device.helpers.IME_PACKAGE
27 import android.tools.device.traces.parsers.WindowManagerStateHelper
28 import android.tools.device.traces.parsers.toFlickerComponent
29 import android.view.WindowInsets.Type.ime
30 import android.view.WindowInsets.Type.navigationBars
31 import android.view.WindowInsets.Type.statusBars
32 import androidx.test.uiautomator.By
33 import androidx.test.uiautomator.Until
34 import com.android.server.wm.flicker.testapp.ActivityOptions
35 import java.util.regex.Pattern
36 
37 class ImeShownOnAppStartHelper
38 @JvmOverloads
39 constructor(
40     instr: Instrumentation,
41     private val rotation: Rotation,
42     private val imePackageName: String = IME_PACKAGE,
43     launcherName: String = ActivityOptions.Ime.AutoFocusActivity.LABEL,
44     component: ComponentNameMatcher =
45         ActivityOptions.Ime.AutoFocusActivity.COMPONENT.toFlickerComponent()
46 ) : ImeAppHelper(instr, launcherName, component) {
47     override fun openIME(wmHelper: WindowManagerStateHelper) {
48         // do nothing (the app is focused automatically)
49         waitIMEShown(wmHelper)
50     }
51 
52     override fun launchViaIntent(
53         wmHelper: WindowManagerStateHelper,
54         launchedAppComponentMatcherOverride: IComponentMatcher?,
55         action: String?,
56         stringExtras: Map<String, String>,
57         waitConditions: Array<Condition<DeviceStateDump>>
58     ) {
59         super.launchViaIntent(
60             wmHelper,
61             launchedAppComponentMatcherOverride,
62             action,
63             stringExtras,
64             waitConditions
65         )
66         waitIMEShown(wmHelper)
67     }
68 
69     override fun open() {
70         val expectedPackage =
71             if (rotation.isRotated()) {
72                 imePackageName
73             } else {
74                 getPackage()
75             }
76         open(expectedPackage)
77     }
78 
79     fun startDialogThemedActivity(wmHelper: WindowManagerStateHelper) {
80         val button =
81             uiDevice.wait(
82                 Until.findObject(By.res(getPackage(), "start_dialog_themed_activity_btn")),
83                 FIND_TIMEOUT
84             )
85 
86         requireNotNull(button) {
87             "Button not found, this usually happens when the device " +
88                 "was left in an unknown state (e.g. Screen turned off)"
89         }
90         button.click()
91         wmHelper
92             .StateSyncBuilder()
93             .withFullScreenApp(ActivityOptions.DialogThemedActivity.COMPONENT.toFlickerComponent())
94             .waitForAndVerify()
95     }
96 
97     fun dismissDialog(wmHelper: WindowManagerStateHelper) {
98         val dialog = uiDevice.wait(Until.findObject(By.text("Dialog for test")), FIND_TIMEOUT)
99 
100         // Pressing back key to dismiss the dialog
101         if (dialog != null) {
102             uiDevice.pressBack()
103             wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify()
104         }
105     }
106 
107     fun getInsetsVisibleFromDialog(type: Int): Boolean {
108         val insetsVisibilityTextView =
109             uiDevice.wait(Until.findObject(By.res("android:id/text1")), FIND_TIMEOUT)
110         if (insetsVisibilityTextView != null) {
111             val visibility = insetsVisibilityTextView.text.toString()
112             val matcher =
113                 when (type) {
114                     ime() -> {
115                         Pattern.compile("IME\\: (VISIBLE|INVISIBLE)").matcher(visibility)
116                     }
117                     statusBars() -> {
118                         Pattern.compile("StatusBar\\: (VISIBLE|INVISIBLE)").matcher(visibility)
119                     }
120                     navigationBars() -> {
121                         Pattern.compile("NavBar\\: (VISIBLE|INVISIBLE)").matcher(visibility)
122                     }
123                     else -> null
124                 }
125             if (matcher != null && matcher.find()) {
126                 return matcher.group(1).equals("VISIBLE")
127             }
128         }
129         return false
130     }
131 
132     fun toggleFixPortraitOrientation(wmHelper: WindowManagerStateHelper) {
133         val button =
134             uiDevice.wait(
135                 Until.findObject(By.res(getPackage(), "toggle_fixed_portrait_btn")),
136                 FIND_TIMEOUT
137             )
138         require(button != null) {
139             "Button not found, this usually happens when the device " +
140                 "was left in an unknown state (e.g. Screen turned off)"
141         }
142         button.click()
143         mInstrumentation.waitForIdleSync()
144         // Ensure app relaunching transition finish and the IME has shown
145         waitIMEShown(wmHelper)
146     }
147 }
148