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