/*
* Copyright (C) 2020 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.car.hal;
import static com.android.car.internal.common.CommonConstants.EMPTY_INT_ARRAY;
import static com.android.car.CarServiceUtils.toIntArray;
import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.PRIVATE_CONSTRUCTOR;
import static com.android.internal.util.Preconditions.checkArgument;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.car.builtin.os.UserManagerHelper;
import android.car.builtin.util.Slogf;
import android.hardware.automotive.vehicle.CreateUserRequest;
import android.hardware.automotive.vehicle.InitialUserInfoRequestType;
import android.hardware.automotive.vehicle.InitialUserInfoResponse;
import android.hardware.automotive.vehicle.InitialUserInfoResponseAction;
import android.hardware.automotive.vehicle.RemoveUserRequest;
import android.hardware.automotive.vehicle.SwitchUserRequest;
import android.hardware.automotive.vehicle.UserIdentificationAssociation;
import android.hardware.automotive.vehicle.UserIdentificationAssociationSetValue;
import android.hardware.automotive.vehicle.UserIdentificationAssociationType;
import android.hardware.automotive.vehicle.UserIdentificationAssociationValue;
import android.hardware.automotive.vehicle.UserIdentificationGetRequest;
import android.hardware.automotive.vehicle.UserIdentificationResponse;
import android.hardware.automotive.vehicle.UserIdentificationSetAssociation;
import android.hardware.automotive.vehicle.UserIdentificationSetRequest;
import android.hardware.automotive.vehicle.UserInfo;
import android.hardware.automotive.vehicle.UsersInfo;
import android.hardware.automotive.vehicle.VehiclePropertyStatus;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
import com.android.car.hal.HalCallback.HalCallbackStatus;
import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
import com.android.car.internal.util.DebugUtils;
import com.android.car.user.UserHandleHelper;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
/**
* Provides utility methods for User HAL related functionalities.
*/
public final class UserHalHelper {
@VisibleForTesting
static final String TAG = UserHalHelper.class.getSimpleName();
public static final int INITIAL_USER_INFO_PROPERTY = 299896583;
public static final int SWITCH_USER_PROPERTY = 299896584;
public static final int CREATE_USER_PROPERTY = 299896585;
public static final int REMOVE_USER_PROPERTY = 299896586;
public static final int USER_IDENTIFICATION_ASSOCIATION_PROPERTY = 299896587;
private static final boolean DEBUG = false;
private static final String STRING_SEPARATOR = "\\|\\|";
/**
* Gets user-friendly representation of the status.
*/
public static String halCallbackStatusToString(@HalCallbackStatus int status) {
switch (status) {
case HalCallback.STATUS_OK:
return "OK";
case HalCallback.STATUS_HAL_SET_TIMEOUT:
return "HAL_SET_TIMEOUT";
case HalCallback.STATUS_HAL_RESPONSE_TIMEOUT:
return "HAL_RESPONSE_TIMEOUT";
case HalCallback.STATUS_WRONG_HAL_RESPONSE:
return "WRONG_HAL_RESPONSE";
case HalCallback.STATUS_CONCURRENT_OPERATION:
return "CONCURRENT_OPERATION";
default:
return "UNKNOWN-" + status;
}
}
/**
* Converts a string to a {@link InitialUserInfoRequestType}.
*
* @return valid type or numeric value if passed "as is"
*
* @throws IllegalArgumentException if type is not valid neither a number
*/
public static int parseInitialUserInfoRequestType(String type) {
switch(type) {
case "FIRST_BOOT":
return InitialUserInfoRequestType.FIRST_BOOT;
case "FIRST_BOOT_AFTER_OTA":
return InitialUserInfoRequestType.FIRST_BOOT_AFTER_OTA;
case "COLD_BOOT":
return InitialUserInfoRequestType.COLD_BOOT;
case "RESUME":
return InitialUserInfoRequestType.RESUME;
default:
try {
return Integer.parseInt(type);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("invalid type: " + type, e);
}
}
}
/**
* Converts Android user flags to HALs.
*/
public static int convertFlags(UserHandleHelper userHandleHelper, UserHandle user) {
checkArgument(user != null, "user cannot be null");
int flags = 0;
if (user.getIdentifier() == UserHandle.SYSTEM.getIdentifier()) {
flags |= UserInfo.USER_FLAG_SYSTEM;
}
if (userHandleHelper.isAdminUser(user)) {
flags |= UserInfo.USER_FLAG_ADMIN;
}
if (userHandleHelper.isGuestUser(user)) {
flags |= UserInfo.USER_FLAG_GUEST;
}
if (userHandleHelper.isEphemeralUser(user)) {
flags |= UserInfo.USER_FLAG_EPHEMERAL;
}
if (!userHandleHelper.isEnabledUser(user)) {
flags |= UserInfo.USER_FLAG_DISABLED;
}
if (userHandleHelper.isProfileUser(user)) {
flags |= UserInfo.USER_FLAG_PROFILE;
}
return flags;
}
/**
* Converts Android user flags to HALs.
*/
public static int getFlags(UserHandleHelper userHandleHelper, @UserIdInt int userId) {
Preconditions.checkArgument(userHandleHelper != null, "UserManager cannot be null");
UserHandle user = userHandleHelper.getExistingUserHandle(userId);
Preconditions.checkArgument(user != null, "No user with id %d", userId);
return convertFlags(userHandleHelper, user);
}
/** Checks if a HAL flag contains {@link UserInfo#USER_FLAG_SYSTEM}. */
public static boolean isSystem(int flags) {
return (flags & UserInfo.USER_FLAG_SYSTEM) != 0;
}
/** Checks if a HAL flag contains {@link UserInfo#USER_FLAG_GUEST}. */
public static boolean isGuest(int flags) {
return (flags & UserInfo.USER_FLAG_GUEST) != 0;
}
/** Checks if a HAL flag contains {@link UserInfo#USER_FLAG_EPHEMERAL}. */
public static boolean isEphemeral(int flags) {
return (flags & UserInfo.USER_FLAG_EPHEMERAL) != 0;
}
/** Checks if a HAL flag contains {@link UserInfo#USER_FLAG_ADMIN}. */
public static boolean isAdmin(int flags) {
return (flags & UserInfo.USER_FLAG_ADMIN) != 0;
}
/** Checks if a HAL flag contains {@link UserInfo#USER_FLAG_DISABLED}. */
public static boolean isDisabled(int flags) {
return (flags & UserInfo.USER_FLAG_DISABLED) != 0;
}
/** Checks if a HAL flag contains {@link UserInfo#USER_FLAG_PROFILE}. */
public static boolean isProfile(int flags) {
return (flags & UserInfo.USER_FLAG_PROFILE) != 0;
}
/**
* Converts HAL flags to Android's.
*/
public static int toUserInfoFlags(int halFlags) {
int flags = 0;
if (isEphemeral(halFlags)) {
flags |= UserManagerHelper.FLAG_EPHEMERAL;
}
if (isAdmin(halFlags)) {
flags |= UserManagerHelper.FLAG_ADMIN;
}
return flags;
}
/**
* Gets a user-friendly representation of the user flags.
*/
public static String userFlagsToString(int flags) {
return DebugUtils.flagsToString(UserInfo.class, /* prefix= */ "", flags);
}
/**
* Adds users information to the property's integer values.
*
*
NOTE: it does not validate the semantics of {@link UsersInfo} content (for example,
* if the current user is present in the list of users or if the flags are valid), only the
* basic correctness (like number of users matching existing users list size). Use
* {@link #checkValid(UsersInfo)} for a full check.
*/
public static void addUsersInfo(List intValues, UsersInfo usersInfo) {
Objects.requireNonNull(usersInfo.currentUser, "Current user cannot be null");
checkArgument(usersInfo.numberUsers == usersInfo.existingUsers.length,
"Number of existing users info does not match numberUsers, got %d, want %d",
usersInfo.numberUsers, usersInfo.existingUsers.length);
addUserInfo(intValues, usersInfo.currentUser);
intValues.add(usersInfo.numberUsers);
for (int i = 0; i < usersInfo.numberUsers; i++) {
UserInfo userInfo = usersInfo.existingUsers[i];
addUserInfo(intValues, userInfo);
}
}
/** Adds user information to the property's integer values. */
public static void addUserInfo(List intValues, UserInfo userInfo) {
Objects.requireNonNull(userInfo, "UserInfo cannot be null");
intValues.add(userInfo.userId);
intValues.add(userInfo.flags);
}
/**
* Checks if the given {@code value} is a valid {@link UserIdentificationAssociationType}.
*/
public static boolean isValidUserIdentificationAssociationType(int type) {
switch(type) {
case UserIdentificationAssociationType.KEY_FOB:
case UserIdentificationAssociationType.CUSTOM_1:
case UserIdentificationAssociationType.CUSTOM_2:
case UserIdentificationAssociationType.CUSTOM_3:
case UserIdentificationAssociationType.CUSTOM_4:
return true;
default:
break;
}
return false;
}
/**
* Checks if the given {@code value} is a valid {@link UserIdentificationAssociationValue}.
*/
public static boolean isValidUserIdentificationAssociationValue(int value) {
switch(value) {
case UserIdentificationAssociationValue.ASSOCIATED_ANOTHER_USER:
case UserIdentificationAssociationValue.ASSOCIATED_CURRENT_USER:
case UserIdentificationAssociationValue.NOT_ASSOCIATED_ANY_USER:
case UserIdentificationAssociationValue.UNKNOWN:
return true;
default:
break;
}
return false;
}
/**
* Checks if the given {@code value} is a valid {@link UserIdentificationAssociationSetValue}.
*/
public static boolean isValidUserIdentificationAssociationSetValue(int value) {
switch(value) {
case UserIdentificationAssociationSetValue.ASSOCIATE_CURRENT_USER:
case UserIdentificationAssociationSetValue.DISASSOCIATE_CURRENT_USER:
case UserIdentificationAssociationSetValue.DISASSOCIATE_ALL_USERS:
return true;
default:
break;
}
return false;
}
/**
* Creates a {@link UserIdentificationResponse} from a generic {@link HalPropValue} sent by
* HAL.
*
* @throws IllegalArgumentException if the HAL property doesn't have the proper format.
*/
public static UserIdentificationResponse toUserIdentificationResponse(HalPropValue prop) {
Objects.requireNonNull(prop, "prop cannot be null");
checkArgument(prop.getPropId() == USER_IDENTIFICATION_ASSOCIATION_PROPERTY,
"invalid prop on %s", prop);
// need at least 4: request_id, number associations, type1, value1
assertMinimumSize(prop, 4);
int requestId = prop.getInt32Value(0);
checkArgument(requestId > 0, "invalid request id (%d) on %s", requestId, prop);
int numberAssociations = prop.getInt32Value(1);
checkArgument(numberAssociations >= 1, "invalid number of items on %s", prop);
int numberOfNonItems = 2; // requestId and size
int numberItems = prop.getInt32ValuesSize() - numberOfNonItems;
checkArgument(numberItems == numberAssociations * 2, "number of items mismatch on %s",
prop);
UserIdentificationResponse response = new UserIdentificationResponse();
response.requestId = requestId;
response.errorMessage = prop.getStringValue();
response.numberAssociation = numberAssociations;
int i = numberOfNonItems;
ArrayList associations = new ArrayList<>(numberAssociations);
for (int a = 0; a < numberAssociations; a++) {
int index;
UserIdentificationAssociation association = new UserIdentificationAssociation();
index = i++;
association.type = prop.getInt32Value(index);
checkArgument(isValidUserIdentificationAssociationType(association.type),
"invalid type at index %d on %s", index, prop);
index = i++;
association.value = prop.getInt32Value(index);
checkArgument(isValidUserIdentificationAssociationValue(association.value),
"invalid value at index %d on %s", index, prop);
associations.add(association);
}
response.associations = associations.toArray(
new UserIdentificationAssociation[associations.size()]);
return response;
}
/**
* Creates a {@link InitialUserInfoResponse} from a generic {@link HalPropValue} sent by
* HAL.
*
* @throws IllegalArgumentException if the HAL property doesn't have the proper format.
*/
public static InitialUserInfoResponse toInitialUserInfoResponse(HalPropValue prop) {
if (DEBUG) Slogf.d(TAG, "toInitialUserInfoResponse(): %s", prop);
Objects.requireNonNull(prop, "prop cannot be null");
checkArgument(prop.getPropId() == INITIAL_USER_INFO_PROPERTY, "invalid prop on %s", prop);
// need at least 2: request_id, action_type
assertMinimumSize(prop, 2);
int requestId = prop.getInt32Value(0);
checkArgument(requestId > 0, "invalid request id (%d) on %s", requestId, prop);
InitialUserInfoResponse response = new InitialUserInfoResponse();
response.userToSwitchOrCreate = new UserInfo();
response.userLocales = "";
response.userNameToCreate = "";
response.requestId = requestId;
response.action = prop.getInt32Value(1);
String[] stringValues = null;
if (!TextUtils.isEmpty(prop.getStringValue())) {
stringValues = TextUtils.split(prop.getStringValue(), STRING_SEPARATOR);
if (DEBUG) {
Slogf.d(TAG, "toInitialUserInfoResponse(): values=" + Arrays.toString(stringValues)
+ " length: " + stringValues.length);
}
}
if (stringValues != null && stringValues.length > 0) {
response.userLocales = stringValues[0];
}
switch (response.action) {
case InitialUserInfoResponseAction.DEFAULT:
response.userToSwitchOrCreate.userId = UserManagerHelper.USER_NULL;
break;
case InitialUserInfoResponseAction.SWITCH:
assertMinimumSize(prop, 3); // request_id, action_type, user_id
response.userToSwitchOrCreate.userId = prop.getInt32Value(2);
break;
case InitialUserInfoResponseAction.CREATE:
assertMinimumSize(prop, 4); // request_id, action_type, user_id, user_flags
// user id is set at index 2, but it's ignored
response.userToSwitchOrCreate.userId = UserManagerHelper.USER_NULL;
response.userToSwitchOrCreate.flags = prop.getInt32Value(3);
if (stringValues.length > 1) {
response.userNameToCreate = stringValues[1];
}
break;
default:
throw new IllegalArgumentException("Invalid response action (" + response.action
+ " on " + prop);
}
if (DEBUG) Slogf.d(TAG, "returning : " + response);
return response;
}
/**
* Creates a generic {@link HalPropValue} (that can be sent to HAL) from a
* {@link UserIdentificationGetRequest}.
*
* @throws IllegalArgumentException if the request doesn't have the proper format.
*/
public static HalPropValue toHalPropValue(HalPropValueBuilder builder,
UserIdentificationGetRequest request) {
Objects.requireNonNull(request, "request cannot be null");
Objects.requireNonNull(request.associationTypes, "associationTypes must not be null");
checkArgument(request.numberAssociationTypes > 0,
"invalid number of association types mismatch on %s", request);
checkArgument(request.numberAssociationTypes == request.associationTypes.length,
"number of association types mismatch on %s", request);
checkArgument(request.requestId > 0, "invalid requestId on %s", request);
List intValues = new ArrayList<>(request.numberAssociationTypes + 2);
intValues.add(request.requestId);
addUserInfo(intValues, request.userInfo);
intValues.add(request.numberAssociationTypes);
for (int i = 0; i < request.numberAssociationTypes; i++) {
int type = request.associationTypes[i];
checkArgument(isValidUserIdentificationAssociationType(type),
"invalid type at index %d on %s", i, request);
intValues.add(type);
}
HalPropValue propValue = builder.build(USER_IDENTIFICATION_ASSOCIATION_PROPERTY,
/* areaId= */ 0, SystemClock.elapsedRealtime(),
VehiclePropertyStatus.AVAILABLE,
toIntArray(intValues));
return propValue;
}
/**
* Creates a generic {@link HalPropValue} (that can be sent to HAL) from a
* {@link UserIdentificationSetRequest}.
*
* @throws IllegalArgumentException if the request doesn't have the proper format.
*/
public static HalPropValue toHalPropValue(HalPropValueBuilder builder,
UserIdentificationSetRequest request) {
Objects.requireNonNull(request, "request cannot be null");
Objects.requireNonNull(request.associations, "associations must not be null");
checkArgument(request.numberAssociations > 0,
"invalid number of associations mismatch on %s", request);
checkArgument(request.numberAssociations == request.associations.length,
"number of associations mismatch on %s", request);
checkArgument(request.requestId > 0, "invalid requestId on %s", request);
List intValues = new ArrayList<>(2);
intValues.add(request.requestId);
addUserInfo(intValues, request.userInfo);
intValues.add(request.numberAssociations);
for (int i = 0; i < request.numberAssociations; i++) {
UserIdentificationSetAssociation association = request.associations[i];
checkArgument(isValidUserIdentificationAssociationType(association.type),
"invalid type at index %d on %s", i, request);
intValues.add(association.type);
checkArgument(isValidUserIdentificationAssociationSetValue(association.value),
"invalid value at index %d on %s", i, request);
intValues.add(association.value);
}
HalPropValue propValue = builder.build(USER_IDENTIFICATION_ASSOCIATION_PROPERTY,
/* areaId= */ 0, SystemClock.elapsedRealtime(),
VehiclePropertyStatus.AVAILABLE,
toIntArray(intValues));
return propValue;
}
/**
* Creates a generic {@link HalPropValue} (that can be sent to HAL) from a
* {@link CreateUserRequest}.
*
* @throws IllegalArgumentException if the request doesn't have the proper format.
*/
public static HalPropValue toHalPropValue(HalPropValueBuilder builder,
CreateUserRequest request) {
Objects.requireNonNull(request, "request cannot be null");
Objects.requireNonNull(request.newUserInfo, "NewUserInfo cannot be null");
checkArgument(request.requestId > 0, "invalid requestId on %s", request);
checkValid(request.usersInfo);
checkArgument(request.newUserName != null, "newUserName cannot be null (should be empty "
+ "instead) on %s", request);
boolean hasNewUser = false;
int newUserFlags = 0;
for (int i = 0; i < request.usersInfo.existingUsers.length; i++) {
UserInfo user = request.usersInfo.existingUsers[i];
if (user.userId == request.newUserInfo.userId) {
hasNewUser = true;
newUserFlags = user.flags;
break;
}
}
Preconditions.checkArgument(hasNewUser,
"new user's id not present on existing users on request %s", request);
Preconditions.checkArgument(request.newUserInfo.flags == newUserFlags,
"new user flags mismatch on existing users on %s", request);
List intValues = new ArrayList<>(2);
intValues.add(request.requestId);
addUserInfo(intValues, request.newUserInfo);
addUsersInfo(intValues, request.usersInfo);
HalPropValue propValue = builder.build(CREATE_USER_PROPERTY, /* areaId= */ 0,
SystemClock.elapsedRealtime(), VehiclePropertyStatus.AVAILABLE,
toIntArray(intValues), new float[0], new long[0], request.newUserName, new byte[0]);
return propValue;
}
/**
* Creates a generic {@link HalPropValue} (that can be sent to HAL) from a
* {@link SwitchUserRequest}.
*
* @throws IllegalArgumentException if the request doesn't have the proper format.
*/
public static HalPropValue toHalPropValue(HalPropValueBuilder builder,
SwitchUserRequest request) {
Objects.requireNonNull(request, "request cannot be null");
checkArgument(request.messageType > 0, "invalid messageType on %s", request);
UserInfo targetInfo = request.targetUser;
UsersInfo usersInfo = request.usersInfo;
Objects.requireNonNull(targetInfo);
checkValid(usersInfo);
List intValues = new ArrayList<>(2);
intValues.add(request.requestId);
intValues.add(request.messageType);
addUserInfo(intValues, targetInfo);
addUsersInfo(intValues, usersInfo);
HalPropValue propValue = builder.build(SWITCH_USER_PROPERTY, /* areaId= */ 0,
SystemClock.elapsedRealtime(), VehiclePropertyStatus.AVAILABLE,
toIntArray(intValues));
return propValue;
}
/**
* Creates a generic {@link HalPropValue} (that can be sent to HAL) from a
* {@link RemoveUserRequest}.
*
* @throws IllegalArgumentException if the request doesn't have the proper format.
*/
public static HalPropValue toHalPropValue(HalPropValueBuilder builder,
RemoveUserRequest request) {
checkArgument(request.requestId > 0, "invalid requestId on %s", request);
UserInfo removedUserInfo = request.removedUserInfo;
Objects.requireNonNull(removedUserInfo);
UsersInfo usersInfo = request.usersInfo;
checkValid(usersInfo);
List intValues = new ArrayList<>(1);
intValues.add(request.requestId);
addUserInfo(intValues, removedUserInfo);
addUsersInfo(intValues, usersInfo);
HalPropValue propValue = builder.build(REMOVE_USER_PROPERTY, /* areaId= */ 0,
SystemClock.elapsedRealtime(), VehiclePropertyStatus.AVAILABLE,
toIntArray(intValues));
return propValue;
}
/**
* Creates a {@link UsersInfo} instance populated with the current users, using
* {@link ActivityManager#getCurrentUser()} as the current user.
*/
public static UsersInfo newUsersInfo(UserManager um, UserHandleHelper userHandleHelper) {
return newUsersInfo(um, userHandleHelper, ActivityManager.getCurrentUser());
}
/**
* Creates a {@link UsersInfo} instance populated with the current users, using
* {@code userId} as the current user.
*/
public static UsersInfo newUsersInfo(UserManager um, UserHandleHelper userHandleHelper,
@UserIdInt int userId) {
Preconditions.checkArgument(um != null, "UserManager cannot be null");
Preconditions.checkArgument(userHandleHelper != null, "UserHandleHelper cannot be null");
List users = UserManagerHelper.getUserHandles(um, /* excludeDying= */ false);
if (users == null || users.isEmpty()) {
Slogf.w(TAG, "newUsersInfo(): no users");
return emptyUsersInfo();
}
UsersInfo usersInfo = emptyUsersInfo();
usersInfo.currentUser.userId = userId;
UserHandle currentUser = null;
int allUsersSize = users.size();
ArrayList halUsers = new ArrayList<>(allUsersSize);
for (int i = 0; i < allUsersSize; i++) {
UserHandle user = users.get(i);
try {
if (user.getIdentifier() == usersInfo.currentUser.userId) {
currentUser = user;
}
UserInfo halUser = new UserInfo();
halUser.userId = user.getIdentifier();
halUser.flags = convertFlags(userHandleHelper, user);
halUsers.add(halUser);
} catch (Exception e) {
// Most likely the user was removed
Slogf.w(TAG, "newUsersInfo(): ignoring user " + user + " due to exception", e);
}
}
int existingUsersSize = halUsers.size();
usersInfo.numberUsers = existingUsersSize;
usersInfo.existingUsers = halUsers.toArray(new UserInfo[existingUsersSize]);
if (currentUser != null) {
usersInfo.currentUser.flags = convertFlags(userHandleHelper, currentUser);
} else {
// This should not happen.
Slogf.wtf(TAG, "Current user is not part of existing users. usersInfo: " + usersInfo);
}
return usersInfo;
}
/**
* Checks if the given {@code usersInfo} is valid.
*
* @throws IllegalArgumentException if it isn't.
*/
public static void checkValid(UsersInfo usersInfo) {
Preconditions.checkArgument(usersInfo != null);
Preconditions.checkArgument(usersInfo.existingUsers != null);
Preconditions.checkArgument(usersInfo.currentUser != null);
Preconditions.checkArgument(usersInfo.numberUsers == usersInfo.existingUsers.length,
"sizes mismatch: numberUsers=%d, existingUsers.size=%d", usersInfo.numberUsers,
usersInfo.existingUsers.length);
boolean hasCurrentUser = false;
int currentUserFlags = 0;
for (int i = 0; i < usersInfo.numberUsers; i++) {
UserInfo user = usersInfo.existingUsers[i];
if (user.userId == usersInfo.currentUser.userId) {
hasCurrentUser = true;
currentUserFlags = user.flags;
break;
}
}
Preconditions.checkArgument(hasCurrentUser,
"current user not found on existing users on %s", usersInfo);
Preconditions.checkArgument(usersInfo.currentUser.flags == currentUserFlags,
"current user flags mismatch on existing users on %s", usersInfo);
}
/**
* Gets an empty CreateUserRequest with fields initialized to valid empty values (not
* {@code null}).
*
* @return An empty {@link CreateUserRequest}.
*/
public static CreateUserRequest emptyCreateUserRequest() {
CreateUserRequest request = new CreateUserRequest();
request.newUserInfo = new UserInfo();
request.usersInfo = emptyUsersInfo();
request.newUserName = "";
return request;
}
/**
* Gets an empty SwitchUserRequest with fields initialized to valid empty values (not
* {@code null}
*
* @return An empty {@link SwitchUserRequest}.
*/
public static SwitchUserRequest emptySwitchUserRequest() {
SwitchUserRequest request = new SwitchUserRequest();
request.targetUser = new UserInfo();
request.usersInfo = emptyUsersInfo();
return request;
}
/**
* Gets an empty RemoveUserRequest with fields initialized to valid empty values (not
* {@code null}
*
* @return An empty {@link RemoveUserRequest}.
*/
public static RemoveUserRequest emptyRemoveUserRequest() {
RemoveUserRequest request = new RemoveUserRequest();
request.removedUserInfo = new UserInfo();
request.usersInfo = emptyUsersInfo();
return request;
}
/**
* Gets an empty UserIdentificationGetRequest with fields initialized to valid empty values
* (not {@code null}).
*
* @return An empty {@link UserIdentificationGetRequest}.
*/
public static UserIdentificationGetRequest emptyUserIdentificationGetRequest() {
UserIdentificationGetRequest request = new UserIdentificationGetRequest();
request.userInfo = new UserInfo();
request.associationTypes = EMPTY_INT_ARRAY;
return request;
}
/**
* Gets an empty UserIdentificationSetRequest with fields initialized to valid empty values
* (not {@code null}).
*
* @return An empty {@link UserIdentificationSetRequest}.
*/
public static UserIdentificationSetRequest emptyUserIdentificationSetRequest() {
UserIdentificationSetRequest request = new UserIdentificationSetRequest();
request.userInfo = new UserInfo();
request.associations = new UserIdentificationSetAssociation[0];
return request;
}
/**
* Gets an empty UsersInfo with fields initialized to valid empty values (not {@code null}).
*
* @return An empty {@link UsersInfo}.
*/
public static UsersInfo emptyUsersInfo() {
UsersInfo usersInfo = new UsersInfo();
usersInfo.currentUser = new UserInfo();
usersInfo.existingUsers = new UserInfo[0];
usersInfo.currentUser.userId = UserManagerHelper.USER_NULL;
return usersInfo;
}
private static void assertMinimumSize(HalPropValue prop, int minSize) {
checkArgument(prop.getInt32ValuesSize() >= minSize,
"not enough int32Values (minimum is %d) on %s", minSize, prop);
}
@ExcludeFromCodeCoverageGeneratedReport(reason = PRIVATE_CONSTRUCTOR)
private UserHalHelper() {
throw new UnsupportedOperationException("contains only static methods");
}
}