blob: 1148fad90dde721c2d7784c9147b810aadd7d88a [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
jovanake4ce3cc2018-04-19 12:17:12 -070041import com.android.internal.util.UserIcons;
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -070042import com.android.settingslib.users.UserManagerHelper;
43import com.android.systemui.R;
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -070044
Aarthi Balachander0e0e9212018-04-19 19:25:33 -070045import com.android.systemui.statusbar.phone.SystemUIDialog;
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -070046import java.util.ArrayList;
47import java.util.List;
48
49/**
50 * Displays a GridLayout with icons for the users in the system to allow switching between users.
51 * One of the uses of this is for the lock screen in auto.
52 */
Aarthi Balachander608b6e32018-04-11 18:41:52 -070053public class UserGridRecyclerView extends PagedListView implements
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -070054 UserManagerHelper.OnUsersUpdateListener {
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -070055 private UserSelectionListener mUserSelectionListener;
56 private UserAdapter mAdapter;
57 private UserManagerHelper mUserManagerHelper;
58 private Context mContext;
59
60 public UserGridRecyclerView(Context context, AttributeSet attrs) {
61 super(context, attrs);
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -070062 mContext = context;
63 mUserManagerHelper = new UserManagerHelper(mContext);
64 }
65
66 /**
67 * Register listener for any update to the users
68 */
69 @Override
70 public void onFinishInflate() {
Aarthi Balachander608b6e32018-04-11 18:41:52 -070071 super.onFinishInflate();
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -070072 mUserManagerHelper.registerOnUsersUpdateListener(this);
73 }
74
75 /**
76 * Unregisters listener checking for any change to the users
77 */
78 @Override
79 public void onDetachedFromWindow() {
Aarthi Balachander608b6e32018-04-11 18:41:52 -070080 super.onDetachedFromWindow();
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -070081 mUserManagerHelper.unregisterOnUsersUpdateListener();
82 }
83
84 /**
85 * Initializes the adapter that populates the grid layout
86 *
87 * @return the adapter
88 */
89 public void buildAdapter() {
90 List<UserRecord> userRecords = createUserRecords(mUserManagerHelper
91 .getAllUsers());
92 mAdapter = new UserAdapter(mContext, userRecords);
93 super.setAdapter(mAdapter);
94 }
95
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -070096 private List<UserRecord> createUserRecords(List<UserInfo> userInfoList) {
97 List<UserRecord> userRecords = new ArrayList<>();
98 for (UserInfo userInfo : userInfoList) {
jovanak80b48592018-04-11 17:09:53 -070099 if (userInfo.isGuest()) {
100 // Don't display guests in the switcher.
101 continue;
102 }
jovanak0535abc2018-04-10 15:14:50 -0700103 boolean isForeground = mUserManagerHelper.getForegroundUserId() == userInfo.id;
jovanak80b48592018-04-11 17:09:53 -0700104 UserRecord record = new UserRecord(userInfo, false /* isStartGuestSession */,
jovanak0535abc2018-04-10 15:14:50 -0700105 false /* isAddUser */, isForeground);
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700106 userRecords.add(record);
107 }
108
jovanak0535abc2018-04-10 15:14:50 -0700109 // Add guest user record if the foreground user is not a guest
jovanak82029ae2018-04-02 16:40:15 -0700110 if (!mUserManagerHelper.foregroundUserIsGuestUser()) {
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700111 userRecords.add(addGuestUserRecord());
112 }
113
jovanak0535abc2018-04-10 15:14:50 -0700114 // Add add user record if the foreground user can add users
jovanak82029ae2018-04-02 16:40:15 -0700115 if (mUserManagerHelper.foregroundUserCanAddUsers()) {
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700116 userRecords.add(addUserRecord());
117 }
118
119 return userRecords;
120 }
121
122 /**
123 * Create guest user record
124 */
125 private UserRecord addGuestUserRecord() {
126 UserInfo userInfo = new UserInfo();
127 userInfo.name = mContext.getString(R.string.car_guest);
jovanak80b48592018-04-11 17:09:53 -0700128 return new UserRecord(userInfo, true /* isStartGuestSession */,
jovanak0535abc2018-04-10 15:14:50 -0700129 false /* isAddUser */, false /* isForeground */);
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700130 }
131
132 /**
133 * Create add user record
134 */
135 private UserRecord addUserRecord() {
136 UserInfo userInfo = new UserInfo();
137 userInfo.name = mContext.getString(R.string.car_add_user);
jovanak80b48592018-04-11 17:09:53 -0700138 return new UserRecord(userInfo, false /* isStartGuestSession */,
jovanak0535abc2018-04-10 15:14:50 -0700139 true /* isAddUser */, false /* isForeground */);
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700140 }
141
142 public void setUserSelectionListener(UserSelectionListener userSelectionListener) {
143 mUserSelectionListener = userSelectionListener;
144 }
145
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700146 @Override
147 public void onUsersUpdate() {
148 mAdapter.clearUsers();
149 mAdapter.updateUsers(createUserRecords(mUserManagerHelper.getAllUsers()));
150 mAdapter.notifyDataSetChanged();
151 }
152
153 /**
154 * Adapter to populate the grid layout with the available user profiles
155 */
Aarthi Balachander0e0e9212018-04-19 19:25:33 -0700156 public final class UserAdapter extends RecyclerView.Adapter<UserAdapter.UserAdapterViewHolder>
157 implements Dialog.OnClickListener {
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700158
159 private final Context mContext;
160 private List<UserRecord> mUsers;
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700161 private final Resources mRes;
162 private final String mGuestName;
163 private final String mNewUserName;
Aarthi Balachander0e0e9212018-04-19 19:25:33 -0700164 private AlertDialog mDialog;
165 // View that holds the add user button. Used to enable/disable the view
166 private View mAddUserView;
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700167
168 public UserAdapter(Context context, List<UserRecord> users) {
169 mRes = context.getResources();
170 mContext = context;
171 updateUsers(users);
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700172 mGuestName = mRes.getString(R.string.car_guest);
173 mNewUserName = mRes.getString(R.string.car_new_user);
174 }
175
176 public void clearUsers() {
177 mUsers.clear();
178 }
179
180 public void updateUsers(List<UserRecord> users) {
181 mUsers = users;
182 }
183
184 @Override
185 public UserAdapterViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
186 View view = LayoutInflater.from(mContext)
187 .inflate(R.layout.car_fullscreen_user_pod, parent, false);
188 view.setAlpha(1f);
189 view.bringToFront();
190 return new UserAdapterViewHolder(view);
191 }
192
193 @Override
194 public void onBindViewHolder(UserAdapterViewHolder holder, int position) {
195 UserRecord userRecord = mUsers.get(position);
jovanake4ce3cc2018-04-19 12:17:12 -0700196 holder.mUserAvatarImageView.setImageBitmap(getUserRecordIcon(userRecord));
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700197 holder.mUserNameTextView.setText(userRecord.mInfo.name);
198 holder.mView.setOnClickListener(v -> {
199 if (userRecord == null) {
200 return;
201 }
202
203 // Notify the listener which user was selected
204 if (mUserSelectionListener != null) {
205 mUserSelectionListener.onUserSelected(userRecord);
206 }
207
jovanak80b48592018-04-11 17:09:53 -0700208 // If the user selects Guest, start the guest session.
209 if (userRecord.mIsStartGuestSession) {
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700210 mUserManagerHelper.switchToGuest(mGuestName);
211 return;
212 }
213
Aarthi Balachander0e0e9212018-04-19 19:25:33 -0700214 // If the user wants to add a user, show dialog to confirm adding a user
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700215 if (userRecord.mIsAddUser) {
Aarthi Balachander0e0e9212018-04-19 19:25:33 -0700216 // Disable button so it cannot be clicked multiple times
217 mAddUserView = holder.mView;
218 mAddUserView.setEnabled(false);
219
220 String message = mRes.getString(R.string.user_add_user_message_setup)
221 .concat(System.getProperty("line.separator"))
222 .concat(System.getProperty("line.separator"))
223 .concat(mRes.getString(R.string.user_add_user_message_update));
224
225 mDialog = new Builder(mContext, R.style.Theme_Car_Dark_Dialog_Alert)
226 .setTitle(R.string.user_add_user_title)
227 .setMessage(message)
228 .setNegativeButton(android.R.string.cancel, this)
229 .setPositiveButton(android.R.string.ok, this)
230 .create();
231 // Sets window flags for the SysUI dialog
232 SystemUIDialog.applyFlags(mDialog);
233 mDialog.show();
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700234 return;
235 }
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700236 // If the user doesn't want to be a guest or add a user, switch to the user selected
237 mUserManagerHelper.switchToUser(userRecord.mInfo);
238 });
239
240 }
241
jovanake4ce3cc2018-04-19 12:17:12 -0700242 private Bitmap getUserRecordIcon(UserRecord userRecord) {
243 if (userRecord.mIsStartGuestSession) {
244 return UserIcons.convertToBitmap(UserIcons.getDefaultUserIcon(
Aarthi Balachander0e0e9212018-04-19 19:25:33 -0700245 mContext.getResources(), UserHandle.USER_NULL, false));
jovanake4ce3cc2018-04-19 12:17:12 -0700246 }
247
248 if (userRecord.mIsAddUser) {
249 return UserIcons.convertToBitmap(mContext
Aarthi Balachander0e0e9212018-04-19 19:25:33 -0700250 .getDrawable(R.drawable.car_add_circle_round));
jovanake4ce3cc2018-04-19 12:17:12 -0700251 }
252
253 return mUserManagerHelper.getUserIcon(userRecord.mInfo);
254 }
255
Aarthi Balachander0e0e9212018-04-19 19:25:33 -0700256 @Override
257 public void onClick(DialogInterface dialog, int which) {
258 // Enable the add button
259 if (mAddUserView != null) {
260 mAddUserView.setEnabled(true);
261 }
262 if (which == BUTTON_POSITIVE) {
263 new AddNewUserTask().execute(mNewUserName);
264 }
265 }
266
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700267 private class AddNewUserTask extends AsyncTask<String, Void, UserInfo> {
268
269 @Override
270 protected UserInfo doInBackground(String... userNames) {
271 return mUserManagerHelper.createNewUser(userNames[0]);
272 }
273
274 @Override
275 protected void onPreExecute() {
276 }
277
278 @Override
279 protected void onPostExecute(UserInfo user) {
280 if (user != null) {
281 mUserManagerHelper.switchToUser(user);
282 }
283 }
284 }
285
286 @Override
287 public int getItemCount() {
288 return mUsers.size();
289 }
290
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700291 public class UserAdapterViewHolder extends RecyclerView.ViewHolder {
292
293 public ImageView mUserAvatarImageView;
294 public TextView mUserNameTextView;
295 public View mView;
296
297 public UserAdapterViewHolder(View view) {
298 super(view);
299 mView = view;
300 mUserAvatarImageView = (ImageView) view.findViewById(R.id.user_avatar);
301 mUserNameTextView = (TextView) view.findViewById(R.id.user_name);
302 }
303 }
304 }
305
306 /**
307 * Object wrapper class for the userInfo. Use it to distinguish if a profile is a
jovanak0535abc2018-04-10 15:14:50 -0700308 * guest profile, add user profile, or the foreground user.
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700309 */
310 public static final class UserRecord {
311
312 public final UserInfo mInfo;
jovanak80b48592018-04-11 17:09:53 -0700313 public final boolean mIsStartGuestSession;
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700314 public final boolean mIsAddUser;
jovanak0535abc2018-04-10 15:14:50 -0700315 public final boolean mIsForeground;
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700316
jovanak80b48592018-04-11 17:09:53 -0700317 public UserRecord(UserInfo userInfo, boolean isStartGuestSession, boolean isAddUser,
jovanak0535abc2018-04-10 15:14:50 -0700318 boolean isForeground) {
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700319 mInfo = userInfo;
jovanak80b48592018-04-11 17:09:53 -0700320 mIsStartGuestSession = isStartGuestSession;
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700321 mIsAddUser = isAddUser;
jovanak0535abc2018-04-10 15:14:50 -0700322 mIsForeground = isForeground;
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -0700323 }
324 }
325
326 /**
327 * Listener used to notify when a user has been selected
328 */
329 interface UserSelectionListener {
330
331 void onUserSelected(UserRecord record);
332 }
333}