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.systemui_tapl.ui 17 18 import android.graphics.PointF 19 import android.platform.systemui_tapl.utils.DeviceUtils.sysuiResSelector 20 import android.platform.systemui_tapl.utils.SETTINGS_PACKAGE 21 import android.platform.systemui_tapl.utils.SYSUI_PACKAGE 22 import android.platform.test.scenario.tapl_common.TaplUiDevice 23 import android.platform.test.scenario.tapl_common.TaplUiObject 24 import android.platform.uiautomatorhelpers.BetterSwipe 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.waitForFirstObj 29 import android.platform.uiautomatorhelpers.DeviceHelpers.waitForObj 30 import android.platform.uiautomatorhelpers.scrollUntilFound 31 import androidx.test.uiautomator.By 32 import androidx.test.uiautomator.Direction 33 import androidx.test.uiautomator.UiSelector 34 import java.util.regex.Pattern 35 36 /** System UI test automation object representing quick settings in the notification shade. */ 37 class QuickSettings internal constructor() { 38 // TODO(279061302): Remove TaplUiObject after BetterSwipe has a scroll wrapper. 39 private val pager: TaplUiObject 40 41 private val clazzNamePattern = Pattern.compile("android\\.widget\\.((Switch)|(Button))") 42 43 init { <lambda>null44 UI_QUICK_SETTINGS_CONTAINER_ID.assertVisible { "Quick settings didn't open" } 45 FOOTER_SELECTOR.assertVisible() 46 pager = TaplUiDevice.waitForObject(PAGER_UI_OBJECT_SELECTOR, "QS pager") 47 } 48 49 /** Presses Power button to open the power panel. */ openPowerPanelnull50 fun openPowerPanel(): PowerPanel { 51 waitForObj(sysuiResSelector(POWER_BTN_RES_ID)).click() 52 return PowerPanel() 53 } 54 55 /** Presses Settings button to open Settings. */ openSettingsnull56 fun openSettings() { 57 waitForObj(sysuiResSelector(SETTINGS_BUTTON_RES_ID)).click() 58 By.pkg(SETTINGS_PACKAGE).assertVisible() 59 } 60 61 /** Opens the user selection panel by clicking User Switch button. */ openUserSelectionnull62 fun openUserSelection(): UserSelectionPanel { 63 // Click on the multi user switch icon. http://go/hsv/5465641194618880?node=84 64 waitForObj(sysuiResSelector(MULTI_USER_SWITCH_RES_ID)).click() 65 return UserSelectionPanel() 66 } 67 68 /** Finds a tile by the prefix of its description */ findTilenull69 fun findTile(tileDesc: String): QuickSettingsTile { 70 // Select by title_label https://hsv.googleplex.com/5476758214148096?node=57 71 val titleLabelSelector = sysuiResSelector("tile_label").textStartsWith(tileDesc) 72 val tileSelector = By.clazz(clazzNamePattern).hasDescendant(titleLabelSelector, 3) 73 waitForObj(tileSelector) 74 return QuickSettingsTile(tileSelector) 75 } 76 findComposeTilenull77 fun findComposeTile(tileDesc: String): ComposeQuickSettingsTile { 78 val smallTileSelector = ComposeQuickSettingsTile.smallTileSelector(tileDesc) 79 val largeTileSelector = ComposeQuickSettingsTile.largeTileSelector(tileDesc) 80 val (_, selector) = waitForFirstObj(smallTileSelector, largeTileSelector) 81 return ComposeQuickSettingsTile.createFrom(selector) 82 } 83 84 /** Returns the brightness slider. */ 85 val brightnessSlider: BrightnessSlider 86 get() = BrightnessSlider() 87 88 /** Returns the QS header. */ 89 val header: QSHeader 90 get() = QSHeader() 91 92 /** 93 * Returns the visible UMO, or fails if it's not visible. 94 * 95 * **See:** [HSV](https://hsv.googleplex.com/6702722561605632?node=85) 96 */ 97 val universalMediaObject: UniversalMediaObject 98 get() { 99 val footerTop = waitForObj(QUICK_SETTING_FOOTER_SELECTOR).visibleBounds.top 100 waitForObj(QUICK_SETTINGS_SCROLLVIEW_SELECTOR).scrollUntilFound( 101 UniversalMediaObject.MEDIA_CAROUSEL_SCROLLER, 102 direction = Direction.DOWN, <lambda>null103 ) { 104 val umoBottom = it.visibleBounds.bottom 105 umoBottom - footerTop <= 0 106 } 107 return UniversalMediaObject() 108 } 109 110 /** Swipes up back to QQS or closes shade in case of split shade. */ closenull111 fun close() { 112 swipeUp() 113 UI_QUICK_SETTINGS_CONTAINER_ID.assertInvisible() 114 } 115 swipeLeftnull116 fun swipeLeft() { 117 pager.fling(Direction.LEFT, 0.5f) 118 } 119 swipeUpnull120 private fun swipeUp() { 121 val displayWidth = uiDevice.displayWidth 122 val displayHeight = uiDevice.displayHeight 123 BetterSwipe.swipe( 124 PointF((displayWidth / 2).toFloat(), displayHeight.toFloat() - 1f), 125 PointF((displayWidth / 2).toFloat(), 0f), 126 ) 127 } 128 129 private companion object { 130 val UI_QUICK_SETTINGS_CONTAINER_ID = sysuiResSelector("quick_settings_panel") 131 val FOOTER_SELECTOR = sysuiResSelector("qs_footer_actions") 132 133 // https://hsv.googleplex.com/5291196806070272?node=109 134 const val POWER_BTN_RES_ID = "pm_lite" 135 136 // https://hsv.googleplex.com/5291196806070272?node=108 137 const val SETTINGS_BUTTON_RES_ID = "settings_button_container" 138 139 // http://go/hsv/5465641194618880?node=84 140 const val MULTI_USER_SWITCH_RES_ID = "multi_user_switch" 141 const val PAGER_CLASS_NAME = "androidx.viewpager.widget.ViewPager" 142 const val PAGER_RES_ID = "$SYSUI_PACKAGE:id/qs_pager" 143 val PAGER_SELECTOR = UiSelector().className(PAGER_CLASS_NAME).resourceId(PAGER_RES_ID) 144 const val PAGER_UI_OBJECT_RES_ID = "qs_pager" 145 val PAGER_UI_OBJECT_SELECTOR = sysuiResSelector(PAGER_UI_OBJECT_RES_ID) 146 private val QUICK_SETTINGS_SCROLLVIEW_SELECTOR = sysuiResSelector("expanded_qs_scroll_view") 147 private val QUICK_SETTING_FOOTER_SELECTOR = sysuiResSelector("qs_footer_actions") 148 } 149 } 150