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