blob: 5ad08acb373566248e5ac39a23d8142b9bdccfb1 [file] [log] [blame]
/*
* Copyright (C) 2018 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.statusbar.car;
import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.drawable.GradientDrawable;
import android.os.AsyncTask;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.android.settingslib.users.UserManagerHelper;
import com.android.systemui.R;
import java.util.ArrayList;
import java.util.List;
/**
* Displays a GridLayout with icons for the users in the system to allow switching between users.
* One of the uses of this is for the lock screen in auto.
*/
public class UserGridRecyclerView extends RecyclerView implements
UserManagerHelper.OnUsersUpdateListener {
private UserSelectionListener mUserSelectionListener;
private UserAdapter mAdapter;
private UserManagerHelper mUserManagerHelper;
private Context mContext;
public UserGridRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
super.setHasFixedSize(true);
mContext = context;
mUserManagerHelper = new UserManagerHelper(mContext);
}
/**
* Register listener for any update to the users
*/
@Override
public void onFinishInflate() {
mUserManagerHelper.registerOnUsersUpdateListener(this);
}
/**
* Unregisters listener checking for any change to the users
*/
@Override
public void onDetachedFromWindow() {
mUserManagerHelper.unregisterOnUsersUpdateListener();
}
/**
* Initializes the adapter that populates the grid layout
*
* @return the adapter
*/
public void buildAdapter() {
List<UserRecord> userRecords = createUserRecords(mUserManagerHelper
.getAllUsers());
mAdapter = new UserAdapter(mContext, userRecords);
super.setAdapter(mAdapter);
}
private List<UserRecord> createUserRecords(List<UserInfo> userInfoList) {
List<UserRecord> userRecords = new ArrayList<>();
for (UserInfo userInfo : userInfoList) {
boolean isForeground = mUserManagerHelper.getForegroundUserId() == userInfo.id;
UserRecord record = new UserRecord(userInfo, false /* isGuest */,
false /* isAddUser */, isForeground);
userRecords.add(record);
}
// Add guest user record if the foreground user is not a guest
if (!mUserManagerHelper.foregroundUserIsGuestUser()) {
userRecords.add(addGuestUserRecord());
}
// Add add user record if the foreground user can add users
if (mUserManagerHelper.foregroundUserCanAddUsers()) {
userRecords.add(addUserRecord());
}
return userRecords;
}
/**
* Create guest user record
*/
private UserRecord addGuestUserRecord() {
UserInfo userInfo = new UserInfo();
userInfo.name = mContext.getString(R.string.car_guest);
return new UserRecord(userInfo, true /* isGuest */,
false /* isAddUser */, false /* isForeground */);
}
/**
* Create add user record
*/
private UserRecord addUserRecord() {
UserInfo userInfo = new UserInfo();
userInfo.name = mContext.getString(R.string.car_add_user);
return new UserRecord(userInfo, false /* isGuest */,
true /* isAddUser */, false /* isForeground */);
}
public void setUserSelectionListener(UserSelectionListener userSelectionListener) {
mUserSelectionListener = userSelectionListener;
}
@Override
public void onUsersUpdate() {
mAdapter.clearUsers();
mAdapter.updateUsers(createUserRecords(mUserManagerHelper.getAllUsers()));
mAdapter.notifyDataSetChanged();
}
/**
* Adapter to populate the grid layout with the available user profiles
*/
public final class UserAdapter extends RecyclerView.Adapter<UserAdapter.UserAdapterViewHolder> {
private final Context mContext;
private List<UserRecord> mUsers;
private final int mPodImageAvatarWidth;
private final int mPodImageAvatarHeight;
private final Resources mRes;
private final String mGuestName;
private final String mNewUserName;
public UserAdapter(Context context, List<UserRecord> users) {
mRes = context.getResources();
mContext = context;
updateUsers(users);
mPodImageAvatarWidth = mRes.getDimensionPixelSize(
R.dimen.car_fullscreen_user_pod_image_avatar_width);
mPodImageAvatarHeight = mRes.getDimensionPixelSize(
R.dimen.car_fullscreen_user_pod_image_avatar_height);
mGuestName = mRes.getString(R.string.car_guest);
mNewUserName = mRes.getString(R.string.car_new_user);
}
public void clearUsers() {
mUsers.clear();
}
public void updateUsers(List<UserRecord> users) {
mUsers = users;
}
@Override
public UserAdapterViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext)
.inflate(R.layout.car_fullscreen_user_pod, parent, false);
view.setAlpha(1f);
view.bringToFront();
return new UserAdapterViewHolder(view);
}
@Override
public void onBindViewHolder(UserAdapterViewHolder holder, int position) {
UserRecord userRecord = mUsers.get(position);
holder.mUserAvatarImageView.setImageBitmap(getDefaultUserIcon(userRecord));
holder.mUserNameTextView.setText(userRecord.mInfo.name);
holder.mView.setOnClickListener(v -> {
if (userRecord == null) {
return;
}
// Notify the listener which user was selected
if (mUserSelectionListener != null) {
mUserSelectionListener.onUserSelected(userRecord);
}
// If the user selects Guest, switch to Guest profile
if (userRecord.mIsGuest) {
mUserManagerHelper.switchToGuest(mGuestName);
return;
}
// If the user wants to add a user, start task to add new user
if (userRecord.mIsAddUser) {
new AddNewUserTask().execute(mNewUserName);
return;
}
// If the user doesn't want to be a guest or add a user, switch to the user selected
mUserManagerHelper.switchToUser(userRecord.mInfo);
});
}
private class AddNewUserTask extends AsyncTask<String, Void, UserInfo> {
@Override
protected UserInfo doInBackground(String... userNames) {
return mUserManagerHelper.createNewUser(userNames[0]);
}
@Override
protected void onPreExecute() {
}
@Override
protected void onPostExecute(UserInfo user) {
if (user != null) {
mUserManagerHelper.switchToUser(user);
}
}
}
@Override
public int getItemCount() {
return mUsers.size();
}
/**
* Returns the default user icon. This icon is a circle with a letter in it. The letter is
* the first character in the username.
*
* @param record the profile of the user for which the icon should be created
*/
private Bitmap getDefaultUserIcon(UserRecord record) {
CharSequence displayText;
boolean isAddUserText = false;
if (record.mIsAddUser) {
displayText = "+";
isAddUserText = true;
} else {
displayText = record.mInfo.name.subSequence(0, 1);
}
Bitmap out = Bitmap.createBitmap(mPodImageAvatarWidth, mPodImageAvatarHeight,
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(out);
// Draw the circle background.
GradientDrawable shape = new GradientDrawable();
shape.setShape(GradientDrawable.RADIAL_GRADIENT);
shape.setGradientRadius(1.0f);
shape.setColor(mContext.getColor(R.color.car_user_switcher_no_user_image_bgcolor));
shape.setBounds(0, 0, mPodImageAvatarWidth, mPodImageAvatarHeight);
shape.draw(canvas);
// Draw the letter in the center.
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(mContext.getColor(R.color.car_user_switcher_no_user_image_fgcolor));
paint.setTextAlign(Align.CENTER);
if (isAddUserText) {
paint.setTextSize(mRes.getDimensionPixelSize(
R.dimen.car_touch_target_size));
} else {
paint.setTextSize(mRes.getDimensionPixelSize(
R.dimen.car_fullscreen_user_pod_icon_text_size));
}
Paint.FontMetricsInt metrics = paint.getFontMetricsInt();
// The Y coordinate is measured by taking half the height of the pod, but that would
// draw the character putting the bottom of the font in the middle of the pod. To
// correct this, half the difference between the top and bottom distance metrics of the
// font gives the offset of the font. Bottom is a positive value, top is negative, so
// the different is actually a sum. The "half" operation is then factored out.
canvas.drawText(displayText.toString(), mPodImageAvatarWidth / 2,
(mPodImageAvatarHeight - (metrics.bottom + metrics.top)) / 2, paint);
return out;
}
public class UserAdapterViewHolder extends RecyclerView.ViewHolder {
public ImageView mUserAvatarImageView;
public TextView mUserNameTextView;
public View mView;
public UserAdapterViewHolder(View view) {
super(view);
mView = view;
mUserAvatarImageView = (ImageView) view.findViewById(R.id.user_avatar);
mUserNameTextView = (TextView) view.findViewById(R.id.user_name);
}
}
}
/**
* Object wrapper class for the userInfo. Use it to distinguish if a profile is a
* guest profile, add user profile, or the foreground user.
*/
public static final class UserRecord {
public final UserInfo mInfo;
public final boolean mIsGuest;
public final boolean mIsAddUser;
public final boolean mIsForeground;
public UserRecord(UserInfo userInfo, boolean isGuest, boolean isAddUser,
boolean isForeground) {
mInfo = userInfo;
mIsGuest = isGuest;
mIsAddUser = isAddUser;
mIsForeground = isForeground;
}
}
/**
* Listener used to notify when a user has been selected
*/
interface UserSelectionListener {
void onUserSelected(UserRecord record);
}
}