DropdownChipLayouter.java revision 4ddcdaed9ef5ea83910a0513e87538130270e2e4
1package com.android.ex.chips; 2 3import android.content.Context; 4import android.graphics.Bitmap; 5import android.graphics.BitmapFactory; 6import android.net.Uri; 7import android.support.annotation.LayoutRes; 8import android.text.TextUtils; 9import android.text.util.Rfc822Tokenizer; 10import android.view.LayoutInflater; 11import android.view.View; 12import android.view.ViewGroup; 13import android.widget.ImageView; 14import android.widget.TextView; 15 16import com.android.ex.chips.Queries.Query; 17 18/** 19 * A class that inflates and binds the views in the dropdown list from 20 * RecipientEditTextView. 21 */ 22public class DropdownChipLayouter { 23 /** 24 * The type of adapter that is requesting a chip layout. 25 */ 26 public enum AdapterType { 27 BASE_RECIPIENT, 28 RECIPIENT_ALTERNATES, 29 SINGLE_RECIPIENT 30 } 31 32 private final LayoutInflater mInflater; 33 private final Context mContext; 34 private Query mQuery; 35 36 public DropdownChipLayouter(LayoutInflater inflater, Context context) { 37 mInflater = inflater; 38 mContext = context; 39 } 40 41 public void setQuery(Query query) { 42 mQuery = query; 43 } 44 45 46 /** 47 * Layouts and binds recipient information to the view. If convertView is null, inflates a new 48 * view with getItemLaytout(). 49 * 50 * @param convertView The view to bind information to. 51 * @param parent The parent to bind the view to if we inflate a new view. 52 * @param entry The recipient entry to get information from. 53 * @param position The position in the list. 54 * @param type The adapter type that is requesting the bind. 55 * @param constraint The constraint typed in the auto complete view. 56 * 57 * @return A view ready to be shown in the drop down list. 58 */ 59 public View bindView(View convertView, ViewGroup parent, RecipientEntry entry, int position, 60 AdapterType type, String constraint) { 61 // Default to show all the information 62 String displayName = entry.getDisplayName(); 63 String destination = entry.getDestination(); 64 boolean showImage = true; 65 CharSequence destinationType = getDestinationType(entry); 66 67 final View itemView = reuseOrInflateView(convertView, parent, type); 68 69 final ViewHolder viewHolder = new ViewHolder(itemView); 70 71 // Hide some information depending on the entry type and adapter type 72 switch (type) { 73 case BASE_RECIPIENT: 74 if (TextUtils.isEmpty(displayName) || TextUtils.equals(displayName, destination)) { 75 displayName = destination; 76 77 // We only show the destination for secondary entries, so clear it only for the 78 // first level. 79 if (entry.isFirstLevel()) { 80 destination = null; 81 } 82 } 83 84 if (!entry.isFirstLevel()) { 85 displayName = null; 86 showImage = false; 87 } 88 break; 89 case RECIPIENT_ALTERNATES: 90 if (position != 0) { 91 displayName = null; 92 showImage = false; 93 } 94 break; 95 case SINGLE_RECIPIENT: 96 destination = Rfc822Tokenizer.tokenize(entry.getDestination())[0].getAddress(); 97 destinationType = null; 98 } 99 100 // Bind the information to the view 101 bindTextToView(displayName, viewHolder.displayNameView); 102 bindTextToView(destination, viewHolder.destinationView); 103 bindTextToView(destinationType, viewHolder.destinationTypeView); 104 bindIconToView(showImage, entry, viewHolder.imageView, type); 105 106 return itemView; 107 } 108 109 /** 110 * Returns a new view with {@link #getItemLayoutResId(AdapterType)}. 111 */ 112 public View newView(AdapterType type) { 113 return mInflater.inflate(getItemLayoutResId(type), null); 114 } 115 116 /** 117 * Returns the same view, or inflates a new one if the given view was null. 118 */ 119 protected View reuseOrInflateView(View convertView, ViewGroup parent, AdapterType type) { 120 int itemLayout = getItemLayoutResId(type); 121 switch (type) { 122 case BASE_RECIPIENT: 123 case RECIPIENT_ALTERNATES: 124 break; 125 case SINGLE_RECIPIENT: 126 itemLayout = getAlternateItemLayoutResId(type); 127 break; 128 } 129 return convertView != null ? convertView : mInflater.inflate(itemLayout, parent, false); 130 } 131 132 /** 133 * Binds the text to the given text view. If the text was null, hides the text view. 134 */ 135 protected void bindTextToView(CharSequence text, TextView view) { 136 if (view == null) { 137 return; 138 } 139 140 if (text != null) { 141 view.setText(text); 142 view.setVisibility(View.VISIBLE); 143 } else { 144 view.setVisibility(View.GONE); 145 } 146 } 147 148 /** 149 * Binds the avatar icon to the image view. If we don't want to show the image, hides the 150 * image view. 151 */ 152 protected void bindIconToView(boolean showImage, RecipientEntry entry, ImageView view, 153 AdapterType type) { 154 if (view == null) { 155 return; 156 } 157 158 if (showImage) { 159 switch (type) { 160 case BASE_RECIPIENT: 161 byte[] photoBytes = entry.getPhotoBytes(); 162 if (photoBytes != null && photoBytes.length > 0) { 163 final Bitmap photo = BitmapFactory.decodeByteArray(photoBytes, 0, 164 photoBytes.length); 165 view.setImageBitmap(photo); 166 } else { 167 view.setImageResource(getDefaultPhotoResId()); 168 } 169 break; 170 case RECIPIENT_ALTERNATES: 171 Uri thumbnailUri = entry.getPhotoThumbnailUri(); 172 if (thumbnailUri != null) { 173 // TODO: see if this needs to be done outside the main thread 174 // as it may be too slow to get immediately. 175 view.setImageURI(thumbnailUri); 176 } else { 177 view.setImageResource(getDefaultPhotoResId()); 178 } 179 break; 180 case SINGLE_RECIPIENT: 181 default: 182 break; 183 } 184 view.setVisibility(View.VISIBLE); 185 } else { 186 view.setVisibility(View.GONE); 187 } 188 } 189 190 protected CharSequence getDestinationType(RecipientEntry entry) { 191 return mQuery.getTypeLabel(mContext.getResources(), entry.getDestinationType(), 192 entry.getDestinationLabel()).toString().toUpperCase(); 193 } 194 195 /** 196 * Returns a layout id for each item inside auto-complete list. 197 * 198 * Each View must contain two TextViews (for display name and destination) and one ImageView 199 * (for photo). Ids for those should be available via {@link #getDisplayNameResId()}, 200 * {@link #getDestinationResId()}, and {@link #getPhotoResId()}. 201 */ 202 protected @LayoutRes int getItemLayoutResId(AdapterType type) { 203 switch (type) { 204 case BASE_RECIPIENT: 205 return R.layout.chips_autocomplete_recipient_dropdown_item; 206 case RECIPIENT_ALTERNATES: 207 return R.layout.chips_recipient_dropdown_item; 208 default: 209 return R.layout.chips_recipient_dropdown_item; 210 } 211 } 212 213 /** 214 * Returns a layout id for each item inside alternate auto-complete list. 215 * 216 * Each View must contain two TextViews (for display name and destination) and one ImageView 217 * (for photo). Ids for those should be available via {@link #getDisplayNameResId()}, 218 * {@link #getDestinationResId()}, and {@link #getPhotoResId()}. 219 */ 220 protected @LayoutRes int getAlternateItemLayoutResId(AdapterType type) { 221 switch (type) { 222 case BASE_RECIPIENT: 223 return R.layout.chips_autocomplete_recipient_dropdown_item; 224 case RECIPIENT_ALTERNATES: 225 return R.layout.chips_recipient_dropdown_item; 226 default: 227 return R.layout.chips_recipient_dropdown_item; 228 } 229 } 230 231 /** 232 * Returns a resource ID representing an image which should be shown when ther's no relevant 233 * photo is available. 234 */ 235 protected int getDefaultPhotoResId() { 236 return R.drawable.ic_contact_picture; 237 } 238 239 /** 240 * Returns an id for TextView in an item View for showing a display name. By default 241 * {@link android.R.id#title} is returned. 242 */ 243 protected int getDisplayNameResId() { 244 return android.R.id.title; 245 } 246 247 /** 248 * Returns an id for TextView in an item View for showing a destination 249 * (an email address or a phone number). 250 * By default {@link android.R.id#text1} is returned. 251 */ 252 protected int getDestinationResId() { 253 return android.R.id.text1; 254 } 255 256 /** 257 * Returns an id for TextView in an item View for showing the type of the destination. 258 * By default {@link android.R.id#text2} is returned. 259 */ 260 protected int getDestinationTypeResId() { 261 return android.R.id.text2; 262 } 263 264 /** 265 * Returns an id for ImageView in an item View for showing photo image for a person. In default 266 * {@link android.R.id#icon} is returned. 267 */ 268 protected int getPhotoResId() { 269 return android.R.id.icon; 270 } 271 272 /** 273 * A holder class the view. Uses the getters in DropdownChipLayouter to find the id of the 274 * corresponding views. 275 */ 276 protected class ViewHolder { 277 public final TextView displayNameView; 278 public final TextView destinationView; 279 public final TextView destinationTypeView; 280 public final ImageView imageView; 281 282 public ViewHolder(View view) { 283 displayNameView = (TextView) view.findViewById(getDisplayNameResId()); 284 destinationView = (TextView) view.findViewById(getDestinationResId()); 285 destinationTypeView = (TextView) view.findViewById(getDestinationTypeResId()); 286 imageView = (ImageView) view.findViewById(getPhotoResId()); 287 } 288 } 289} 290