DropdownChipLayouter.java revision e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ff
1b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Linpackage com.android.ex.chips; 2b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 3b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Linimport android.content.Context; 46c3f99e2e9f0f1ada622c7ab25876b69fa82b146Jin Caoimport android.content.res.Resources; 5b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Linimport android.graphics.Bitmap; 6b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Linimport android.graphics.BitmapFactory; 74db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Caoimport android.graphics.drawable.StateListDrawable; 8b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Linimport android.net.Uri; 94db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Caoimport android.support.annotation.DrawableRes; 104db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Caoimport android.support.annotation.IdRes; 114ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Caoimport android.support.annotation.LayoutRes; 12e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedyimport android.support.annotation.Nullable; 13e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedyimport android.text.SpannableStringBuilder; 14e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedyimport android.text.Spanned; 15b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Linimport android.text.TextUtils; 16e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedyimport android.text.style.ForegroundColorSpan; 17b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Linimport android.text.util.Rfc822Tokenizer; 18b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Linimport android.view.LayoutInflater; 19b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Linimport android.view.View; 20b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Linimport android.view.ViewGroup; 21b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Linimport android.widget.ImageView; 22b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Linimport android.widget.TextView; 23b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 24b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Linimport com.android.ex.chips.Queries.Query; 25b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 26b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin/** 27b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * A class that inflates and binds the views in the dropdown list from 28b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * RecipientEditTextView. 29b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin */ 30b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Linpublic class DropdownChipLayouter { 31b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin /** 32b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * The type of adapter that is requesting a chip layout. 33b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin */ 34b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin public enum AdapterType { 35b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin BASE_RECIPIENT, 36b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin RECIPIENT_ALTERNATES, 37b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin SINGLE_RECIPIENT 38b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 39b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 404db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao public interface ChipDeleteListener { 414db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao void onChipDelete(); 424db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao } 434db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao 44b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin private final LayoutInflater mInflater; 45b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin private final Context mContext; 464db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao private ChipDeleteListener mDeleteListener; 47b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin private Query mQuery; 48b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 49b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin public DropdownChipLayouter(LayoutInflater inflater, Context context) { 50b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin mInflater = inflater; 51b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin mContext = context; 52b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 53b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 54b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin public void setQuery(Query query) { 55b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin mQuery = query; 56b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 57b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 584db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao public void setDeleteListener(ChipDeleteListener listener) { 594db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao mDeleteListener = listener; 604db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao } 614db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao 62b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 63b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin /** 64b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * Layouts and binds recipient information to the view. If convertView is null, inflates a new 65b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * view with getItemLaytout(). 66b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * 67b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * @param convertView The view to bind information to. 68b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * @param parent The parent to bind the view to if we inflate a new view. 69b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * @param entry The recipient entry to get information from. 70b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * @param position The position in the list. 71b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * @param type The adapter type that is requesting the bind. 72b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * @param constraint The constraint typed in the auto complete view. 73b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * 74b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * @return A view ready to be shown in the drop down list. 75b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin */ 76b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin public View bindView(View convertView, ViewGroup parent, RecipientEntry entry, int position, 77b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin AdapterType type, String constraint) { 784db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao return bindView(convertView, parent, entry, position, type, constraint, null); 794db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao } 804db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao 814db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao /** 824db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao * See {@link #bindView(View, ViewGroup, RecipientEntry, int, AdapterType, String)} 836c3f99e2e9f0f1ada622c7ab25876b69fa82b146Jin Cao * @param deleteDrawable a {@link android.graphics.drawable.StateListDrawable} representing 846c3f99e2e9f0f1ada622c7ab25876b69fa82b146Jin Cao * the delete icon. android.R.attr.state_activated should map to the delete icon, and the 856c3f99e2e9f0f1ada622c7ab25876b69fa82b146Jin Cao * default state can map to a drawable of your choice (or null for no drawable). 864db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao */ 874db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao public View bindView(View convertView, ViewGroup parent, RecipientEntry entry, int position, 884db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao AdapterType type, String constraint, StateListDrawable deleteDrawable) { 89b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin // Default to show all the information 90e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy CharSequence[] styledResults = 91e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy getStyledResults(constraint, entry.getDisplayName(), entry.getDestination()); 92e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy CharSequence displayName = styledResults[0]; 93e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy CharSequence destination = styledResults[1]; 94b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin boolean showImage = true; 95b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin CharSequence destinationType = getDestinationType(entry); 96b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 97b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin final View itemView = reuseOrInflateView(convertView, parent, type); 98b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 99b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin final ViewHolder viewHolder = new ViewHolder(itemView); 100b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 101b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin // Hide some information depending on the entry type and adapter type 102b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin switch (type) { 103b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin case BASE_RECIPIENT: 104b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin if (TextUtils.isEmpty(displayName) || TextUtils.equals(displayName, destination)) { 105b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin displayName = destination; 106b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 107b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin // We only show the destination for secondary entries, so clear it only for the 108b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin // first level. 109b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin if (entry.isFirstLevel()) { 110b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin destination = null; 111b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 112b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 113b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 114b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin if (!entry.isFirstLevel()) { 115b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin displayName = null; 116b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin showImage = false; 117b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 118b58c9a621a250c6119be2d5a77164b940a8559b0Jin Cao 119b58c9a621a250c6119be2d5a77164b940a8559b0Jin Cao // For BASE_RECIPIENT set all top dividers except for the first one to be GONE. 120b58c9a621a250c6119be2d5a77164b940a8559b0Jin Cao if (viewHolder.topDivider != null) { 121b58c9a621a250c6119be2d5a77164b940a8559b0Jin Cao viewHolder.topDivider.setVisibility(position == 0 ? View.VISIBLE : View.GONE); 122b58c9a621a250c6119be2d5a77164b940a8559b0Jin Cao } 123b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin break; 124b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin case RECIPIENT_ALTERNATES: 125b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin if (position != 0) { 126b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin displayName = null; 127b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin showImage = false; 128b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 129b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin break; 130b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin case SINGLE_RECIPIENT: 131b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin destination = Rfc822Tokenizer.tokenize(entry.getDestination())[0].getAddress(); 132b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin destinationType = null; 133b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 134b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 135b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin // Bind the information to the view 136b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin bindTextToView(displayName, viewHolder.displayNameView); 137b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin bindTextToView(destination, viewHolder.destinationView); 138b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin bindTextToView(destinationType, viewHolder.destinationTypeView); 139b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin bindIconToView(showImage, entry, viewHolder.imageView, type); 1406c3f99e2e9f0f1ada622c7ab25876b69fa82b146Jin Cao bindDrawableToDeleteView(deleteDrawable, entry.getDisplayName(), viewHolder.deleteView); 141b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 142b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin return itemView; 143b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 144b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 145b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin /** 1464ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao * Returns a new view with {@link #getItemLayoutResId(AdapterType)}. 147b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin */ 1484ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao public View newView(AdapterType type) { 1494ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao return mInflater.inflate(getItemLayoutResId(type), null); 150b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 151b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 152b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin /** 153b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * Returns the same view, or inflates a new one if the given view was null. 154b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin */ 155b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin protected View reuseOrInflateView(View convertView, ViewGroup parent, AdapterType type) { 1564ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao int itemLayout = getItemLayoutResId(type); 157b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin switch (type) { 158b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin case BASE_RECIPIENT: 159b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin case RECIPIENT_ALTERNATES: 160b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin break; 161b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin case SINGLE_RECIPIENT: 1624ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao itemLayout = getAlternateItemLayoutResId(type); 163b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin break; 164b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 165b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin return convertView != null ? convertView : mInflater.inflate(itemLayout, parent, false); 166b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 167b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 168b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin /** 169b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * Binds the text to the given text view. If the text was null, hides the text view. 170b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin */ 171b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin protected void bindTextToView(CharSequence text, TextView view) { 172b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin if (view == null) { 173b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin return; 174b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 175b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 176b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin if (text != null) { 177b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin view.setText(text); 178b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin view.setVisibility(View.VISIBLE); 179b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } else { 180b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin view.setVisibility(View.GONE); 181b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 182b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 183b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 184b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin /** 185b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * Binds the avatar icon to the image view. If we don't want to show the image, hides the 186b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * image view. 187b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin */ 188b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin protected void bindIconToView(boolean showImage, RecipientEntry entry, ImageView view, 189b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin AdapterType type) { 190b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin if (view == null) { 191b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin return; 192b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 193b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 194b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin if (showImage) { 195b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin switch (type) { 196b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin case BASE_RECIPIENT: 197b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin byte[] photoBytes = entry.getPhotoBytes(); 198b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin if (photoBytes != null && photoBytes.length > 0) { 199b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin final Bitmap photo = BitmapFactory.decodeByteArray(photoBytes, 0, 200b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin photoBytes.length); 201b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin view.setImageBitmap(photo); 202b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } else { 203b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin view.setImageResource(getDefaultPhotoResId()); 204b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 205b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin break; 206b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin case RECIPIENT_ALTERNATES: 207b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin Uri thumbnailUri = entry.getPhotoThumbnailUri(); 208b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin if (thumbnailUri != null) { 209b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin // TODO: see if this needs to be done outside the main thread 210b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin // as it may be too slow to get immediately. 2117a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy view.setImageURI(thumbnailUri); 212b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } else { 213b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin view.setImageResource(getDefaultPhotoResId()); 214b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 215b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin break; 216b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin case SINGLE_RECIPIENT: 217b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin default: 218b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin break; 219b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 220b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin view.setVisibility(View.VISIBLE); 221b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } else { 222b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin view.setVisibility(View.GONE); 223b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 224b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 225b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 2266c3f99e2e9f0f1ada622c7ab25876b69fa82b146Jin Cao protected void bindDrawableToDeleteView(final StateListDrawable drawable, String recipient, 2276c3f99e2e9f0f1ada622c7ab25876b69fa82b146Jin Cao ImageView view) { 2284db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao if (view == null) { 2294db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao return; 2304db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao } 2314db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao if (drawable == null) { 2324db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao view.setVisibility(View.GONE); 233ffc0111fa742c72f2457cecc1116e4ea3c6c8c6eJin Cao } else { 2346c3f99e2e9f0f1ada622c7ab25876b69fa82b146Jin Cao final Resources res = mContext.getResources(); 235ffc0111fa742c72f2457cecc1116e4ea3c6c8c6eJin Cao view.setImageDrawable(drawable); 2366c3f99e2e9f0f1ada622c7ab25876b69fa82b146Jin Cao view.setContentDescription( 2376c3f99e2e9f0f1ada622c7ab25876b69fa82b146Jin Cao res.getString(R.string.dropdown_delete_button_desc, recipient)); 238ffc0111fa742c72f2457cecc1116e4ea3c6c8c6eJin Cao if (mDeleteListener != null) { 239ffc0111fa742c72f2457cecc1116e4ea3c6c8c6eJin Cao view.setOnClickListener(new View.OnClickListener() { 240ffc0111fa742c72f2457cecc1116e4ea3c6c8c6eJin Cao @Override 241ffc0111fa742c72f2457cecc1116e4ea3c6c8c6eJin Cao public void onClick(View view) { 242ffc0111fa742c72f2457cecc1116e4ea3c6c8c6eJin Cao if (drawable.getCurrent() != null) { 243ffc0111fa742c72f2457cecc1116e4ea3c6c8c6eJin Cao mDeleteListener.onChipDelete(); 244ffc0111fa742c72f2457cecc1116e4ea3c6c8c6eJin Cao } 2454db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao } 246ffc0111fa742c72f2457cecc1116e4ea3c6c8c6eJin Cao }); 247ffc0111fa742c72f2457cecc1116e4ea3c6c8c6eJin Cao } 2484db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao } 2494db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao } 2504db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao 251b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin protected CharSequence getDestinationType(RecipientEntry entry) { 252b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin return mQuery.getTypeLabel(mContext.getResources(), entry.getDestinationType(), 253b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin entry.getDestinationLabel()).toString().toUpperCase(); 254b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 255b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 256b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin /** 257b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * Returns a layout id for each item inside auto-complete list. 258b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * 259b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * Each View must contain two TextViews (for display name and destination) and one ImageView 260b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * (for photo). Ids for those should be available via {@link #getDisplayNameResId()}, 261b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * {@link #getDestinationResId()}, and {@link #getPhotoResId()}. 262b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin */ 2634ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao protected @LayoutRes int getItemLayoutResId(AdapterType type) { 2644ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao switch (type) { 2654ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao case BASE_RECIPIENT: 2664ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao return R.layout.chips_autocomplete_recipient_dropdown_item; 2674ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao case RECIPIENT_ALTERNATES: 2684ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao return R.layout.chips_recipient_dropdown_item; 2694ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao default: 2704ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao return R.layout.chips_recipient_dropdown_item; 2714ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao } 272b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 273b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 274b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin /** 275b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * Returns a layout id for each item inside alternate auto-complete list. 276b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * 277b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * Each View must contain two TextViews (for display name and destination) and one ImageView 278b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * (for photo). Ids for those should be available via {@link #getDisplayNameResId()}, 279b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * {@link #getDestinationResId()}, and {@link #getPhotoResId()}. 280b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin */ 2814ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao protected @LayoutRes int getAlternateItemLayoutResId(AdapterType type) { 2824ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao switch (type) { 2834ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao case BASE_RECIPIENT: 2844ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao return R.layout.chips_autocomplete_recipient_dropdown_item; 2854ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao case RECIPIENT_ALTERNATES: 2864ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao return R.layout.chips_recipient_dropdown_item; 2874ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao default: 2884ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao return R.layout.chips_recipient_dropdown_item; 2894ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao } 290b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 291b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 292b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin /** 293b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * Returns a resource ID representing an image which should be shown when ther's no relevant 294b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * photo is available. 295b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin */ 2964db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao protected @DrawableRes int getDefaultPhotoResId() { 297b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin return R.drawable.ic_contact_picture; 298b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 299b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 300b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin /** 301b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * Returns an id for TextView in an item View for showing a display name. By default 302b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * {@link android.R.id#title} is returned. 303b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin */ 3044db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao protected @IdRes int getDisplayNameResId() { 305b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin return android.R.id.title; 306b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 307b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 308b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin /** 309b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * Returns an id for TextView in an item View for showing a destination 310b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * (an email address or a phone number). 311b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * By default {@link android.R.id#text1} is returned. 312b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin */ 3134db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao protected @IdRes int getDestinationResId() { 314b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin return android.R.id.text1; 315b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 316b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 317b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin /** 318b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * Returns an id for TextView in an item View for showing the type of the destination. 319b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * By default {@link android.R.id#text2} is returned. 320b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin */ 3214db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao protected @IdRes int getDestinationTypeResId() { 322b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin return android.R.id.text2; 323b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 324b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 325b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin /** 326b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * Returns an id for ImageView in an item View for showing photo image for a person. In default 327b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * {@link android.R.id#icon} is returned. 328b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin */ 3294db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao protected @IdRes int getPhotoResId() { 330b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin return android.R.id.icon; 331b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 332b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 333b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin /** 3344db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao * Returns an id for ImageView in an item View for showing the delete button. In default 3354db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao * {@link android.R.id#icon1} is returned. 3364db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao */ 3374db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao protected @IdRes int getDeleteResId() { return android.R.id.icon1; } 3384db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao 3394db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao /** 340e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy * Given a constraint and results, tries to find the constraint in those results, one at a time. 341e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy * A foreground font color style will be applied to the section that matches the constraint. As 342e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy * soon as a match has been found, no further matches are attempted. 343e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy * 344e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy * @param constraint A string that we will attempt to find within the results. 345e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy * @param results Strings that may contain the constraint. The order given is the order used to 346e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy * search for the constraint. 347e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy * 348e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy * @return An array of CharSequences, the length determined by the length of results. Each 349e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy * CharSequence will either be a styled SpannableString or just the input String. 350e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy */ 351e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy protected CharSequence[] getStyledResults(@Nullable String constraint, String... results) { 352e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy if (isAllWhitespace(constraint)) { 353e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy return results; 354e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy } 355e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy 356e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy CharSequence[] styledResults = new CharSequence[results.length]; 357e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy boolean foundMatch = false; 358e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy for (int i = 0; i < results.length; i++) { 359e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy String result = results[i]; 360e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy if (result == null) { 361e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy continue; 362e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy } 363e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy 364e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy if (!foundMatch) { 365e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy int index = result.toLowerCase().indexOf(constraint.toLowerCase()); 366e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy if (index != -1) { 367e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy SpannableStringBuilder styled = SpannableStringBuilder.valueOf(result); 368e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy ForegroundColorSpan highlightSpan = 369e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy new ForegroundColorSpan(mContext.getResources().getColor( 370e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy R.color.chips_dropdown_text_highlighted)); 371e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy styled.setSpan(highlightSpan, 372e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy index, index + constraint.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 373e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy styledResults[i] = styled; 374e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy foundMatch = true; 375e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy continue; 376e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy } 377e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy } 378e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy styledResults[i] = result; 379e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy } 380e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy return styledResults; 381e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy } 382e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy 383e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy private static boolean isAllWhitespace(@Nullable String string) { 384e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy if (TextUtils.isEmpty(string)) { 385e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy return true; 386e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy } 387e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy 388e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy for (int i = 0; i < string.length(); ++i) { 389e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy if (!Character.isWhitespace(string.charAt(i))) { 390e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy return false; 391e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy } 392e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy } 393e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy 394e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy return true; 395e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy } 396e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy 397e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy /** 398b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * A holder class the view. Uses the getters in DropdownChipLayouter to find the id of the 399b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * corresponding views. 400b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin */ 401b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin protected class ViewHolder { 402b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin public final TextView displayNameView; 403b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin public final TextView destinationView; 404b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin public final TextView destinationTypeView; 405b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin public final ImageView imageView; 4064db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao public final ImageView deleteView; 407b58c9a621a250c6119be2d5a77164b940a8559b0Jin Cao public final View topDivider; 408b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 409b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin public ViewHolder(View view) { 410b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin displayNameView = (TextView) view.findViewById(getDisplayNameResId()); 411b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin destinationView = (TextView) view.findViewById(getDestinationResId()); 412b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin destinationTypeView = (TextView) view.findViewById(getDestinationTypeResId()); 413b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin imageView = (ImageView) view.findViewById(getPhotoResId()); 4144db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao deleteView = (ImageView) view.findViewById(getDeleteResId()); 415b58c9a621a250c6119be2d5a77164b940a8559b0Jin Cao topDivider = view.findViewById(R.id.chip_autocomplete_top_divider); 416b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 417b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin } 418b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin} 419