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