1 /*
2 * Copyright (C) 2021 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.permissioncontroller.permissionui.ui.television
18
19 import androidx.test.uiautomator.By
20 import androidx.test.uiautomator.StaleObjectException
21 import androidx.test.uiautomator.UiDevice
22 import androidx.test.uiautomator.UiObject2
23 import androidx.test.uiautomator.Until
24
25 private val SELECTOR_FOCUSED = By.focused(true)
26 private val SELECTOR_RES_ID_PC_DECOR_TITLE =
27 By.res("com.android.permissioncontroller", "decor_title")
28 private val SELECTOR_RES_ID_ANDROID_TITLE = By.res("android", "title")
29
30 private const val WAIT_DELAY = 3_000L
31 private const val RETRIES = 5
32
33 val UiDevice.fragmentDecorTitle: String?
34 get() = wait(Until.findObject(SELECTOR_RES_ID_PC_DECOR_TITLE), WAIT_DELAY)?.text
35
36 val UiDevice.focusedElement: UiObject2
37 get() =
38 wait(Until.findObject(SELECTOR_FOCUSED), WAIT_DELAY) ?: error("Focused item is not found")
39
40 private val UiObject2.titleElement: UiObject2
41 get() =
42 wait(Until.findObject(SELECTOR_RES_ID_ANDROID_TITLE), WAIT_DELAY)
43 ?: error("Could not retrieve title")
44
45 val UiDevice.focusedElementTitle: String?
46 get() {
<lambda>null47 repeat(RETRIES) {
48 try {
49 return focusedElement.titleElement.text
50 } catch (e: StaleObjectException) {}
51 }
52 error("Could not get title text")
53 }
54
<lambda>null55 fun UiDevice.navigateDown() = navigate { pressDPadDown() }
56
<lambda>null57 fun UiDevice.navigateUp() = navigate { pressDPadUp() }
58
59 @Suppress("ControlFlowWithEmptyBody")
UiDevicenull60 fun UiDevice.navigateToTheBottom() {
61 while (navigateDown()) {}
62 }
63
64 @Suppress("ControlFlowWithEmptyBody")
navigateToTheTopnull65 fun UiDevice.navigateToTheTop() {
66 while (navigateUp()) {}
67 }
68
<lambda>null69 fun UiDevice.focusOnElementWithTitle(title: CharSequence): Boolean = checkAllItemsIfNeeded {
70 focusedElementTitle == title
71 }
72
<lambda>null73 fun UiDevice.hasElementWithTitle(title: CharSequence): Boolean = checkAllItemsIfNeeded {
74 hasObject(By.copy(SELECTOR_RES_ID_ANDROID_TITLE).text(title.toString()))
75 }
76
UiDevicenull77 private fun UiDevice.checkAllItemsIfNeeded(predicate: () -> Boolean): Boolean {
78 // Let's do one quick check first, right where we are. If it does not work - we'll do the walk.
79 if (predicate()) return true
80
81 // That didn't work, so we'll go over all the items in the list (if needed) top to bottom, but
82 // let's make sure we start from the very top.
83 navigateToTheTop()
84
85 do {
86 if (predicate()) return true
87 } while (navigateDown())
88
89 return false
90 }
91
navigatenull92 private fun UiDevice.navigate(action: () -> Unit): Boolean {
93 val prevFocusedTitle = focusedElementTitle
94
95 action()
96 waitForIdle()
97
98 return prevFocusedTitle != focusedElementTitle
99 }
100