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.graphics.PointF 20 import android.platform.systemui_tapl.controller.LockscreenController 21 import android.platform.systemui_tapl.ui.CommunalHub.Companion.COMMUNAL_SELECTOR 22 import android.platform.systemui_tapl.utils.DeviceUtils.sysuiResSelector 23 import android.platform.uiautomatorhelpers.BetterSwipe 24 import android.platform.uiautomatorhelpers.DeviceHelpers.assertInvisible 25 import android.platform.uiautomatorhelpers.DeviceHelpers.assertVisible 26 import android.platform.uiautomatorhelpers.DeviceHelpers.betterSwipe 27 import android.platform.uiautomatorhelpers.DeviceHelpers.uiDevice 28 import android.platform.uiautomatorhelpers.DeviceHelpers.waitForObj 29 import android.platform.uiautomatorhelpers.FLING_GESTURE_INTERPOLATOR 30 import androidx.test.uiautomator.By 31 import com.android.launcher3.tapl.LauncherInstrumentation 32 import com.android.launcher3.tapl.Workspace 33 import com.android.systemui.Flags.sceneContainer 34 import com.google.common.truth.Truth.assertWithMessage 35 36 /** System UI test automation object representing the lock screen. */ 37 class LockScreen internal constructor() { 38 init { <lambda>null39 LOCKSCREEN_SELECTOR.assertVisible { "Lockscreen is not visible" } 40 } 41 42 /** 43 * Opens expanded quick settings shade via swipe on the portrait lock screen. When you swipe 44 * from the top area of the screen instead of opening normal notification shade we open expanded 45 * quick settings. This helper methods allows to perform this gesture. The difference from 46 * opening normal shade gesture is that the startY position is higher. It is handled in 47 * [NotificationPanelViewController.shouldQuickSettingsIntercept]. 48 */ openQuickSettingsnull49 fun openQuickSettings(): QuickSettings { 50 val device = uiDevice 51 device.betterSwipe( 52 startX = device.displayWidth / 2, 53 startY = 0, 54 endX = device.displayWidth / 2, 55 endY = device.displayHeight * 2 / 3, 56 interpolator = FLING_GESTURE_INTERPOLATOR, 57 ) 58 return QuickSettings() 59 } 60 61 /** 62 * Returns the lockscreen shade (the one visible without the need to pull it down). Fails if not 63 * visible. 64 */ 65 val notificationShade: LockscreenNotificationShade 66 get() = LockscreenNotificationShade() 67 68 /** Swipes up to the unlocked state. */ swipeUpToUnlocknull69 fun swipeUpToUnlock(): Workspace { 70 swipeUp() 71 LOCKSCREEN_SELECTOR.assertInvisible { "Lockscreen still visible after swiping up." } 72 assertWithMessage("Device is still locked after swiping up") 73 .that(LockscreenController.get().isDeviceLocked) 74 .isFalse() 75 return Root.get().goHomeViaKeycode() 76 } 77 78 /** Uses home key to get to the unlocked state, skipping potentially flaky gesture. */ unlockDirectlynull79 fun unlockDirectly() { 80 uiDevice.pressMenu() 81 LOCKSCREEN_SELECTOR.assertInvisible { "Lockscreen still visible after swiping up." } 82 assertWithMessage("Device is still locked after swiping up") 83 .that(LockscreenController.get().isDeviceLocked) 84 .isFalse() 85 86 // Without this part, the launcher might not be ready when tests start to exercise it. 87 uiDevice.pressHome() 88 val instrumentation = LauncherInstrumentation() 89 instrumentation.setExpectedRotation(uiDevice.displayRotation) 90 instrumentation.waitForLauncherInitialized() 91 } 92 93 /** Swipes left to access the Communal Hub */ swipeLeftToCommunalnull94 fun swipeLeftToCommunal(): CommunalHub { 95 swipeLeft() 96 COMMUNAL_SELECTOR.assertVisible { "Communal Hub is not visible after swiping left" } 97 return CommunalHub() 98 } 99 100 /** 101 * Returns bounds of the lock icon at the bottom of the screen. HSV: 102 * https://hsv.googleplex.com/5632535322165248 103 */ 104 val lockIcon: LockscreenLockIcon 105 get() { <lambda>null106 val lockIcon = waitForObj(LOCK_ICON_SELECTOR) { "Lockscreen lock icon not found" } 107 return LockscreenLockIcon(/* rect= */ lockIcon.visibleBounds) 108 } 109 110 /** 111 * Returns user switcher on the lockscreen. HSV: 112 * https://hsv.googleplex.com/5452172222267392?node=50 113 */ 114 val userSwitcher: LockscreenUserSwitcher 115 get() = LockscreenUserSwitcher() 116 117 /** Returns the lockscreen StatusBar. Fails if not visible. */ 118 val statusBar: LockscreenStatusBar 119 get() = LockscreenStatusBar() 120 121 /** Swipes up to the bouncer. */ swipeUpToBouncernull122 fun swipeUpToBouncer(): Bouncer { 123 swipeUp() 124 return Bouncer(null) 125 } 126 127 /** Returns the bouncer. Fails if the bouncer is not visible. */ getBouncernull128 fun getBouncer(): Bouncer { 129 return Bouncer(null) 130 } 131 swipeUpnull132 private fun swipeUp() { 133 LOCKSCREEN_SELECTOR.assertVisible { "Lockscreen is not visible" } 134 val swipeableArea = waitForObj(SWIPEABLE_AREA) { "Swipeable area not found" } 135 // shift swipe gesture over to left so we don't begin the gesture on the lock icon 136 // this can be removed if b/229696938 gets resolved to allow for swiping on the icon 137 val bounds = swipeableArea.visibleBounds 138 val swipeX = bounds.left + bounds.width() / 4f 139 BetterSwipe.swipe(PointF(swipeX, bounds.bottom - 1f), PointF(swipeX, bounds.top.toFloat())) 140 } 141 swipeLeftnull142 private fun swipeLeft() { 143 LOCKSCREEN_SELECTOR.assertVisible { "Lockscreen is not visible" } 144 val swipeableArea = waitForObj(SWIPEABLE_AREA) { "Swipeable area not found" } 145 val bounds = swipeableArea.visibleBounds 146 val swipeY = bounds.top + bounds.height() / 2f 147 BetterSwipe.swipe( 148 PointF(bounds.right - 1f, swipeY), 149 PointF(bounds.left + bounds.width() / 2f, swipeY), 150 ) 151 } 152 153 companion object { 154 private val LOCK_ICON_SELECTOR = sysuiResSelector("device_entry_icon_view") 155 156 // https://hsv.googleplex.com/5130837462876160?node=117 157 val LOCKSCREEN_SELECTOR = 158 if (sceneContainer()) { 159 By.res("element:lockscreen") 160 } else { 161 162 sysuiResSelector("keyguard_indication_area") 163 } 164 private val SWIPEABLE_AREA = 165 if (com.android.systemui.Flags.sceneContainer()) { 166 sysuiResSelector("shared_notification_container") 167 } else { 168 sysuiResSelector("notification_panel") 169 } 170 } 171 } 172