blob: fc76f78e0b1fa4fcedbe0f897793d15d5d55b900 [file] [log] [blame]
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -07001/*
2 * Copyright (C) 2018 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
17package com.android.systemui.statusbar.car;
18
Aarthi Balachander0e0e9212018-04-19 19:25:33 -070019import static android.content.DialogInterface.BUTTON_POSITIVE;
20
21import android.app.AlertDialog;
22import android.app.AlertDialog.Builder;
23import android.app.Dialog;
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -070024import android.content.Context;
Aarthi Balachander0e0e9212018-04-19 19:25:33 -070025import android.content.DialogInterface;
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -070026import android.content.pm.UserInfo;
27import android.content.res.Resources;
jovanake4ce3cc2018-04-19 12:17:12 -070028import android.graphics.Bitmap;
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -070029import android.os.AsyncTask;
jovanake4ce3cc2018-04-19 12:17:12 -070030import android.os.UserHandle;
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -070031import android.support.v7.widget.RecyclerView;
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -070032import android.util.AttributeSet;
33import android.view.LayoutInflater;
34import android.view.View;
35import android.view.ViewGroup;
36import android.widget.ImageView;
37import android.widget.TextView;
38
Aarthi Balachander608b6e32018-04-11 18:41:52 -070039import androidx.car.widget.PagedListView;
40
Aarthi Balachandere3110e42018-04-30 18:16:26 -070041import androidx.core.graphics.drawable.RoundedBitmapDrawable;
42import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
jovanake4ce3cc2018-04-19 12:17:12 -070043import com.android.internal.util.UserIcons;
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -070044import com.android.settingslib.users.UserManagerHelper;
45import com.android.systemui.R;
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -070046
Aarthi Balachander0e0e9212018-04-19 19:25:33 -070047import com.android.systemui.statusbar.phone.SystemUIDialog;
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -070048import java.util.ArrayList;
49import java.util.List;
50
51/**
52 * Displays a GridLayout with icons for the users in the system to allow switching between users.
53 * One of the uses of this is for the lock screen in auto.
54 */
Aarthi Balachander608b6e32018-04-11 18:41:52 -070055public class UserGridRecyclerView extends PagedListView implements
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -070056 UserManagerHelper.OnUsersUpdateListener {
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -070057 private UserSelectionListener mUserSelectionListener;
58 private UserAdapter mAdapter;
59 private UserManagerHelper mUserManagerHelper;
60 private Context mContext;
61
62 public UserGridRecyclerView(Context context, AttributeSet attrs) {
63 super(context, attrs);
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -070064 mContext = context;
65 mUserManagerHelper = new UserManagerHelper(mContext);
66 }
67
68 /**
69 * Register listener for any update to the users
70 */
71 @Override
72 public void onFinishInflate() {
Aarthi Balachander608b6e32018-04-11 18:41:52 -070073 super.onFinishInflate();
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -070074 mUserManagerHelper.registerOnUsersUpdateListener(this);
75 }
76
77 /**
78 * Unregisters listener checking for any change to the users
79 */
80 @Override
81 public void onDetachedFromWindow() {
Aarthi Balachander608b6e32018-04-11 18:41:52 -070082 super.onDetachedFromWindow();
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -070083 mUserManagerHelper.unregisterOnUsersUpdateListener();
84 }
85
86 /**
87 * Initializes the adapter that populates the grid layout
88 *
89 * @return the adapter
90 */
91 public void buildAdapter() {
92 List<UserRecord> userRecords = createUserRecords(mUserManagerHelper
93 .getAllUsers());
94 mAdapter = new UserAdapter(mContext, userRecords);
95 super.setAdapter(mAdapter);
96 }
97
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -070098 private List<UserRecord> createUserRecords(List<UserInfo> userInfoList) {
99 List<UserRecord> userRecords = new ArrayList<>();
100 for (UserInfo userInfo : userInfoList) {
jovanak80b48592018-04-11 17:09:53 -0700101 if (userInfo.isGuest()) {
102 // Don't display guests in the switcher.
103 continue;
104 }
jovanak0535abc2018-04-10 15:14:50 -0700105 boolean isForeground = mUserManagerHelper.getForegroundUserId() == userInfo.id;
jovanak80b48592018-04-11 17:09:53 -0700106 UserRecord record = new UserRecord(userInfo, false /* isStartGuestSession */,
jovanak0535abc2018-04-10 15:14:50 -0700107 false /* isAddUser */, isForeground);
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700108 userRecords.add(record);
109 }
110
jovanak0535abc2018-04-10 15:14:50 -0700111 // Add guest user record if the foreground user is not a guest
jovanak82029ae2018-04-02 16:40:15 -0700112 if (!mUserManagerHelper.foregroundUserIsGuestUser()) {
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700113 userRecords.add(addGuestUserRecord());
114 }
115
jovanak0535abc2018-04-10 15:14:50 -0700116 // Add add user record if the foreground user can add users
jovanak82029ae2018-04-02 16:40:15 -0700117 if (mUserManagerHelper.foregroundUserCanAddUsers()) {
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700118 userRecords.add(addUserRecord());
119 }
120
121 return userRecords;
122 }
123
124 /**
125 * Create guest user record
126 */
127 private UserRecord addGuestUserRecord() {
128 UserInfo userInfo = new UserInfo();
129 userInfo.name = mContext.getString(R.string.car_guest);
jovanak80b48592018-04-11 17:09:53 -0700130 return new UserRecord(userInfo, true /* isStartGuestSession */,
jovanak0535abc2018-04-10 15:14:50 -0700131 false /* isAddUser */, false /* isForeground */);
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700132 }
133
134 /**
135 * Create add user record
136 */
137 private UserRecord addUserRecord() {
138 UserInfo userInfo = new UserInfo();
139 userInfo.name = mContext.getString(R.string.car_add_user);
jovanak80b48592018-04-11 17:09:53 -0700140 return new UserRecord(userInfo, false /* isStartGuestSession */,
jovanak0535abc2018-04-10 15:14:50 -0700141 true /* isAddUser */, false /* isForeground */);
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700142 }
143
144 public void setUserSelectionListener(UserSelectionListener userSelectionListener) {
145 mUserSelectionListener = userSelectionListener;
146 }
147
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700148 @Override
149 public void onUsersUpdate() {
150 mAdapter.clearUsers();
151 mAdapter.updateUsers(createUserRecords(mUserManagerHelper.getAllUsers()));
152 mAdapter.notifyDataSetChanged();
153 }
154
155 /**
156 * Adapter to populate the grid layout with the available user profiles
157 */
Aarthi Balachander0e0e9212018-04-19 19:25:33 -0700158 public final class UserAdapter extends RecyclerView.Adapter<UserAdapter.UserAdapterViewHolder>
159 implements Dialog.OnClickListener {
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700160
161 private final Context mContext;
162 private List<UserRecord> mUsers;
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700163 private final Resources mRes;
164 private final String mGuestName;
165 private final String mNewUserName;
Aarthi Balachander0e0e9212018-04-19 19:25:33 -0700166 private AlertDialog mDialog;
167 // View that holds the add user button. Used to enable/disable the view
168 private View mAddUserView;
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700169
170 public UserAdapter(Context context, List<UserRecord> users) {
171 mRes = context.getResources();
172 mContext = context;
173 updateUsers(users);
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700174 mGuestName = mRes.getString(R.string.car_guest);
175 mNewUserName = mRes.getString(R.string.car_new_user);
176 }
177
178 public void clearUsers() {
179 mUsers.clear();
180 }
181
182 public void updateUsers(List<UserRecord> users) {
183 mUsers = users;
184 }
185
186 @Override
187 public UserAdapterViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
188 View view = LayoutInflater.from(mContext)
189 .inflate(R.layout.car_fullscreen_user_pod, parent, false);
190 view.setAlpha(1f);
191 view.bringToFront();
192 return new UserAdapterViewHolder(view);
193 }
194
195 @Override
196 public void onBindViewHolder(UserAdapterViewHolder holder, int position) {
197 UserRecord userRecord = mUsers.get(position);
Aarthi Balachandere3110e42018-04-30 18:16:26 -0700198 RoundedBitmapDrawable circleIcon = RoundedBitmapDrawableFactory.create(mRes,
199 getUserRecordIcon(userRecord));
200 circleIcon.setCircular(true);
201 holder.mUserAvatarImageView.setImageDrawable(circleIcon);
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700202 holder.mUserNameTextView.setText(userRecord.mInfo.name);
203 holder.mView.setOnClickListener(v -> {
204 if (userRecord == null) {
205 return;
206 }
207
208 // Notify the listener which user was selected
209 if (mUserSelectionListener != null) {
210 mUserSelectionListener.onUserSelected(userRecord);
211 }
212
jovanak80b48592018-04-11 17:09:53 -0700213 // If the user selects Guest, start the guest session.
214 if (userRecord.mIsStartGuestSession) {
jovanak6639c4d2018-04-25 14:45:18 -0700215 mUserManagerHelper.startNewGuestSession(mGuestName);
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700216 return;
217 }
218
Aarthi Balachander0e0e9212018-04-19 19:25:33 -0700219 // If the user wants to add a user, show dialog to confirm adding a user
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700220 if (userRecord.mIsAddUser) {
Aarthi Balachander0e0e9212018-04-19 19:25:33 -0700221 // Disable button so it cannot be clicked multiple times
222 mAddUserView = holder.mView;
223 mAddUserView.setEnabled(false);
224
225 String message = mRes.getString(R.string.user_add_user_message_setup)
226 .concat(System.getProperty("line.separator"))
227 .concat(System.getProperty("line.separator"))
228 .concat(mRes.getString(R.string.user_add_user_message_update));
229
230 mDialog = new Builder(mContext, R.style.Theme_Car_Dark_Dialog_Alert)
231 .setTitle(R.string.user_add_user_title)
232 .setMessage(message)
233 .setNegativeButton(android.R.string.cancel, this)
234 .setPositiveButton(android.R.string.ok, this)
235 .create();
236 // Sets window flags for the SysUI dialog
237 SystemUIDialog.applyFlags(mDialog);
238 mDialog.show();
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700239 return;
240 }
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700241 // If the user doesn't want to be a guest or add a user, switch to the user selected
242 mUserManagerHelper.switchToUser(userRecord.mInfo);
243 });
244
245 }
246
jovanake4ce3cc2018-04-19 12:17:12 -0700247 private Bitmap getUserRecordIcon(UserRecord userRecord) {
248 if (userRecord.mIsStartGuestSession) {
jovanak6639c4d2018-04-25 14:45:18 -0700249 return mUserManagerHelper.getGuestDefaultIcon();
jovanake4ce3cc2018-04-19 12:17:12 -0700250 }
251
252 if (userRecord.mIsAddUser) {
253 return UserIcons.convertToBitmap(mContext
Aarthi Balachander0e0e9212018-04-19 19:25:33 -0700254 .getDrawable(R.drawable.car_add_circle_round));
jovanake4ce3cc2018-04-19 12:17:12 -0700255 }
256
257 return mUserManagerHelper.getUserIcon(userRecord.mInfo);
258 }
259
Aarthi Balachander0e0e9212018-04-19 19:25:33 -0700260 @Override
261 public void onClick(DialogInterface dialog, int which) {
262 // Enable the add button
263 if (mAddUserView != null) {
264 mAddUserView.setEnabled(true);
265 }
266 if (which == BUTTON_POSITIVE) {
267 new AddNewUserTask().execute(mNewUserName);
268 }
269 }
270
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700271 private class AddNewUserTask extends AsyncTask<String, Void, UserInfo> {
272
273 @Override
274 protected UserInfo doInBackground(String... userNames) {
275 return mUserManagerHelper.createNewUser(userNames[0]);
276 }
277
278 @Override
279 protected void onPreExecute() {
280 }
281
282 @Override
283 protected void onPostExecute(UserInfo user) {
284 if (user != null) {
285 mUserManagerHelper.switchToUser(user);
286 }
287 }
288 }
289
290 @Override
291 public int getItemCount() {
292 return mUsers.size();
293 }
294
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700295 public class UserAdapterViewHolder extends RecyclerView.ViewHolder {
296
297 public ImageView mUserAvatarImageView;
298 public TextView mUserNameTextView;
299 public View mView;
300
301 public UserAdapterViewHolder(View view) {
302 super(view);
303 mView = view;
304 mUserAvatarImageView = (ImageView) view.findViewById(R.id.user_avatar);
305 mUserNameTextView = (TextView) view.findViewById(R.id.user_name);
306 }
307 }
308 }
309
310 /**
311 * Object wrapper class for the userInfo. Use it to distinguish if a profile is a
jovanak0535abc2018-04-10 15:14:50 -0700312 * guest profile, add user profile, or the foreground user.
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700313 */
314 public static final class UserRecord {
315
316 public final UserInfo mInfo;
jovanak80b48592018-04-11 17:09:53 -0700317 public final boolean mIsStartGuestSession;
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700318 public final boolean mIsAddUser;
jovanak0535abc2018-04-10 15:14:50 -0700319 public final boolean mIsForeground;
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700320
jovanak80b48592018-04-11 17:09:53 -0700321 public UserRecord(UserInfo userInfo, boolean isStartGuestSession, boolean isAddUser,
jovanak0535abc2018-04-10 15:14:50 -0700322 boolean isForeground) {
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700323 mInfo = userInfo;
jovanak80b48592018-04-11 17:09:53 -0700324 mIsStartGuestSession = isStartGuestSession;
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700325 mIsAddUser = isAddUser;
jovanak0535abc2018-04-10 15:14:50 -0700326 mIsForeground = isForeground;
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700327 }
328 }
329
330 /**
331 * Listener used to notify when a user has been selected
332 */
333 interface UserSelectionListener {
334
335 void onUserSelected(UserRecord record);
336 }
337}