Prepares UserSwitcherController.
UserSwitcherActivity refactor: CL 1/7 - Extracts some logic out of UserSwitcherController and into LegacyUserUiHelper. This logic will later be used by classes in the modern architecture refactor of UserSwitcherActivity. The code is being moved to a common place to avoid code duplication. - Exposes some new APIs in UserSwitcherController to facilitate user selection, expose guest-specific and lock-screen specific configuration, and trigger dialog-based user journeys such as adding a user Bug: 243844359 Test: Existing unit tests still pass. Manually verified in CL 7/7. Change-Id: Iab77acb20781b291289a59389db7b542fdfe0a47
This commit is contained in:
@@ -86,6 +86,7 @@ import com.android.systemui.statusbar.phone.SystemUIDialog;
|
||||
import com.android.systemui.telephony.TelephonyListenerManager;
|
||||
import com.android.systemui.user.CreateUserActivity;
|
||||
import com.android.systemui.user.data.source.UserRecord;
|
||||
import com.android.systemui.user.legacyhelper.ui.LegacyUserUiHelper;
|
||||
import com.android.systemui.util.settings.GlobalSettings;
|
||||
import com.android.systemui.util.settings.SecureSettings;
|
||||
|
||||
@@ -100,14 +101,20 @@ import java.util.function.Consumer;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import kotlinx.coroutines.flow.Flow;
|
||||
import kotlinx.coroutines.flow.MutableStateFlow;
|
||||
import kotlinx.coroutines.flow.StateFlowKt;
|
||||
|
||||
/**
|
||||
* Keeps a list of all users on the device for user switching.
|
||||
*/
|
||||
@SysUISingleton
|
||||
public class UserSwitcherController implements Dumpable {
|
||||
|
||||
public static final float USER_SWITCH_ENABLED_ALPHA = 1.0f;
|
||||
public static final float USER_SWITCH_DISABLED_ALPHA = 0.38f;
|
||||
public static final float USER_SWITCH_ENABLED_ALPHA =
|
||||
LegacyUserUiHelper.USER_SWITCHER_USER_VIEW_SELECTABLE_ALPHA;
|
||||
public static final float USER_SWITCH_DISABLED_ALPHA =
|
||||
LegacyUserUiHelper.USER_SWITCHER_USER_VIEW_NOT_SELECTABLE_ALPHA;
|
||||
|
||||
private static final String TAG = "UserSwitcherController";
|
||||
private static final boolean DEBUG = false;
|
||||
@@ -155,7 +162,8 @@ public class UserSwitcherController implements Dumpable {
|
||||
private boolean mSimpleUserSwitcher;
|
||||
// When false, there won't be any visual affordance to add a new user from the keyguard even if
|
||||
// the user is unlocked
|
||||
private boolean mAddUsersFromLockScreen;
|
||||
private final MutableStateFlow<Boolean> mAddUsersFromLockScreen =
|
||||
StateFlowKt.MutableStateFlow(false);
|
||||
private boolean mUserSwitcherEnabled;
|
||||
@VisibleForTesting
|
||||
boolean mPauseRefreshUsers;
|
||||
@@ -258,8 +266,11 @@ public class UserSwitcherController implements Dumpable {
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
mSimpleUserSwitcher = shouldUseSimpleUserSwitcher();
|
||||
mAddUsersFromLockScreen = mGlobalSettings.getIntForUser(
|
||||
Settings.Global.ADD_USERS_WHEN_LOCKED, 0, UserHandle.USER_SYSTEM) != 0;
|
||||
mAddUsersFromLockScreen.setValue(
|
||||
mGlobalSettings.getIntForUser(
|
||||
Settings.Global.ADD_USERS_WHEN_LOCKED,
|
||||
0,
|
||||
UserHandle.USER_SYSTEM) != 0);
|
||||
mUserSwitcherEnabled = mGlobalSettings.getIntForUser(
|
||||
Settings.Global.USER_SWITCHER_ENABLED, 0, UserHandle.USER_SYSTEM) != 0;
|
||||
refreshUsers(UserHandle.USER_NULL);
|
||||
@@ -323,7 +334,6 @@ public class UserSwitcherController implements Dumpable {
|
||||
}
|
||||
mForcePictureLoadForUserId.clear();
|
||||
|
||||
final boolean addUsersWhenLocked = mAddUsersFromLockScreen;
|
||||
mBgExecutor.execute(() -> {
|
||||
List<UserInfo> infos = mUserManager.getAliveUsers();
|
||||
if (infos == null) {
|
||||
@@ -434,7 +444,7 @@ public class UserSwitcherController implements Dumpable {
|
||||
}
|
||||
|
||||
boolean anyoneCanCreateUsers() {
|
||||
return systemCanCreateUsers() && mAddUsersFromLockScreen;
|
||||
return systemCanCreateUsers() && mAddUsersFromLockScreen.getValue();
|
||||
}
|
||||
|
||||
boolean canCreateGuest(boolean hasExistingGuest) {
|
||||
@@ -450,7 +460,7 @@ public class UserSwitcherController implements Dumpable {
|
||||
}
|
||||
|
||||
boolean createIsRestricted() {
|
||||
return !mAddUsersFromLockScreen;
|
||||
return !mAddUsersFromLockScreen.getValue();
|
||||
}
|
||||
|
||||
boolean canCreateSupervisedUser() {
|
||||
@@ -516,17 +526,48 @@ public class UserSwitcherController implements Dumpable {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies that a user has been selected.
|
||||
*
|
||||
* <p>This will trigger the right user journeys to create a guest user, switch users, and/or
|
||||
* navigate to the correct destination.
|
||||
*
|
||||
* <p>If a user with the given ID is not found, this method is a no-op.
|
||||
*
|
||||
* @param userId The ID of the user to switch to.
|
||||
* @param dialogShower An optional {@link DialogShower} in case we need to show dialogs.
|
||||
*/
|
||||
public void onUserSelected(int userId, @Nullable DialogShower dialogShower) {
|
||||
UserRecord userRecord = mUsers.stream()
|
||||
.filter(x -> x.resolveId() == userId)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (userRecord == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
onUserListItemClicked(userRecord, dialogShower);
|
||||
}
|
||||
|
||||
/** Whether it is allowed to add users while the device is locked. */
|
||||
public Flow<Boolean> getAddUsersFromLockScreen() {
|
||||
return mAddUsersFromLockScreen;
|
||||
}
|
||||
|
||||
/** Returns {@code true} if the guest user is configured to always be present on the device. */
|
||||
public boolean isGuestUserAutoCreated() {
|
||||
return mGuestUserAutoCreated;
|
||||
}
|
||||
|
||||
/** Returns {@code true} if the guest user is currently being reset. */
|
||||
public boolean isGuestUserResetting() {
|
||||
return mGuestIsResetting.get();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void onUserListItemClicked(UserRecord record, DialogShower dialogShower) {
|
||||
if (record.isGuest && record.info == null) {
|
||||
// No guest user. Create one.
|
||||
createGuestAsync(guestId -> {
|
||||
// guestId may be USER_NULL if we haven't reloaded the user list yet.
|
||||
if (guestId != UserHandle.USER_NULL) {
|
||||
mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_ADD);
|
||||
onUserListItemClicked(guestId, record, dialogShower);
|
||||
}
|
||||
});
|
||||
createAndSwitchToGuestUser(dialogShower);
|
||||
} else if (record.isAddUser) {
|
||||
showAddUserDialog(dialogShower);
|
||||
} else if (record.isAddSupervisedUser) {
|
||||
@@ -604,7 +645,23 @@ public class UserSwitcherController implements Dumpable {
|
||||
}
|
||||
}
|
||||
|
||||
private void showAddUserDialog(DialogShower dialogShower) {
|
||||
/**
|
||||
* Creates and switches to the guest user.
|
||||
*/
|
||||
public void createAndSwitchToGuestUser(@Nullable DialogShower dialogShower) {
|
||||
createGuestAsync(guestId -> {
|
||||
// guestId may be USER_NULL if we haven't reloaded the user list yet.
|
||||
if (guestId != UserHandle.USER_NULL) {
|
||||
mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_ADD);
|
||||
onUserListItemClicked(guestId, UserRecord.createForGuest(), dialogShower);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the add user dialog.
|
||||
*/
|
||||
public void showAddUserDialog(@Nullable DialogShower dialogShower) {
|
||||
if (mAddUserDialog != null && mAddUserDialog.isShowing()) {
|
||||
mAddUserDialog.cancel();
|
||||
}
|
||||
@@ -620,7 +677,10 @@ public class UserSwitcherController implements Dumpable {
|
||||
}
|
||||
}
|
||||
|
||||
private void startSupervisedUserActivity() {
|
||||
/**
|
||||
* Starts an activity to add a supervised user to the device.
|
||||
*/
|
||||
public void startSupervisedUserActivity() {
|
||||
final Intent intent = new Intent()
|
||||
.setAction(UserManager.ACTION_CREATE_SUPERVISED_USER)
|
||||
.setPackage(mCreateSupervisedUserPackage)
|
||||
@@ -772,7 +832,7 @@ public class UserSwitcherController implements Dumpable {
|
||||
* Removes guest user and switches to target user. The guest must be the current user and its id
|
||||
* must be {@code guestUserId}.
|
||||
*
|
||||
* <p>If {@code targetUserId} is {@link UserHandle.USER_NULL}, then create a new guest user in
|
||||
* <p>If {@code targetUserId} is {@link UserHandle#USER_NULL}, then create a new guest user in
|
||||
* the foreground, and immediately switch to it. This is used for wiping the current guest and
|
||||
* replacing it with a new one.
|
||||
*
|
||||
@@ -782,11 +842,11 @@ public class UserSwitcherController implements Dumpable {
|
||||
* <p>If device is configured with {@link
|
||||
* com.android.internal.R.bool.config_guestUserAutoCreated}, then after guest user is removed, a
|
||||
* new one is created in the background. This has no effect if {@code targetUserId} is {@link
|
||||
* UserHandle.USER_NULL}.
|
||||
* UserHandle#USER_NULL}.
|
||||
*
|
||||
* @param guestUserId id of the guest user to remove
|
||||
* @param targetUserId id of the user to switch to after guest is removed. If {@link
|
||||
* UserHandle.USER_NULL}, then switch immediately to the newly created guest user.
|
||||
* UserHandle#USER_NULL}, then switch immediately to the newly created guest user.
|
||||
*/
|
||||
public void removeGuestUser(@UserIdInt int guestUserId, @UserIdInt int targetUserId) {
|
||||
UserInfo currentUser = mUserTracker.getUserInfo();
|
||||
@@ -839,7 +899,7 @@ public class UserSwitcherController implements Dumpable {
|
||||
* user.
|
||||
*
|
||||
* @param guestUserId user id of the guest user to exit
|
||||
* @param targetUserId user id of the guest user to exit, set to UserHandle.USER_NULL when
|
||||
* @param targetUserId user id of the guest user to exit, set to UserHandle#USER_NULL when
|
||||
* target user id is not known
|
||||
* @param forceRemoveGuestOnExit true: remove guest before switching user,
|
||||
* false: remove guest only if its ephemeral, else keep guest
|
||||
@@ -952,7 +1012,7 @@ public class UserSwitcherController implements Dumpable {
|
||||
* {@link UserManager} to create a new one.
|
||||
*
|
||||
* @return The multi-user user ID of the newly created guest user, or
|
||||
* {@link UserHandle.USER_NULL} if the guest couldn't be created.
|
||||
* {@link UserHandle#USER_NULL} if the guest couldn't be created.
|
||||
*/
|
||||
public @UserIdInt int createGuest() {
|
||||
UserInfo guest;
|
||||
@@ -1062,38 +1122,11 @@ public class UserSwitcherController implements Dumpable {
|
||||
}
|
||||
|
||||
public String getName(Context context, UserRecord item) {
|
||||
if (item.isGuest) {
|
||||
if (item.isCurrent) {
|
||||
return context.getString(
|
||||
com.android.settingslib.R.string.guest_exit_quick_settings_button);
|
||||
} else {
|
||||
if (item.info != null) {
|
||||
return context.getString(com.android.internal.R.string.guest_name);
|
||||
} else {
|
||||
if (mController.mGuestUserAutoCreated) {
|
||||
// If mGuestIsResetting=true, we expect the guest user to be created
|
||||
// shortly, so display a "Resetting guest..." as an indicator that we
|
||||
// are busy. Otherwise, if mGuestIsResetting=false, we probably failed
|
||||
// to create a guest at some point. In this case, always show guest
|
||||
// nickname instead of "Add guest" to make it seem as though the device
|
||||
// always has a guest ready for use.
|
||||
return context.getString(
|
||||
mController.mGuestIsResetting.get()
|
||||
? com.android.settingslib.R.string.guest_resetting
|
||||
: com.android.internal.R.string.guest_name);
|
||||
} else {
|
||||
// we always show "guest" as string, instead of "add guest"
|
||||
return context.getString(com.android.internal.R.string.guest_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (item.isAddUser) {
|
||||
return context.getString(com.android.settingslib.R.string.user_add_user);
|
||||
} else if (item.isAddSupervisedUser) {
|
||||
return context.getString(R.string.add_user_supervised);
|
||||
} else {
|
||||
return item.info.name;
|
||||
}
|
||||
return LegacyUserUiHelper.getUserRecordName(
|
||||
context,
|
||||
item,
|
||||
mController.isGuestUserAutoCreated(),
|
||||
mController.isGuestUserResetting());
|
||||
}
|
||||
|
||||
protected static ColorFilter getDisabledUserAvatarColorFilter() {
|
||||
@@ -1103,17 +1136,8 @@ public class UserSwitcherController implements Dumpable {
|
||||
}
|
||||
|
||||
protected static Drawable getIconDrawable(Context context, UserRecord item) {
|
||||
int iconRes;
|
||||
if (item.isAddUser) {
|
||||
iconRes = R.drawable.ic_add;
|
||||
} else if (item.isGuest) {
|
||||
iconRes = R.drawable.ic_account_circle;
|
||||
} else if (item.isAddSupervisedUser) {
|
||||
iconRes = R.drawable.ic_add_supervised_user;
|
||||
} else {
|
||||
iconRes = R.drawable.ic_avatar_user;
|
||||
}
|
||||
|
||||
int iconRes = LegacyUserUiHelper.getUserSwitcherActionIconResourceId(
|
||||
item.isAddUser, item.isGuest, item.isAddSupervisedUser);
|
||||
return context.getDrawable(iconRes);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,28 +26,31 @@ import android.os.UserHandle
|
||||
data class UserRecord(
|
||||
/** Relevant user information. If `null`, this record is not a user but an option item. */
|
||||
@JvmField
|
||||
val info: UserInfo?,
|
||||
val info: UserInfo? = null,
|
||||
/** An image representing the user. */
|
||||
@JvmField
|
||||
val picture: Bitmap?,
|
||||
val picture: Bitmap? = null,
|
||||
/** Whether this record represents an option to switch to a guest user. */
|
||||
@JvmField
|
||||
val isGuest: Boolean,
|
||||
val isGuest: Boolean = false,
|
||||
/** Whether this record represents the currently-selected user. */
|
||||
@JvmField
|
||||
val isCurrent: Boolean,
|
||||
val isCurrent: Boolean = false,
|
||||
/** Whether this record represents an option to add another user to the device. */
|
||||
@JvmField
|
||||
val isAddUser: Boolean,
|
||||
/** If true, the record is only visible to the owner and only when unlocked. */
|
||||
val isAddUser: Boolean = false,
|
||||
/**
|
||||
* If true, the record is only available if unlocked or if the user has granted permission to
|
||||
* access this user action whilst on the device is locked.
|
||||
*/
|
||||
@JvmField
|
||||
val isRestricted: Boolean,
|
||||
val isRestricted: Boolean = false,
|
||||
/** Whether it is possible to switch to this user. */
|
||||
@JvmField
|
||||
val isSwitchToEnabled: Boolean,
|
||||
val isSwitchToEnabled: Boolean = false,
|
||||
/** Whether this record represents an option to add another supervised user to the device. */
|
||||
@JvmField
|
||||
val isAddSupervisedUser: Boolean,
|
||||
val isAddSupervisedUser: Boolean = false,
|
||||
) {
|
||||
/**
|
||||
* Returns a new instance of [UserRecord] with its [isCurrent] set to the given value.
|
||||
@@ -67,4 +70,11 @@ data class UserRecord(
|
||||
info.id
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun createForGuest(): UserRecord {
|
||||
return UserRecord(isGuest = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.android.systemui.user.legacyhelper.ui
|
||||
|
||||
import android.content.Context
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.user.data.source.UserRecord
|
||||
import kotlin.math.ceil
|
||||
|
||||
/**
|
||||
* Defines utility functions for helping with legacy UI code for users.
|
||||
*
|
||||
* We need these to avoid code duplication between logic inside the UserSwitcherController and in
|
||||
* modern architecture classes such as repositories, interactors, and view-models. If we ever
|
||||
* simplify UserSwitcherController (or delete it), the code here could be moved into its call-sites.
|
||||
*/
|
||||
object LegacyUserUiHelper {
|
||||
|
||||
/** Returns the maximum number of columns for user items in the user switcher. */
|
||||
fun getMaxUserSwitcherItemColumns(userCount: Int): Int {
|
||||
// TODO(b/243844097): remove this once we remove the old user switcher implementation.
|
||||
return if (userCount < 5) {
|
||||
4
|
||||
} else {
|
||||
ceil(userCount / 2.0).toInt()
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@DrawableRes
|
||||
fun getUserSwitcherActionIconResourceId(
|
||||
isAddUser: Boolean,
|
||||
isGuest: Boolean,
|
||||
isAddSupervisedUser: Boolean,
|
||||
): Int {
|
||||
return if (isAddUser) {
|
||||
R.drawable.ic_add
|
||||
} else if (isGuest) {
|
||||
R.drawable.ic_account_circle
|
||||
} else if (isAddSupervisedUser) {
|
||||
R.drawable.ic_add_supervised_user
|
||||
} else {
|
||||
R.drawable.ic_avatar_user
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getUserRecordName(
|
||||
context: Context,
|
||||
record: UserRecord,
|
||||
isGuestUserAutoCreated: Boolean,
|
||||
isGuestUserResetting: Boolean,
|
||||
): String {
|
||||
val resourceId: Int? = getGuestUserRecordNameResourceId(record)
|
||||
return when {
|
||||
resourceId != null -> context.getString(resourceId)
|
||||
record.info != null -> record.info.name
|
||||
else ->
|
||||
context.getString(
|
||||
getUserSwitcherActionTextResourceId(
|
||||
isGuest = record.isGuest,
|
||||
isGuestUserAutoCreated = isGuestUserAutoCreated,
|
||||
isGuestUserResetting = isGuestUserResetting,
|
||||
isAddUser = record.isAddUser,
|
||||
isAddSupervisedUser = record.isAddSupervisedUser,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the resource ID for a string for the name of the guest user.
|
||||
*
|
||||
* If the given record is not the guest user, returns `null`.
|
||||
*/
|
||||
@StringRes
|
||||
fun getGuestUserRecordNameResourceId(record: UserRecord): Int? {
|
||||
return when {
|
||||
record.isGuest && record.isCurrent ->
|
||||
com.android.settingslib.R.string.guest_exit_quick_settings_button
|
||||
record.isGuest && record.info != null -> com.android.internal.R.string.guest_name
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@StringRes
|
||||
fun getUserSwitcherActionTextResourceId(
|
||||
isGuest: Boolean,
|
||||
isGuestUserAutoCreated: Boolean,
|
||||
isGuestUserResetting: Boolean,
|
||||
isAddUser: Boolean,
|
||||
isAddSupervisedUser: Boolean,
|
||||
): Int {
|
||||
check(isGuest || isAddUser || isAddSupervisedUser)
|
||||
|
||||
return when {
|
||||
isGuest && isGuestUserAutoCreated && isGuestUserResetting ->
|
||||
com.android.settingslib.R.string.guest_resetting
|
||||
isGuest && isGuestUserAutoCreated -> com.android.internal.R.string.guest_name
|
||||
isGuest -> com.android.internal.R.string.guest_name
|
||||
isAddUser -> com.android.settingslib.R.string.user_add_user
|
||||
isAddSupervisedUser -> R.string.add_user_supervised
|
||||
else -> error("This should never happen!")
|
||||
}
|
||||
}
|
||||
|
||||
/** Alpha value to apply to a user view in the user switcher when it's selectable. */
|
||||
const val USER_SWITCHER_USER_VIEW_SELECTABLE_ALPHA = 1.0f
|
||||
|
||||
/** Alpha value to apply to a user view in the user switcher when it's not selectable. */
|
||||
const val USER_SWITCHER_USER_VIEW_NOT_SELECTABLE_ALPHA = 0.38f
|
||||
}
|
||||
@@ -53,7 +53,6 @@ class UserDetailViewAdapterTest : SysuiTestCase() {
|
||||
@Mock private lateinit var mUserDetailItemView: UserDetailItemView
|
||||
@Mock private lateinit var mOtherView: View
|
||||
@Mock private lateinit var mInflatedUserDetailItemView: UserDetailItemView
|
||||
@Mock private lateinit var mUserInfo: UserInfo
|
||||
@Mock private lateinit var mLayoutInflater: LayoutInflater
|
||||
private var falsingManagerFake: FalsingManagerFake = FalsingManagerFake()
|
||||
private lateinit var adapter: UserDetailView.Adapter
|
||||
@@ -142,7 +141,7 @@ class UserDetailViewAdapterTest : SysuiTestCase() {
|
||||
|
||||
private fun createUserRecord(current: Boolean, guest: Boolean) =
|
||||
UserRecord(
|
||||
mUserInfo,
|
||||
UserInfo(0 /* id */, "name", 0 /* flags */),
|
||||
mPicture,
|
||||
guest,
|
||||
current,
|
||||
|
||||
@@ -57,8 +57,6 @@ class KeyguardUserSwitcherAdapterTest : SysuiTestCase() {
|
||||
@Mock
|
||||
private lateinit var inflatedUserDetailItemView: KeyguardUserDetailItemView
|
||||
@Mock
|
||||
private lateinit var userInfo: UserInfo
|
||||
@Mock
|
||||
private lateinit var layoutInflater: LayoutInflater
|
||||
@Mock
|
||||
private lateinit var keyguardUserSwitcherController: KeyguardUserSwitcherController
|
||||
@@ -188,7 +186,7 @@ class KeyguardUserSwitcherAdapterTest : SysuiTestCase() {
|
||||
|
||||
private fun createUserRecord(isCurrentUser: Boolean, isGuestUser: Boolean) =
|
||||
UserRecord(
|
||||
userInfo,
|
||||
UserInfo(0 /* id */, "name", 0 /* flags */),
|
||||
picture,
|
||||
isGuestUser,
|
||||
isCurrentUser,
|
||||
|
||||
Reference in New Issue
Block a user