• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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 android.platform.systemui_tapl.ui
18 
19 import android.platform.systemui_tapl.utils.DeviceUtils.sysuiResSelector
20 import android.platform.systemui_tapl.utils.SETTINGS_PACKAGE
21 import android.platform.test.scenario.tapl_common.Gestures
22 import android.platform.test.scenario.tapl_common.Gestures.click
23 import android.platform.test.scenario.tapl_common.TaplUiDevice
24 import android.platform.test.util.HealthTestingUtils.waitForValueCatchingStaleObjectExceptions
25 import android.platform.uiautomatorhelpers.DeviceHelpers.assertInvisible
26 import android.platform.uiautomatorhelpers.DeviceHelpers.assertVisible
27 import android.platform.uiautomatorhelpers.DeviceHelpers.uiDevice
28 import android.platform.uiautomatorhelpers.DeviceHelpers.waitForObj
29 import android.platform.uiautomatorhelpers.WaitResult
30 import android.platform.uiautomatorhelpers.WaitUtils.ensureThat
31 import android.platform.uiautomatorhelpers.WaitUtils.waitToBecomeTrue
32 import android.platform.uiautomatorhelpers.scrollUntilFound
33 import android.util.Log
34 import androidx.test.uiautomator.By
35 import androidx.test.uiautomator.BySelector
36 import androidx.test.uiautomator.UiObject2
37 import com.android.systemui.Flags
38 import com.google.common.truth.Truth.assertWithMessage
39 
40 /** Base class for tiles in Quick Settings and Quick Quick Settings */
41 sealed class QuickSettingsTileBase {
42     protected abstract val tile: UiObject2
43 
44     /**
45      * Obtain the label of this tile. Will fail if the label is not found or it doesn't have text.
46      */
47     val tileLabel: String
48         get() {
49             val label =
50                 if (Flags.qsUiRefactorComposeFragment()) {
51                     tile.contentDescription
52                 } else {
53                     tile.waitForObj(QuickQuickSettings.UI_TILE_LABEL_SELECTOR).text
54                 }
55             assertWithMessage("Tile label should not be null").that(label).isNotNull()
56             return label
57         }
58 
59     /** Returns whether the tile is checked. */
60     val isChecked: Boolean
61         get() {
<lambda>null62             ensureThat("tile is clickable") {
63                 waitForValueCatchingStaleObjectExceptions({
64                     "Failed to get clickable state for tile."
65                 }) {
66                     tile.isClickable
67                 }
68             }
<lambda>null69             return waitForValueCatchingStaleObjectExceptions({
70                 "Failed to get checked state for tile"
71             }) {
72                 tile.isChecked
73             }
74         }
75 
76     /** Clicks a non-Internet tile and verifies that its checked state changes. */
clicknull77     fun click() {
78         val wasChecked = isChecked
79         click(tile, "Tile")
80         assertCheckedStatus(!wasChecked)
81     }
82 
83     /**
84      * Clicks a non-Internet tile without any assertions about resulting tile state. Please don't
85      * use unless you have a very good reason to omit assertions.
86      */
clickWithoutAssertionsnull87     fun clickWithoutAssertions() {
88         click(tile, "Tile")
89     }
90 
assertCheckedStatusnull91     fun assertCheckedStatus(checked: Boolean) {
92         val expectedState = if (checked) "checked" else "unchecked"
93         ensureThat("tile is $expectedState") { tile.isChecked == checked }
94     }
95 
96     /** Clicks the Internet tile and presses Done button. */
clickInternetTilenull97     fun clickInternetTile() {
98         click(tile, "Tile")
99         val scrollView =
100             TaplUiDevice.waitForObject(
101                     sysuiResSelector(DIALOG_RES_ID),
102                     objectName = "Internet connectivity dialog",
103                 )
104                 .waitForChildObject(
105                     childResourceId = SCROLL_VIEW_RES_ID,
106                     childObjectName = "Scroll view",
107                 )
108                 .uiObject
109         val doneButton = scrollView.scrollUntilFound(DONE_BTN) ?: error("Done button not found")
110         doneButton.click()
111         if (waitToBecomeTrue { !uiDevice.hasObject(DONE_BTN) }.result !is WaitResult.WaitSuccess) {
112             Log.d("QuickSettingsTileBase", "Retrying click due to b/339676505")
113             doneButton.click()
114         }
115         DONE_BTN.assertInvisible(errorProvider = { "Internet dialog is dismissed" })
116     }
117 
118     /** Clicks the Bluetooth tile and presses Done button. */
clickBluetoothTilenull119     fun clickBluetoothTile() {
120         click(tile, "Tile")
121         val scrollView =
122             TaplUiDevice.waitForObject(
123                     sysuiResSelector(BLUETOOTH_TILE_DIALOG_RES_ID),
124                     objectName = "Bluetooth tile dialog",
125                 )
126                 .waitForChildObject(
127                     childResourceId = SCROLL_VIEW_RES_ID,
128                     childObjectName = "Scroll view",
129                 )
130                 .uiObject
131         scrollView.scrollUntilFound(DONE_BTN)?.click() ?: error("Done button not found")
132         DONE_BTN.assertInvisible(errorProvider = { "Bluetooth tile dialog is dismissed" })
133     }
134 
clickDnDIntoDialognull135     fun clickDnDIntoDialog(): AlertDialog {
136         click(tile, "Tile")
137         return AlertDialog()
138     }
139 
clickModesTilenull140     fun clickModesTile(): ModesDialog {
141         click(tile, "Tile")
142         return ModesDialog()
143     }
144 
145     /** Long-clicks the tile and verifies that Settings app appears, unless otherwise specified */
longClicknull146     fun longClick(expectedSettingsPackage: String? = null) {
147         Gestures.longClickDownUp(tile, "Quick settings tile") {
148             val packageName = expectedSettingsPackage ?: SETTINGS_PACKAGE
149             By.pkg(packageName).assertVisible { "$packageName didn't appear" }
150         }
151     }
152 
153     private companion object {
154         val DONE_BTN = sysuiResSelector("done_button")
155         const val DIALOG_RES_ID = "internet_connectivity_dialog"
156         const val SCROLL_VIEW_RES_ID = "scroll_view"
157         const val BLUETOOTH_TILE_DIALOG_RES_ID = "root"
158     }
159 }
160 
161 /**
162  * System UI test automation object representing a Quick Settings tile.
163  *
164  * It keeps track of the tile by its selector, instead of the UiObject2 in case it moves in the
165  * middle of the test.
166  */
167 class QuickSettingsTile internal constructor(private val selector: BySelector) :
168     QuickSettingsTileBase() {
169 
170     override val tile: UiObject2
171         get() = waitForObj(selector)
172 }
173 
174 /**
175  * System UI test automation object representing a Quick Quick Settings tile.
176  *
177  * As these are retrieved by the position, they are associated with the actual object.
178  */
179 class QuickQuickSettingsTile internal constructor(override val tile: UiObject2) :
180     QuickSettingsTileBase()
181