• 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.utils
18 
19 import android.app.ActivityManager
20 import android.app.IUserSwitchObserver
21 import android.app.UserSwitchObserver
22 import android.platform.helpers.CommonUtils.println
23 import android.platform.uiautomatorhelpers.DeviceHelpers.assertInvisible
24 import android.platform.uiautomatorhelpers.TracingUtils.trace
25 import android.util.Log
26 import androidx.test.uiautomator.By
27 import androidx.test.uiautomator.StaleObjectException
28 import com.google.common.truth.Truth.assertWithMessage
29 import java.time.Duration
30 import java.util.concurrent.Semaphore
31 import java.util.concurrent.TimeUnit
32 
33 /** DON'T USE FROM TESTS: TAPL user utilities to be used from ui and controller objects */
34 object UserUtils {
35     private val TAG = UserUtils::class.java.simpleName
36     private val UI_RESPONSE_USER_SWITCH_COMPLETE_TIMEOUT = Duration.ofMinutes(1)
37     private val EVENT_USER_SWITCH_COMPLETE_TIMEOUT = Duration.ofMinutes(1)
38     private const val DEBUG = false
39 
40     private val mActivityManager = ActivityManager.getService()
41 
42     /**
43      * String displayed for the "Add guest" item in quick settings. The word "Guest" is shown in
44      * quick settings regardless of whether there is already a guest on the device.
45      */
46     private val sUserSwitchingSelector = By.textStartsWith("Switching to ")
47     private val sUserSwitchedSemaphore = Semaphore(0 /* permits */)
48     private val sUserSwitchedObserver: IUserSwitchObserver =
49         object : UserSwitchObserver() {
onUserSwitchCompletenull50             override fun onUserSwitchComplete(newUserId: Int) {
51                 Log.i(TAG, "userSwitchComplete for $newUserId")
52                 sUserSwitchedSemaphore.release()
53             }
54         }
55 
56     init {
57         if (DEBUG) println("$TAG#registerUserSwitchedObserver")
58         mActivityManager.registerUserSwitchObserver(sUserSwitchedObserver, TAG)
59     }
60 
runThenWaitForUserSwitchCompleteEventnull61     private fun runThenWaitForUserSwitchCompleteEvent(switchUser: Runnable) {
62         trace("switchUserAndWaitForUserSwitchedEvent") {
63             if (DEBUG) println("$TAG#switchUserAndWaitForUserSwitchedEvent")
64             sUserSwitchedSemaphore.drainPermits()
65             switchUser.run()
66             try {
67                 assertWithMessage("User switched event wasn't received")
68                     .that(
69                         sUserSwitchedSemaphore.tryAcquire(
70                             /* permits */ 1,
71                             EVENT_USER_SWITCH_COMPLETE_TIMEOUT.toSeconds(),
72                             TimeUnit.SECONDS,
73                         )
74                     )
75                     .isTrue()
76             } catch (e: InterruptedException) {
77                 throw AssertionError("Interrupted while verifying user switched", e)
78             }
79         }
80     }
81 
waitUntilSwitchingUserDialogIsGonenull82     private fun waitUntilSwitchingUserDialogIsGone() {
83         trace("waitUntilSwitchingUserDialogIsGone") {
84             if (DEBUG) println("$TAG#waitUntilSwitchingUserDialogIsGone")
85             try {
86                 sUserSwitchingSelector.assertInvisible(UI_RESPONSE_USER_SWITCH_COMPLETE_TIMEOUT) {
87                     "Switching user dialog is not gone"
88                 }
89             } catch (e: StaleObjectException) {
90                 // ignore
91             }
92         }
93     }
94 
95     @JvmStatic
runThenWaitUntilSwitchCompletednull96     fun runThenWaitUntilSwitchCompleted(switchUser: Runnable) {
97         trace("switchUserAndWaitUntilSwitchCompleted") {
98             if (DEBUG) println("$TAG#switchUserAndWaitUntilSwitchCompleted")
99             runThenWaitForUserSwitchCompleteEvent(switchUser)
100             waitUntilSwitchingUserDialogIsGone()
101             // There's an incredible amount of jank, etc. after switching users. Wait a long
102             // time.
103             trace("wait a long time for jank to disappear") {
104                 try {
105                     TimeUnit.SECONDS.sleep(EVENT_USER_SWITCH_COMPLETE_TIMEOUT.toSeconds())
106                 } catch (ignored: InterruptedException) {}
107             }
108         }
109     }
110 }
111