• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package com.android.car.settings.users;
18 
19 import android.car.user.CarUserManagerHelper;
20 import android.content.Context;
21 import android.content.pm.UserInfo;
22 import android.content.res.Resources;
23 import android.graphics.Bitmap;
24 import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
25 import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
26 import android.support.v7.widget.RecyclerView;
27 import android.util.AttributeSet;
28 import android.view.LayoutInflater;
29 import android.view.View;
30 import android.view.ViewGroup;
31 import android.widget.FrameLayout;
32 import android.widget.ImageView;
33 import android.widget.TextView;
34 
35 import androidx.car.widget.PagedListView;
36 
37 import com.android.car.settings.R;
38 import com.android.car.settings.common.BaseFragment;
39 import com.android.car.settings.users.ConfirmCreateNewUserDialog.CancelCreateNewUserListener;
40 import com.android.car.settings.users.ConfirmCreateNewUserDialog.ConfirmCreateNewUserListener;
41 import com.android.internal.util.UserIcons;
42 
43 import java.util.ArrayList;
44 import java.util.List;
45 
46 /**
47  * Displays a GridLayout with icons for the users in the system to allow switching between users.
48  * One of the uses of this is for the lock screen in auto.
49  */
50 public class UserGridRecyclerView extends PagedListView implements
51         CarUserManagerHelper.OnUsersUpdateListener {
52     private UserAdapter mAdapter;
53     private CarUserManagerHelper mCarUserManagerHelper;
54     private Context mContext;
55     private BaseFragment mBaseFragment;
56     public AddNewUserTask mAddNewUserTask;
57     public boolean mEnableAddUserButton;
58 
UserGridRecyclerView(Context context, AttributeSet attrs)59     public UserGridRecyclerView(Context context, AttributeSet attrs) {
60         super(context, attrs);
61         mContext = context;
62         mCarUserManagerHelper = new CarUserManagerHelper(mContext);
63         mEnableAddUserButton = true;
64     }
65 
66     /**
67      * Register listener for any update to the users
68      */
69     @Override
onFinishInflate()70     public void onFinishInflate() {
71         super.onFinishInflate();
72         mCarUserManagerHelper.registerOnUsersUpdateListener(this);
73     }
74 
75     /**
76      * Unregisters listener checking for any change to the users
77      */
78     @Override
onDetachedFromWindow()79     public void onDetachedFromWindow() {
80         super.onDetachedFromWindow();
81         mCarUserManagerHelper.unregisterOnUsersUpdateListener();
82         if (mAddNewUserTask != null) {
83             mAddNewUserTask.cancel(/* mayInterruptIfRunning= */ false);
84         }
85     }
86 
87     /**
88      * Initializes the adapter that populates the grid layout
89      */
buildAdapter()90     public void buildAdapter() {
91         List<UserRecord> userRecords = createUserRecords(mCarUserManagerHelper
92                 .getAllUsers());
93         mAdapter = new UserAdapter(mContext, userRecords);
94         super.setAdapter(mAdapter);
95     }
96 
createUserRecords(List<UserInfo> userInfoList)97     private List<UserRecord> createUserRecords(List<UserInfo> userInfoList) {
98         List<UserRecord> userRecords = new ArrayList<>();
99         for (UserInfo userInfo : userInfoList) {
100             if (userInfo.isGuest()) {
101                 // Don't display guests in the switcher.
102                 continue;
103             }
104             boolean isForeground =
105                     mCarUserManagerHelper.getCurrentForegroundUserId() == userInfo.id;
106             UserRecord record = new UserRecord(userInfo, false /* isStartGuestSession */,
107                     false /* isAddUser */, isForeground);
108             userRecords.add(record);
109         }
110 
111         // Add guest user record if the foreground user is not a guest
112         if (!mCarUserManagerHelper.isForegroundUserGuest()) {
113             userRecords.add(addGuestUserRecord());
114         }
115 
116         // Add "add user" record if the foreground user can add users
117         if (mCarUserManagerHelper.canForegroundUserAddUsers()) {
118             userRecords.add(addUserRecord());
119         }
120 
121         return userRecords;
122     }
123 
124     /**
125      * Show the "Add User" Button
126      */
enableAddUser()127     public void enableAddUser() {
128         mEnableAddUserButton = true;
129         onUsersUpdate();
130     }
131 
132     /**
133      * Hide the "Add User" Button
134      */
disableAddUser()135     public void disableAddUser() {
136         mEnableAddUserButton = false;
137         onUsersUpdate();
138     }
139 
140     /**
141      * Create guest user record
142      */
addGuestUserRecord()143     private UserRecord addGuestUserRecord() {
144         UserInfo userInfo = new UserInfo();
145         userInfo.name = mContext.getString(R.string.user_guest);
146         return new UserRecord(userInfo, true /* isStartGuestSession */,
147                 false /* isAddUser */, false /* isForeground */);
148     }
149 
150     /**
151      * Create add user record
152      */
addUserRecord()153     private UserRecord addUserRecord() {
154         UserInfo userInfo = new UserInfo();
155         userInfo.name = mContext.getString(R.string.user_add_user_menu);
156         return new UserRecord(userInfo, false /* isStartGuestSession */,
157                 true /* isAddUser */, false /* isForeground */);
158     }
159 
setFragment(BaseFragment fragment)160     public void setFragment(BaseFragment fragment) {
161         mBaseFragment = fragment;
162     }
163 
164     @Override
onUsersUpdate()165     public void onUsersUpdate() {
166         // If you can show the add user button, there is no restriction
167         mAdapter.setAddUserRestricted(mEnableAddUserButton ? false : true);
168         mAdapter.clearUsers();
169         mAdapter.updateUsers(createUserRecords(mCarUserManagerHelper
170                 .getAllUsers()));
171         mAdapter.notifyDataSetChanged();
172     }
173 
174     /**
175      * Adapter to populate the grid layout with the available user profiles
176      */
177     public final class UserAdapter extends RecyclerView.Adapter<UserAdapter.UserAdapterViewHolder>
178             implements ConfirmCreateNewUserListener, CancelCreateNewUserListener,
179             AddNewUserTask.AddNewUserListener {
180 
181         private final Context mContext;
182         private List<UserRecord> mUsers;
183         private final Resources mRes;
184         private final String mGuestName;
185         private final String mNewUserName;
186         // View that holds the add user button.  Used to enable/disable the view
187         private View mAddUserView;
188         private float mOpacityDisabled;
189         private float mOpacityEnabled;
190         private boolean mIsAddUserRestricted;
191 
UserAdapter(Context context, List<UserRecord> users)192         public UserAdapter(Context context, List<UserRecord> users) {
193             mRes = context.getResources();
194             mContext = context;
195             updateUsers(users);
196             mGuestName = mRes.getString(R.string.user_guest);
197             mNewUserName = mRes.getString(R.string.user_new_user_name);
198             mOpacityDisabled = mRes.getFloat(R.dimen.opacity_disabled);
199             mOpacityEnabled = mRes.getFloat(R.dimen.opacity_enabled);
200         }
201 
202         /**
203          * Removes all the users from the User Grid.
204          */
clearUsers()205         public void clearUsers() {
206             mUsers.clear();
207         }
208 
209         /**
210          * Refreshes the User Grid with the new List of users.
211          * @param users
212          */
updateUsers(List<UserRecord> users)213         public void updateUsers(List<UserRecord> users) {
214             mUsers = users;
215         }
216 
217         @Override
onCreateViewHolder(ViewGroup parent, int viewType)218         public UserAdapterViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
219             View view = LayoutInflater.from(mContext)
220                     .inflate(R.layout.car_user_switcher_pod, parent, false);
221             view.setAlpha(mOpacityEnabled);
222             view.bringToFront();
223             return new UserAdapterViewHolder(view);
224         }
225 
226         @Override
onBindViewHolder(UserAdapterViewHolder holder, int position)227         public void onBindViewHolder(UserAdapterViewHolder holder, int position) {
228             UserRecord userRecord = mUsers.get(position);
229             RoundedBitmapDrawable circleIcon = RoundedBitmapDrawableFactory.create(mRes,
230                     getUserRecordIcon(userRecord));
231             circleIcon.setCircular(true);
232             holder.mUserAvatarImageView.setImageDrawable(circleIcon);
233             holder.mUserNameTextView.setText(userRecord.mInfo.name);
234 
235             // Show the current user frame if current user
236             if (userRecord.mIsForeground) {
237                 holder.mFrame.setBackgroundResource(R.drawable.car_user_avatar_bg_circle);
238             } else {
239                 holder.mFrame.setBackgroundResource(0);
240             }
241 
242             // If there are restrictions, show a 50% opaque "add user" view
243             if (userRecord.mIsAddUser && mIsAddUserRestricted) {
244                 holder.mView.setAlpha(mOpacityDisabled);
245             } else {
246                 holder.mView.setAlpha(mOpacityEnabled);
247             }
248 
249             holder.mView.setOnClickListener(v -> {
250                 if (userRecord == null) {
251                     return;
252                 }
253 
254                 // If the user selects Guest, start the guest session.
255                 if (userRecord.mIsStartGuestSession) {
256                     mCarUserManagerHelper.startNewGuestSession(mGuestName);
257                     return;
258                 }
259 
260                 // If the user wants to add a user, show dialog to confirm adding a user
261                 if (userRecord.mIsAddUser) {
262                     if (mIsAddUserRestricted) {
263                         mBaseFragment.getFragmentController().showDOBlockingMessage();
264                     } else {
265                         // Disable button so it cannot be clicked multiple times
266                         mAddUserView = holder.mView;
267                         mAddUserView.setEnabled(false);
268 
269                         ConfirmCreateNewUserDialog dialog =
270                                 new ConfirmCreateNewUserDialog();
271                         dialog.setConfirmCreateNewUserListener(this);
272                         dialog.setCancelCreateNewUserListener(this);
273                         if (mBaseFragment != null) {
274                             dialog.show(mBaseFragment);
275                         }
276                     }
277                     return;
278                 }
279                 // If the user doesn't want to be a guest or add a user, switch to the user selected
280                 mCarUserManagerHelper.switchToUser(userRecord.mInfo);
281             });
282 
283         }
284 
285         /**
286          * Specify if adding a user should be restricted.
287          *
288          * @param isAddUserRestricted should adding a user be restricted
289          *
290          */
setAddUserRestricted(boolean isAddUserRestricted)291         public void setAddUserRestricted(boolean isAddUserRestricted) {
292             mIsAddUserRestricted = isAddUserRestricted;
293         }
294 
getUserRecordIcon(UserRecord userRecord)295         private Bitmap getUserRecordIcon(UserRecord userRecord) {
296             if (userRecord.mIsStartGuestSession) {
297                 return mCarUserManagerHelper.getGuestDefaultIcon();
298             }
299 
300             if (userRecord.mIsAddUser) {
301                 return UserIcons.convertToBitmap(mContext
302                     .getDrawable(R.drawable.car_add_circle_round));
303             }
304 
305             return mCarUserManagerHelper.getUserIcon(userRecord.mInfo);
306         }
307 
308         @Override
onCreateNewUserConfirmed()309         public void onCreateNewUserConfirmed() {
310             mAddNewUserTask =
311                     new AddNewUserTask(mCarUserManagerHelper, /* addNewUserListener= */ this);
312             mAddNewUserTask.execute(mNewUserName);
313         }
314 
315         /**
316          * Enable the "add user" button if the user cancels adding an user
317          */
318         @Override
onCreateNewUserCancelled()319         public void onCreateNewUserCancelled() {
320             if (mAddUserView != null) {
321                 mAddUserView.setEnabled(true);
322             }
323         }
324 
325         @Override
onUserAdded()326         public void onUserAdded() {
327             if (mAddUserView != null) {
328                 mAddUserView.setEnabled(true);
329             }
330         }
331 
332         @Override
getItemCount()333         public int getItemCount() {
334             return mUsers.size();
335         }
336 
337         /**
338          * Layout for each individual pod in the Grid RecyclerView
339          */
340         public class UserAdapterViewHolder extends RecyclerView.ViewHolder {
341 
342             public ImageView mUserAvatarImageView;
343             public TextView mUserNameTextView;
344             public View mView;
345             public FrameLayout mFrame;
346 
UserAdapterViewHolder(View view)347             public UserAdapterViewHolder(View view) {
348                 super(view);
349                 mView = view;
350                 mUserAvatarImageView = (ImageView) view.findViewById(R.id.user_avatar);
351                 mUserNameTextView = (TextView) view.findViewById(R.id.user_name);
352                 mFrame = (FrameLayout) view.findViewById(R.id.current_user_frame);
353             }
354         }
355     }
356 
357     /**
358      * Object wrapper class for the userInfo.  Use it to distinguish if a profile is a
359      * guest profile, add user profile, or the foreground user.
360      */
361     public static final class UserRecord {
362 
363         public final UserInfo mInfo;
364         public final boolean mIsStartGuestSession;
365         public final boolean mIsAddUser;
366         public final boolean mIsForeground;
367 
UserRecord(UserInfo userInfo, boolean isStartGuestSession, boolean isAddUser, boolean isForeground)368         public UserRecord(UserInfo userInfo, boolean isStartGuestSession, boolean isAddUser,
369                 boolean isForeground) {
370             mInfo = userInfo;
371             mIsStartGuestSession = isStartGuestSession;
372             mIsAddUser = isAddUser;
373             mIsForeground = isForeground;
374         }
375     }
376 }
377