• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 package android.platform.test.scenario.tapl_common
17 
18 import android.os.SystemClock.sleep
19 import android.platform.uiautomatorhelpers.BetterSwipe
20 import android.platform.uiautomatorhelpers.BetterSwipe.Swipe
21 import android.platform.uiautomatorhelpers.WaitUtils.ensureThat
22 import android.provider.Settings
23 import androidx.test.platform.app.InstrumentationRegistry
24 import androidx.test.uiautomator.StaleObjectException
25 import androidx.test.uiautomator.UiObject2
26 import java.time.Duration
27 
28 /**
29  * A collection of gestures for UI objects that implements flake-proof patterns and adds
30  * diagnostics. Don't use these gestures directly from the test, this class should be used only by
31  * TAPL.
32  */
33 object Gestures {
34     private val WAIT_TIME = Duration.ofSeconds(10)
35 
waitForObjectConditionnull36     private fun waitForObjectCondition(
37         objectName: String,
38         conditionName: String,
39         condition: () -> Boolean,
40     ) {
41         ensureThat(
42             condition = condition,
43             description = "UI object '$objectName' becomes $conditionName",
44             timeout = WAIT_TIME,
45         )
46     }
47 
waitForObjectEnablednull48     internal fun waitForObjectEnabled(uiObject: UiObject2, objectName: String) {
49         waitForObjectCondition(objectName, "enabled") { uiObject.isEnabled() }
50     }
51 
waitForObjectClickablenull52     private fun waitForObjectClickable(uiObject: UiObject2, waitReason: String) {
53         waitForObjectCondition(waitReason, "clickable") { uiObject.isClickable() }
54     }
55 
waitForObjectLongClickablenull56     private fun waitForObjectLongClickable(uiObject: UiObject2, waitReason: String) {
57         waitForObjectCondition(waitReason, "long-clickable") { uiObject.isLongClickable() }
58     }
59 
waitForObjectScrollablenull60     internal fun waitForObjectScrollable(uiObject: UiObject2, waitReason: String) {
61         waitForObjectCondition(waitReason, "scrollable") { uiObject.isScrollable() }
62     }
63 
64     /**
65      * Wait for the object to become clickable and enabled, then clicks the object.
66      *
67      * @param [uiObject] The object to click
68      * @param [objectName] Name of the object for diags
69      */
70     @JvmStatic
clicknull71     fun click(uiObject: UiObject2, objectName: String) {
72         try {
73             waitForObjectEnabled(uiObject, objectName)
74             waitForObjectClickable(uiObject, objectName)
75             clickNow(uiObject)
76         } catch (e: StaleObjectException) {
77             throw AssertionError(
78                 "UI object '$objectName' has disappeared from the screen during the click gesture.",
79                 e,
80             )
81         }
82     }
83 
84     /**
85      * Waits for the object to become long-clickable and enabled, then presses the object down.
86      *
87      * @param [uiObject] The object to click
88      * @param [objectName] Name of the object for diags
89      * @param [whileHoldingFn] lambda to call between press and release.
90      */
91     @JvmStatic
longClickDownUpnull92     fun longClickDownUp(
93         uiObject: UiObject2,
94         objectName: String,
95         whileHoldingFn: (Swipe.() -> Unit),
96     ) {
97         try {
98             waitForObjectEnabled(uiObject, objectName)
99             waitForObjectLongClickable(uiObject, objectName)
100             val context = InstrumentationRegistry.getInstrumentation().targetContext
101             BetterSwipe.swipe(uiObject.visibleCenter) {
102 
103                 // press for twice the long press timeout, just to make sure.
104                 val longPressMsec =
105                     Settings.Secure.getInt(context.contentResolver, "long_press_timeout")
106                 sleep(longPressMsec.toLong() * 2)
107                 whileHoldingFn()
108             }
109         } catch (e: StaleObjectException) {
110             throw AssertionError(
111                 "UI object '$objectName' has disappeared from " +
112                     "the screen during the long click gesture.",
113                 e,
114             )
115         }
116     }
117 
118     /**
119      * Click on the ui object right away without waiting for animation.
120      *
121      * [UiObject2.click] would wait for all animations finished before clicking. Not waiting for
122      * animations because in some scenarios there is a playing animations when the click is
123      * attempted.
124      */
clickNownull125     private fun clickNow(uiObject: UiObject2) {
126         BetterSwipe.swipe(uiObject.visibleCenter)
127     }
128 }
129