/* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.platform.systemui_tapl.ui.quicksettings import android.platform.systemui_tapl.ui.AlertDialog import android.platform.systemui_tapl.ui.BluetoothDialog import android.platform.systemui_tapl.ui.HearingDevicesDialog import android.platform.systemui_tapl.ui.InternetDialog import android.platform.systemui_tapl.ui.ModesDialog import android.platform.systemui_tapl.utils.DeviceUtils.sysuiResSelector import android.platform.systemui_tapl.utils.SETTINGS_PACKAGE import android.platform.test.scenario.tapl_common.Gestures import android.platform.test.scenario.tapl_common.Gestures.shortClick import android.platform.test.util.HealthTestingUtils.waitForValueCatchingStaleObjectExceptions import android.platform.uiautomatorhelpers.DeviceHelpers.assertVisible import android.platform.uiautomatorhelpers.DeviceHelpers.waitForObj import android.platform.uiautomatorhelpers.WaitUtils.ensureThat import android.view.Display.DEFAULT_DISPLAY import androidx.test.uiautomator.By import androidx.test.uiautomator.BySelector import androidx.test.uiautomator.UiObject2 import com.android.systemui.Flags import com.google.common.truth.Truth.assertWithMessage /** Base class for tiles in Quick Settings and Quick Quick Settings */ sealed class QuickSettingsTileBase(val displayId: Int = DEFAULT_DISPLAY) { protected abstract val tile: UiObject2 /** * Obtain the label of this tile. Will fail if the label is not found or it doesn't have text. */ val tileLabel: String get() { val label = if (Flags.qsUiRefactorComposeFragment()) { tile.contentDescription } else { tile.waitForObj(QuickQuickSettings.tileLabelSelector(displayId)).text } assertWithMessage("Tile label should not be null").that(label).isNotNull() return label } /** Returns whether the tile is checked. */ val isChecked: Boolean get() { ensureThat("tile is clickable") { waitForValueCatchingStaleObjectExceptions({ "Failed to get clickable state for tile." }) { tile.isClickable } } return waitForValueCatchingStaleObjectExceptions({ "Failed to get checked state for tile" }) { tile.isChecked } } /** Clicks a non-Internet tile and verifies that its checked state changes. */ fun click() { val wasChecked = isChecked clickWithoutAssertions() assertCheckedStatus(!wasChecked) } /** * Clicks a non-Internet tile without any assertions about resulting tile state. Please don't * use unless you have a very good reason to omit assertions. */ fun clickWithoutAssertions() { shortClick(tile, "Tile") } fun assertCheckedStatus(checked: Boolean) { val expectedState = if (checked) "checked" else "unchecked" ensureThat("tile is $expectedState") { tile.isChecked == checked } } /** Clicks the Internet tile and presses Done button. */ fun clickInternetTile() { clickWithoutAssertions() val internetDialog = InternetDialog(displayId) internetDialog.clickOnDoneAndClose() } /** Clicks the Internet tile and presses dismisses it. */ fun openHearingDevicesTile(): HearingDevicesDialog { clickWithoutAssertions() return HearingDevicesDialog(displayId) } /** Clicks the Bluetooth tile and opens dialog. */ fun openBluetoothDialog(): BluetoothDialog { clickWithoutAssertions() return BluetoothDialog(displayId) } /** Clicks the Bluetooth tile, opens dialog and presses Done button. */ fun clickBluetoothTile() { val bluetoothDialog = openBluetoothDialog() bluetoothDialog.clickOnDoneAndClose() } fun clickDnDIntoDialog(): AlertDialog { clickWithoutAssertions() return AlertDialog() } fun clickModesTile(): ModesDialog { clickWithoutAssertions() return ModesDialog(displayId) } /** Long-clicks the tile and verifies that Settings app appears, unless otherwise specified */ fun longClick(expectedSettingsPackage: String? = null) { Gestures.longClickDownUp(tile, "Quick settings tile", displayId) { val packageName = expectedSettingsPackage ?: SETTINGS_PACKAGE By.displayId(displayId).pkg(packageName).assertVisible { "$packageName didn't appear" } } } private companion object { val DONE_BTN = sysuiResSelector("done_button") const val DIALOG_RES_ID = "internet_connectivity_dialog" const val SCROLL_VIEW_RES_ID = "scroll_view" const val BLUETOOTH_TILE_DIALOG_RES_ID = "root" } } /** * System UI test automation object representing a Quick Settings tile. * * It keeps track of the tile by its selector, instead of the UiObject2 in case it moves in the * middle of the test. */ class QuickSettingsTile internal constructor(private val selector: BySelector, displayId: Int = DEFAULT_DISPLAY) : QuickSettingsTileBase(displayId) { override val tile: UiObject2 get() = waitForObj(selector) } /** * System UI test automation object representing a Quick Quick Settings tile. * * As these are retrieved by the position, they are associated with the actual object. */ class QuickQuickSettingsTile internal constructor(override val tile: UiObject2, displayId: Int = DEFAULT_DISPLAY) : QuickSettingsTileBase(displayId)