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