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