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  */
17 
18 package com.android.systemui.statusbar.policy
19 
20 import android.content.Context
21 import android.content.Intent
22 import android.view.View
23 import com.android.systemui.dagger.SysUISingleton
24 import com.android.systemui.dagger.qualifiers.Application
25 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
26 import com.android.systemui.plugins.ActivityStarter
27 import com.android.systemui.qs.user.UserSwitchDialogController.DialogShower
28 import com.android.systemui.user.data.source.UserRecord
29 import com.android.systemui.user.domain.interactor.GuestUserInteractor
30 import com.android.systemui.user.domain.interactor.UserSwitcherInteractor
31 import com.android.systemui.user.legacyhelper.ui.LegacyUserUiHelper
32 import dagger.Lazy
33 import java.io.PrintWriter
34 import java.lang.ref.WeakReference
35 import javax.inject.Inject
36 
37 /** Access point into multi-user switching logic. */
38 @Deprecated("Use UserInteractor or GuestUserInteractor instead.")
39 @SysUISingleton
40 class UserSwitcherController
41 @Inject
42 constructor(
43     @Application private val applicationContext: Context,
44     private val userSwitcherInteractorLazy: Lazy<UserSwitcherInteractor>,
45     private val guestUserInteractorLazy: Lazy<GuestUserInteractor>,
46     private val keyguardInteractorLazy: Lazy<KeyguardInteractor>,
47     private val activityStarter: ActivityStarter,
48 ) {
49 
50     /** Defines interface for classes that can be called back when the user is switched. */
interfacenull51     fun interface UserSwitchCallback {
52         /** Notifies that the user has switched. */
53         fun onUserSwitched()
54     }
55 
<lambda>null56     private val mUserSwitcherInteractor: UserSwitcherInteractor by lazy {
57         userSwitcherInteractorLazy.get()
58     }
<lambda>null59     private val guestUserInteractor: GuestUserInteractor by lazy { guestUserInteractorLazy.get() }
<lambda>null60     private val keyguardInteractor: KeyguardInteractor by lazy { keyguardInteractorLazy.get() }
61 
62     private val callbackCompatMap =
63         mutableMapOf<UserSwitchCallback, UserSwitcherInteractor.UserCallback>()
64 
65     /** The current list of [UserRecord]. */
66     val users: ArrayList<UserRecord>
67         get() = mUserSwitcherInteractor.userRecords.value
68 
69     /** Whether the user switcher experience should use the simple experience. */
70     val isSimpleUserSwitcher: Boolean
71         get() = mUserSwitcherInteractor.isSimpleUserSwitcher
72 
73     val isUserSwitcherEnabled: Boolean
74         get() = mUserSwitcherInteractor.isUserSwitcherEnabled
75 
76     /** The [UserRecord] of the current user or `null` when none. */
77     val currentUserRecord: UserRecord?
78         get() = mUserSwitcherInteractor.selectedUserRecord.value
79 
80     /** The name of the current user of the device or `null`, when none is selected. */
81     val currentUserName: String?
82         get() =
<lambda>null83             currentUserRecord?.let {
84                 LegacyUserUiHelper.getUserRecordName(
85                     context = applicationContext,
86                     record = it,
87                     isGuestUserAutoCreated = mUserSwitcherInteractor.isGuestUserAutoCreated,
88                     isGuestUserResetting = mUserSwitcherInteractor.isGuestUserResetting,
89                 )
90             }
91 
92     /**
93      * Notifies that a user has been selected.
94      *
95      * This will trigger the right user journeys to create a guest user, switch users, and/or
96      * navigate to the correct destination.
97      *
98      * If a user with the given ID is not found, this method is a no-op.
99      *
100      * @param userId The ID of the user to switch to.
101      * @param dialogShower An optional [DialogShower] in case we need to show dialogs.
102      */
onUserSelectednull103     fun onUserSelected(userId: Int, dialogShower: DialogShower?) {
104         mUserSwitcherInteractor.selectUser(userId, dialogShower)
105     }
106 
107     /** Whether the guest user is configured to always be present on the device. */
108     val isGuestUserAutoCreated: Boolean
109         get() = mUserSwitcherInteractor.isGuestUserAutoCreated
110 
111     /** Whether the guest user is currently being reset. */
112     val isGuestUserResetting: Boolean
113         get() = mUserSwitcherInteractor.isGuestUserResetting
114 
115     /** Registers an adapter to notify when the users change. */
addAdapternull116     fun addAdapter(adapter: WeakReference<BaseUserSwitcherAdapter>) {
117         mUserSwitcherInteractor.addCallback(
118             object : UserSwitcherInteractor.UserCallback {
119                 override fun isEvictable(): Boolean {
120                     return adapter.get() == null
121                 }
122 
123                 override fun onUserStateChanged() {
124                     adapter.get()?.notifyDataSetChanged()
125                 }
126             }
127         )
128     }
129 
130     /** Notifies the item for a user has been clicked. */
onUserListItemClickednull131     fun onUserListItemClicked(
132         record: UserRecord,
133         dialogShower: DialogShower?,
134     ) {
135         mUserSwitcherInteractor.onRecordSelected(record, dialogShower)
136     }
137 
138     /**
139      * Removes guest user and switches to target user. The guest must be the current user and its id
140      * must be `guestUserId`.
141      *
142      * If `targetUserId` is `UserHandle.USER_NULL`, then create a new guest user in the foreground,
143      * and immediately switch to it. This is used for wiping the current guest and replacing it with
144      * a new one.
145      *
146      * If `targetUserId` is specified, then remove the guest in the background while switching to
147      * `targetUserId`.
148      *
149      * If device is configured with `config_guestUserAutoCreated`, then after guest user is removed,
150      * a new one is created in the background. This has no effect if `targetUserId` is
151      * `UserHandle.USER_NULL`.
152      *
153      * @param guestUserId id of the guest user to remove
154      * @param targetUserId id of the user to switch to after guest is removed. If
155      *   `UserHandle.USER_NULL`, then switch immediately to the newly created guest user.
156      */
removeGuestUsernull157     fun removeGuestUser(guestUserId: Int, targetUserId: Int) {
158         mUserSwitcherInteractor.removeGuestUser(
159             guestUserId = guestUserId,
160             targetUserId = targetUserId,
161         )
162     }
163 
164     /**
165      * Exits guest user and switches to previous non-guest user. The guest must be the current user.
166      *
167      * @param guestUserId user id of the guest user to exit
168      * @param targetUserId user id of the guest user to exit, set to UserHandle#USER_NULL when
169      *   target user id is not known
170      * @param forceRemoveGuestOnExit true: remove guest before switching user, false: remove guest
171      *   only if its ephemeral, else keep guest
172      */
exitGuestUsernull173     fun exitGuestUser(guestUserId: Int, targetUserId: Int, forceRemoveGuestOnExit: Boolean) {
174         mUserSwitcherInteractor.exitGuestUser(guestUserId, targetUserId, forceRemoveGuestOnExit)
175     }
176 
177     /**
178      * Guarantee guest is present only if the device is provisioned. Otherwise, create a content
179      * observer to wait until the device is provisioned, then schedule the guest creation.
180      */
schedulePostBootGuestCreationnull181     fun schedulePostBootGuestCreation() {
182         guestUserInteractor.onDeviceBootCompleted()
183     }
184 
185     /** Whether keyguard is showing. */
186     val isKeyguardShowing: Boolean
187         get() = keyguardInteractor.isKeyguardShowing()
188 
189     /** Starts an activity with the given [Intent]. */
startActivitynull190     fun startActivity(intent: Intent) {
191         activityStarter.startActivity(intent, /* dismissShade= */ true)
192     }
193 
194     /**
195      * Refreshes users from UserManager.
196      *
197      * The pictures are only loaded if they have not been loaded yet.
198      */
refreshUsersnull199     fun refreshUsers() {
200         mUserSwitcherInteractor.refreshUsers()
201     }
202 
203     /** Adds a subscriber to when user switches. */
addUserSwitchCallbacknull204     fun addUserSwitchCallback(callback: UserSwitchCallback) {
205         val interactorCallback =
206             object : UserSwitcherInteractor.UserCallback {
207                 override fun onUserStateChanged() {
208                     callback.onUserSwitched()
209                 }
210             }
211         callbackCompatMap[callback] = interactorCallback
212         mUserSwitcherInteractor.addCallback(interactorCallback)
213     }
214 
215     /** Removes a previously-added subscriber. */
removeUserSwitchCallbacknull216     fun removeUserSwitchCallback(callback: UserSwitchCallback) {
217         val interactorCallback = callbackCompatMap.remove(callback)
218         if (interactorCallback != null) {
219             mUserSwitcherInteractor.removeCallback(interactorCallback)
220         }
221     }
222 
dumpnull223     fun dump(pw: PrintWriter, args: Array<out String>) {
224         mUserSwitcherInteractor.dump(pw)
225     }
226 
227     companion object {
228         /** Alpha value to apply to a user view in the user switcher when it's selectable. */
229         private const val ENABLED_ALPHA =
230             LegacyUserUiHelper.USER_SWITCHER_USER_VIEW_SELECTABLE_ALPHA
231 
232         /** Alpha value to apply to a user view in the user switcher when it's not selectable. */
233         private const val DISABLED_ALPHA =
234             LegacyUserUiHelper.USER_SWITCHER_USER_VIEW_NOT_SELECTABLE_ALPHA
235 
236         @JvmStatic
setSelectableAlphanull237         fun setSelectableAlpha(view: View) {
238             view.alpha =
239                 if (view.isEnabled) {
240                     ENABLED_ALPHA
241                 } else {
242                     DISABLED_ALPHA
243                 }
244         }
245     }
246 }
247