• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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.settings.dashboard.profileselector;
18 
19 import static android.app.admin.DevicePolicyResources.Strings.Settings.PERSONAL_CATEGORY_HEADER;
20 import static android.app.admin.DevicePolicyResources.Strings.Settings.PRIVATE_CATEGORY_HEADER;
21 import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_CATEGORY_HEADER;
22 
23 import android.app.ActivityManager;
24 import android.app.admin.DevicePolicyManager;
25 import android.app.admin.DevicePolicyResourcesManager;
26 import android.content.Context;
27 import android.content.pm.UserInfo;
28 import android.graphics.drawable.Drawable;
29 import android.os.UserHandle;
30 import android.os.UserManager;
31 import android.util.Log;
32 import android.view.LayoutInflater;
33 import android.view.View;
34 import android.view.ViewGroup;
35 import android.widget.BaseAdapter;
36 import android.widget.ImageView;
37 import android.widget.TextView;
38 
39 import com.android.internal.util.UserIcons;
40 import com.android.internal.widget.RecyclerView;
41 import com.android.settings.R;
42 
43 import java.util.ArrayList;
44 import java.util.List;
45 import java.util.Objects;
46 
47 /**
48  * Adapter for a spinner that shows a list of users.
49  */
50 public class UserAdapter extends BaseAdapter {
51     private static final String TAG = "UserAdapter";
52 
53     /** Holder for user details */
54     public static class UserDetails {
55         private final UserHandle mUserHandle;
56         private final UserManager mUserManager;
57         private final Drawable mIcon;
58         private final String mTitle;
59 
UserDetails(UserHandle userHandle, UserManager um, Context context)60         public UserDetails(UserHandle userHandle, UserManager um, Context context) {
61             mUserHandle = userHandle;
62             mUserManager = um;
63             UserInfo userInfo = um.getUserInfo(mUserHandle.getIdentifier());
64             int tintColor = context.getColor(com.android.internal.R.color.materialColorPrimary);
65 
66             if (userInfo.isManagedProfile()
67                     || (android.os.Flags.allowPrivateProfile()
68                         && android.multiuser.Flags.enablePrivateSpaceFeatures()
69                         && android.multiuser.Flags.handleInterleavedSettingsForPrivateSpace()
70                         && userInfo.isPrivateProfile())) {
71                 mIcon = context.getPackageManager().getUserBadgeForDensityNoBackground(
72                         userHandle, /* density= */ 0);
73                 if (mIcon != null) {
74                     mIcon.setTint(tintColor);
75                 }
76             } else {
77                 mIcon = UserIcons.getDefaultUserIconInColor(context.getResources(), tintColor);
78             }
79             mTitle = getTitle(context);
80         }
81 
getTitle(Context context)82         private String getTitle(Context context) {
83             DevicePolicyManager devicePolicyManager =
84                     Objects.requireNonNull(context.getSystemService(DevicePolicyManager.class));
85             DevicePolicyResourcesManager resources = devicePolicyManager.getResources();
86             int userId = mUserHandle.getIdentifier();
87             if (userId == UserHandle.USER_CURRENT || userId == ActivityManager.getCurrentUser()) {
88                 return resources.getString(PERSONAL_CATEGORY_HEADER,
89                         () -> context.getString(
90                                 com.android.settingslib.R.string.category_personal));
91             } else if (mUserManager.isManagedProfile(userId)) {
92                 return resources.getString(WORK_CATEGORY_HEADER,
93                         () -> context.getString(com.android.settingslib.R.string.category_work));
94             } else if (android.os.Flags.allowPrivateProfile()
95                     && android.multiuser.Flags.enablePrivateSpaceFeatures()
96                     && android.multiuser.Flags.handleInterleavedSettingsForPrivateSpace()
97                     && mUserManager.getUserInfo(userId).isPrivateProfile()) {
98                 return resources.getString(PRIVATE_CATEGORY_HEADER,
99                         () -> context.getString(com.android.settingslib.R.string.category_private));
100             }
101             Log.w(TAG, "title requested for unexpected user id " + userId);
102             return resources.getString(PERSONAL_CATEGORY_HEADER,
103                     () -> context.getString(com.android.settingslib.R.string.category_personal));
104         }
105     }
106 
107     private final ArrayList<UserDetails> mUserDetails;
108     private final LayoutInflater mInflater;
109 
UserAdapter(Context context, ArrayList<UserDetails> users)110     public UserAdapter(Context context, ArrayList<UserDetails> users) {
111         if (users == null) {
112             throw new IllegalArgumentException("A list of user details must be provided");
113         }
114         mUserDetails = users;
115         mInflater = context.getSystemService(LayoutInflater.class);
116     }
117 
getUserHandle(int position)118     public UserHandle getUserHandle(int position) {
119         if (position < 0 || position >= mUserDetails.size()) {
120             return null;
121         }
122         return mUserDetails.get(position).mUserHandle;
123     }
124 
125     @Override
getView(int position, View convertView, ViewGroup parent)126     public View getView(int position, View convertView, ViewGroup parent) {
127         ViewHolder holder;
128         if (convertView != null) {
129             holder = (ViewHolder) convertView.getTag();
130         } else {
131             convertView = mInflater.inflate(R.layout.user_preference, parent, false);
132             holder = new ViewHolder(convertView);
133             convertView.setTag(holder);
134         }
135         bindViewHolder(holder, position);
136         return convertView;
137     }
138 
bindViewHolder(ViewHolder holder, int position)139     private void bindViewHolder(ViewHolder holder, int position) {
140         UserDetails userDetails = getItem(position);
141         holder.getIconView().setImageDrawable(userDetails.mIcon);
142         holder.setTitle(userDetails.mTitle);
143     }
144 
145     @Override
getCount()146     public int getCount() {
147         return mUserDetails.size();
148     }
149 
150     @Override
getItem(int position)151     public UserAdapter.UserDetails getItem(int position) {
152         return mUserDetails.get(position);
153     }
154 
155     @Override
getItemId(int position)156     public long getItemId(int position) {
157         return mUserDetails.get(position).mUserHandle.getIdentifier();
158     }
159 
createRecyclerViewAdapter( OnClickListener onClickListener)160     private RecyclerView.Adapter<ViewHolder> createRecyclerViewAdapter(
161             OnClickListener onClickListener) {
162         return new RecyclerView.Adapter<ViewHolder>() {
163             @Override
164             public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
165                 View view = LayoutInflater.from(parent.getContext())
166                         .inflate(R.layout.user_select_item, parent, false);
167 
168                 return new ViewHolder(view, onClickListener);
169             }
170 
171             @Override
172             public void onBindViewHolder(ViewHolder holder, int position) {
173                 UserAdapter.this.bindViewHolder(holder, position);
174             }
175 
176             @Override
177             public int getItemCount() {
178                 return getCount();
179             }
180         };
181     }
182 
183     /**
184      * Creates a {@link UserAdapter} if there is more than one profile on the device.
185      *
186      * <p> The adapter can be used to populate a spinner that switches between the different
187      * profiles.
188      *
189      * @return a {@link UserAdapter} or null if there is only one profile.
190      */
191     public static UserAdapter createUserSpinnerAdapter(UserManager userManager, Context context) {
192         List<UserHandle> userProfiles = userManager.getUserProfiles();
193         if (userProfiles.size() < 2) {
194             return null;
195         }
196 
197         UserHandle myUserHandle = new UserHandle(UserHandle.myUserId());
198         // The first option should be the current profile
199         userProfiles.remove(myUserHandle);
200         userProfiles.add(0, myUserHandle);
201 
202         return createUserAdapter(userManager, context, userProfiles);
203     }
204 
205     /**
206      * Creates a {@link RecyclerView} adapter which be used to populate a {@link RecyclerView} that
207      * select one of the different profiles.
208      */
209     public static RecyclerView.Adapter<ViewHolder> createUserRecycleViewAdapter(
210             Context context, List<UserHandle> userProfiles, OnClickListener onClickListener) {
211         UserManager systemService = context.getSystemService(UserManager.class);
212         return createUserAdapter(systemService, context, userProfiles)
213                 .createRecyclerViewAdapter(onClickListener);
214     }
215 
216     private static UserAdapter createUserAdapter(
217             UserManager userManager, Context context, List<UserHandle> userProfiles) {
218         updateUserHandlesIfNeeded(userManager, userProfiles);
219         ArrayList<UserDetails> userDetails = new ArrayList<>(userProfiles.size());
220         for (UserHandle userProfile : userProfiles) {
221             userDetails.add(new UserDetails(userProfile, userManager, context));
222         }
223         return new UserAdapter(context, userDetails);
224     }
225 
226     private static void updateUserHandlesIfNeeded(
227             UserManager userManager, List<UserHandle> userProfiles) {
228         for (int i = userProfiles.size() - 1; i >= 0; --i) {
229             if (com.android.settings.Utils.shouldHideUser(userProfiles.get(i), userManager)) {
230                 userProfiles.remove(i);
231             }
232         }
233     }
234 
235     static class ViewHolder extends RecyclerView.ViewHolder {
236         private final ImageView mIconView;
237         private final TextView mTitleView;
238         private final View mButtonView;
239 
240         private ViewHolder(View view) {
241             super(view);
242             mIconView = view.findViewById(android.R.id.icon);
243             mTitleView = view.findViewById(android.R.id.title);
244             mButtonView = view.findViewById(R.id.button);
245         }
246 
247         private ViewHolder(View view, OnClickListener onClickListener) {
248             this(view);
249             if (mButtonView != null) {
250                 mButtonView.setOnClickListener(v -> onClickListener.onClick(getAdapterPosition()));
251             }
252         }
253 
254         private ImageView getIconView() {
255             return mIconView;
256         }
257 
258         private void setTitle(CharSequence title) {
259             mTitleView.setText(title);
260             if (mButtonView != null) {
261                 mButtonView.setContentDescription(title);
262             }
263         }
264     }
265 
266     /**
267      * Interface definition for a callback to be invoked when a user is clicked.
268      */
269     public interface OnClickListener {
270         /**
271          * Called when a user has been clicked.
272          */
273         void onClick(int position);
274     }
275 }
276