• 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.graphics.Rect
20 import android.platform.systemui_tapl.controller.SysUiFlagController
21 import android.platform.systemui_tapl.controller.SysUiFlagController.SystemUIFlag
22 import android.platform.systemui_tapl.utils.DeviceUtils.SHORT_WAIT
23 import android.platform.systemui_tapl.utils.DeviceUtils.androidResSelector
24 import android.platform.systemui_tapl.utils.DeviceUtils.sysuiResSelector
25 import android.platform.systemui_tapl.utils.UserUtils.runThenWaitUntilSwitchCompleted
26 import android.platform.test.scenario.tapl_common.TaplUiDevice
27 import android.platform.uiautomatorhelpers.DeviceHelpers.assertVisible
28 import android.platform.uiautomatorhelpers.DeviceHelpers.uiDevice
29 import android.platform.uiautomatorhelpers.DeviceHelpers.waitForObj
30 import androidx.test.uiautomator.By
31 import androidx.test.uiautomator.BySelector
32 import androidx.test.uiautomator.Until
33 import java.util.regex.Pattern.compile
34 
35 /**
36  * Panel that shows up from the QS multiuser button or user switcher chip.
37  *
38  * Based on the [FULL_SCREEN_USER_SWITCHER] flag, this can be either:
39  * - full screen: http://go/hsv/5243841595572224
40  * - dialog: http://go/hsv/5008296081620992
41  */
42 class UserSelectionPanel internal constructor() {
43 
44     private val fullscreen: Boolean = SystemUIFlag.FULL_SCREEN_USER_SWITCHER.isEnabled
45 
46     init {
<lambda>null47         userSwitcherSelector().assertVisible { "UserSelectionPanel didn't appear" }
48     }
49 
50     /** The number of active users on the current panel. Experimental. */
51     val usersCount: Int
52         get() {
53             return uiDevice.wait(Until.findObjects(userSelector()), SHORT_WAIT.toMillis()).size
54         }
55 
56     /**
57      * The visible bound of the user container. It's mainly for screenshot testing. Experimental.
58      */
59     val userContainerRect: Rect?
60         get() {
61             if (fullscreen) {
62                 return uiDevice
63                     .waitForObj(sysuiResSelector(FULLSCREEN_USER_CONTAINER_ID))
64                     .waitForObj(sysuiResSelector("flow"))
65                     .visibleBounds
66             }
67             throw NotImplementedError("userContainerRect isn't supported on the current device.")
68         }
69 
70     /** Closes user selection. */
closenull71     fun close() {
72         TaplUiDevice.waitForObject(closeSelector(), "Close button").click()
73     }
74 
75     /** Opens user settings by clicking the User Settings button. */
openUserSettingsnull76     fun openUserSettings(): MultipleUsersSettings {
77         if (fullscreen) {
78             clickButtonFromAddMenu(MANAGE_USERS_BUTTON_LABEL)
79         } else {
80             // http://go/hsv/5905004487507968?node=28
81             val userSettingsButton = androidResSelector("button3").text("Manage users")
82             TaplUiDevice.waitForObject(userSettingsButton, "User settings button").click()
83         }
84         return MultipleUsersSettings()
85     }
86 
87     /**
88      * Unless guest user is initialized in some other way, on every UserSelection type we have
89      * creating always means selecting guest user.
90      */
createAndSwitchToGuestUsernull91     fun createAndSwitchToGuestUser() {
92         runThenWaitUntilSwitchCompleted {
93             if (fullscreen) {
94                 clickButtonFromAddMenu(ADD_GUEST_BUTTON_LABEL)
95             } else {
96                 selectUser(GUEST_NAME)
97             }
98         }
99     }
100 
101     /** Opens add user prompt. */
openAddUserPromptnull102     fun openAddUserPrompt(): AddUserPrompt {
103         if (fullscreen) {
104             clickButtonFromAddMenu(ADD_USER_BUTTON_LABEL)
105         } else {
106             selectUser(ADD_USER_BUTTON_LABEL)
107         }
108         return AddUserPrompt()
109     }
110 
111     /** Selects switching back to an already added guest user. */
switchBackToGuestnull112     fun switchBackToGuest(): WelcomeBackGuestDialog {
113         runThenWaitUntilSwitchCompleted { selectUser(GUEST_NAME) }
114         return WelcomeBackGuestDialog()
115     }
116 
117     /** Selects switching to an existing user or a new guest user. */
switchToUsernull118     fun switchToUser(userName: String) {
119         runThenWaitUntilSwitchCompleted { selectUser(userName) }
120     }
121 
122     /**
123      * Selects an entry from the "Add" menu, available only in fullscreen.
124      *
125      * https://hsv.googleplex.com/5243841595572224?node=10
126      */
clickButtonFromAddMenunull127     private fun clickButtonFromAddMenu(label: String) {
128         fun clickButtonWithText(label: String) {
129             // TODO(b/260815442): The clickable attribute of these items in the menu list is false.
130             waitForObj(By.text(label)).click()
131         }
132         clickButtonWithText("Add")
133         clickButtonWithText(label)
134     }
135 
136     /** Selects the user with [userName]. */
selectUsernull137     private fun selectUser(userName: String) {
138         val userItemSelector: BySelector =
139             if (fullscreen) By.clazz("android.view.ViewGroup") else sysuiResSelector("user_item")
140 
141         waitForObj(userItemSelector.hasDescendant(userSelector().text(userName))).click()
142     }
143 
144     /** Selects exiting the guest user. */
exitGuestnull145     fun exitGuest(): ExitGuestPrompt {
146         selectUser(EXIT_GUEST_ITEM)
147         return ExitGuestPrompt()
148     }
149 
userSwitcherSelectornull150     private fun userSwitcherSelector(): BySelector =
151         if (fullscreen) {
152             sysuiResSelector("user_switcher_root")
153         } else {
154             androidResSelector("alertTitle").text("Select user")
155         }
156 
closeSelectornull157     private fun closeSelector(): BySelector =
158         if (fullscreen) {
159             // http://go/hsv/5243841595572224?node=9
160             sysuiResSelector(FULLSCREEN_CANCEL_ID)
161         } else {
162             // http://go/hsv/5905004487507968?node=29
163             androidResSelector("button1").text(compile("Close|Done"))
164         }
165 
166     // http://go/hsv/5008296081620992?node=10#
userSelectornull167     private fun userSelector(): BySelector =
168         sysuiResSelector(if (fullscreen) "user_switcher_text" else "user_name")
169 
170     companion object {
171         private const val GUEST_NAME = "Guest"
172         private const val MANAGE_USERS_BUTTON_LABEL = "Manage users"
173         private const val ADD_GUEST_BUTTON_LABEL = "Add guest"
174         private const val ADD_USER_BUTTON_LABEL = "Add user"
175         private const val FULLSCREEN_CANCEL_ID = "cancel"
176         private const val EXIT_GUEST_ITEM = "Exit guest"
177         private const val FULLSCREEN_USER_CONTAINER_ID = "user_switcher_grid_container"
178     }
179 
180     private val SystemUIFlag.isEnabled: Boolean
181         get() = SysUiFlagController.get().isEnabled(this)
182 }
183