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