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;
784f848c6601f1759689c5318e8d01924ce2f0b2bBraden Walkerimport android.graphics.Color;
884f848c6601f1759689c5318e8d01924ce2f0b2bBraden Walkerimport android.graphics.PorterDuff;
984f848c6601f1759689c5318e8d01924ce2f0b2bBraden Walkerimport android.graphics.drawable.Drawable;
104db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Caoimport android.graphics.drawable.StateListDrawable;
11b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Linimport android.net.Uri;
124db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Caoimport android.support.annotation.DrawableRes;
134db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Caoimport android.support.annotation.IdRes;
144ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Caoimport android.support.annotation.LayoutRes;
15e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedyimport android.support.annotation.Nullable;
166f86e3b4ab4137d43769d78abd9a45ed84e6e50dScott Kennedyimport android.support.v4.view.MarginLayoutParamsCompat;
17e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedyimport android.text.SpannableStringBuilder;
18e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedyimport android.text.Spanned;
19b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Linimport android.text.TextUtils;
20e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedyimport android.text.style.ForegroundColorSpan;
21b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Linimport android.text.util.Rfc822Tokenizer;
22b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Linimport android.view.LayoutInflater;
23b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Linimport android.view.View;
24f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovicimport android.view.View.OnClickListener;
25b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Linimport android.view.ViewGroup;
266f86e3b4ab4137d43769d78abd9a45ed84e6e50dScott Kennedyimport android.view.ViewGroup.MarginLayoutParams;
27b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Linimport android.widget.ImageView;
28b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Linimport android.widget.TextView;
29b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin
30b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Linimport com.android.ex.chips.Queries.Query;
31b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin
32b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin/**
33b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * A class that inflates and binds the views in the dropdown list from
34b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin * RecipientEditTextView.
35b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin */
36b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Linpublic class DropdownChipLayouter {
37b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    /**
38b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * The type of adapter that is requesting a chip layout.
39b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     */
40b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    public enum AdapterType {
41b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        BASE_RECIPIENT,
42b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        RECIPIENT_ALTERNATES,
43b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        SINGLE_RECIPIENT
44b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    }
45b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin
464db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao    public interface ChipDeleteListener {
474db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao        void onChipDelete();
484db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao    }
494db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao
50f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic    /**
51f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic     * Listener that handles the dismisses of the entries of the
52f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic     * {@link RecipientEntry#ENTRY_TYPE_PERMISSION_REQUEST} type.
53f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic     */
54f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic    public interface PermissionRequestDismissedListener {
55f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic
56f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic        /**
57f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic         * Callback that occurs when user dismisses the item that asks user to grant permissions to
58f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic         * the app.
59f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic         */
60f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic        void onPermissionRequestDismissed();
61f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic    }
62f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic
63b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    private final LayoutInflater mInflater;
64b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    private final Context mContext;
654db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao    private ChipDeleteListener mDeleteListener;
66f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic    private PermissionRequestDismissedListener mPermissionRequestDismissedListener;
67b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    private Query mQuery;
686f86e3b4ab4137d43769d78abd9a45ed84e6e50dScott Kennedy    private int mAutocompleteDividerMarginStart;
69b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin
70b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    public DropdownChipLayouter(LayoutInflater inflater, Context context) {
71b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        mInflater = inflater;
72b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        mContext = context;
736f86e3b4ab4137d43769d78abd9a45ed84e6e50dScott Kennedy        mAutocompleteDividerMarginStart =
746f86e3b4ab4137d43769d78abd9a45ed84e6e50dScott Kennedy                context.getResources().getDimensionPixelOffset(R.dimen.chip_wrapper_start_padding);
75b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    }
76b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin
77b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    public void setQuery(Query query) {
78b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        mQuery = query;
79b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    }
80b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin
814db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao    public void setDeleteListener(ChipDeleteListener listener) {
824db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao        mDeleteListener = listener;
834db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao    }
844db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao
85f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic    public void setPermissionRequestDismissedListener(PermissionRequestDismissedListener listener) {
86f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic        mPermissionRequestDismissedListener = listener;
87f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic    }
88f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic
896f86e3b4ab4137d43769d78abd9a45ed84e6e50dScott Kennedy    public void setAutocompleteDividerMarginStart(int autocompleteDividerMarginStart) {
906f86e3b4ab4137d43769d78abd9a45ed84e6e50dScott Kennedy        mAutocompleteDividerMarginStart = autocompleteDividerMarginStart;
916f86e3b4ab4137d43769d78abd9a45ed84e6e50dScott Kennedy    }
92b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin
93b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    /**
94b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * Layouts and binds recipient information to the view. If convertView is null, inflates a new
95b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * view with getItemLaytout().
96b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     *
97b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * @param convertView The view to bind information to.
98b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * @param parent The parent to bind the view to if we inflate a new view.
99b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * @param entry The recipient entry to get information from.
100b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * @param position The position in the list.
101b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * @param type The adapter type that is requesting the bind.
102b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * @param constraint The constraint typed in the auto complete view.
103b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     *
104b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * @return A view ready to be shown in the drop down list.
105b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     */
106b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    public View bindView(View convertView, ViewGroup parent, RecipientEntry entry, int position,
107b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        AdapterType type, String constraint) {
1084db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao        return bindView(convertView, parent, entry, position, type, constraint, null);
1094db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao    }
1104db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao
1114db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao    /**
1124db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao     * See {@link #bindView(View, ViewGroup, RecipientEntry, int, AdapterType, String)}
1136c3f99e2e9f0f1ada622c7ab25876b69fa82b146Jin Cao     * @param deleteDrawable a {@link android.graphics.drawable.StateListDrawable} representing
1146c3f99e2e9f0f1ada622c7ab25876b69fa82b146Jin Cao     *     the delete icon. android.R.attr.state_activated should map to the delete icon, and the
1156c3f99e2e9f0f1ada622c7ab25876b69fa82b146Jin Cao     *     default state can map to a drawable of your choice (or null for no drawable).
1164db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao     */
1174db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao    public View bindView(View convertView, ViewGroup parent, RecipientEntry entry, int position,
1180d4d806606fa8210ad09430fab3a230a1c4e3681Greg Bullock            AdapterType type, String constraint, StateListDrawable deleteDrawable) {
119b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        // Default to show all the information
120d829c9383940496eedd0ab6027efad36a0ec235cBen Brosbe        CharSequence[] styledResults = getStyledResults(constraint, entry);
121e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy        CharSequence displayName = styledResults[0];
122e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy        CharSequence destination = styledResults[1];
123b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        boolean showImage = true;
124b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        CharSequence destinationType = getDestinationType(entry);
125b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin
1260d4d806606fa8210ad09430fab3a230a1c4e3681Greg Bullock        final View itemView = reuseOrInflateView(convertView, parent, type);
127b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin
128b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        final ViewHolder viewHolder = new ViewHolder(itemView);
129b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin
130f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic        // Hide some information depending on the adapter type.
1310d4d806606fa8210ad09430fab3a230a1c4e3681Greg Bullock        switch (type) {
132b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin            case BASE_RECIPIENT:
133b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                if (TextUtils.isEmpty(displayName) || TextUtils.equals(displayName, destination)) {
134b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                    displayName = destination;
135b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin
136b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                    // We only show the destination for secondary entries, so clear it only for the
137b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                    // first level.
138b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                    if (entry.isFirstLevel()) {
139b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                        destination = null;
140b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                    }
141b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                }
142b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin
143b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                if (!entry.isFirstLevel()) {
144b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                    displayName = null;
145b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                    showImage = false;
146b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                }
147b58c9a621a250c6119be2d5a77164b940a8559b0Jin Cao
148b58c9a621a250c6119be2d5a77164b940a8559b0Jin Cao                // For BASE_RECIPIENT set all top dividers except for the first one to be GONE.
149b58c9a621a250c6119be2d5a77164b940a8559b0Jin Cao                if (viewHolder.topDivider != null) {
150b58c9a621a250c6119be2d5a77164b940a8559b0Jin Cao                    viewHolder.topDivider.setVisibility(position == 0 ? View.VISIBLE : View.GONE);
1516f86e3b4ab4137d43769d78abd9a45ed84e6e50dScott Kennedy                    MarginLayoutParamsCompat.setMarginStart(
1526f86e3b4ab4137d43769d78abd9a45ed84e6e50dScott Kennedy                            (MarginLayoutParams) viewHolder.topDivider.getLayoutParams(),
1536f86e3b4ab4137d43769d78abd9a45ed84e6e50dScott Kennedy                            mAutocompleteDividerMarginStart);
1546f86e3b4ab4137d43769d78abd9a45ed84e6e50dScott Kennedy                }
1550d4d806606fa8210ad09430fab3a230a1c4e3681Greg Bullock                if (viewHolder.bottomDivider != null) {
1566f86e3b4ab4137d43769d78abd9a45ed84e6e50dScott Kennedy                    MarginLayoutParamsCompat.setMarginStart(
1576f86e3b4ab4137d43769d78abd9a45ed84e6e50dScott Kennedy                            (MarginLayoutParams) viewHolder.bottomDivider.getLayoutParams(),
1586f86e3b4ab4137d43769d78abd9a45ed84e6e50dScott Kennedy                            mAutocompleteDividerMarginStart);
159b58c9a621a250c6119be2d5a77164b940a8559b0Jin Cao                }
160b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                break;
161b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin            case RECIPIENT_ALTERNATES:
162b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                if (position != 0) {
163b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                    displayName = null;
164b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                    showImage = false;
165b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                }
166b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                break;
167b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin            case SINGLE_RECIPIENT:
16823f4fd2e3581f29e164d4b62a9095ab1e492c009Michael Berberet                if (!PhoneUtil.isPhoneNumber(entry.getDestination())) {
16923f4fd2e3581f29e164d4b62a9095ab1e492c009Michael Berberet                    destination = Rfc822Tokenizer.tokenize(entry.getDestination())[0].getAddress();
17023f4fd2e3581f29e164d4b62a9095ab1e492c009Michael Berberet                }
171b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                destinationType = null;
172b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        }
173b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin
174b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        // Bind the information to the view
175b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        bindTextToView(displayName, viewHolder.displayNameView);
176b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        bindTextToView(destination, viewHolder.destinationView);
177b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        bindTextToView(destinationType, viewHolder.destinationTypeView);
1780d4d806606fa8210ad09430fab3a230a1c4e3681Greg Bullock        bindIconToView(showImage, entry, viewHolder.imageView, type);
1796c3f99e2e9f0f1ada622c7ab25876b69fa82b146Jin Cao        bindDrawableToDeleteView(deleteDrawable, entry.getDisplayName(), viewHolder.deleteView);
18084f848c6601f1759689c5318e8d01924ce2f0b2bBraden Walker        bindIndicatorToView(
18184f848c6601f1759689c5318e8d01924ce2f0b2bBraden Walker                entry.getIndicatorIconId(), entry.getIndicatorText(), viewHolder.indicatorView);
182f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic        bindPermissionRequestDismissView(viewHolder.permissionRequestDismissView);
183f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic
1840d4d806606fa8210ad09430fab3a230a1c4e3681Greg Bullock        // Hide some view groups depending on the entry type
1850d4d806606fa8210ad09430fab3a230a1c4e3681Greg Bullock        final int entryType = entry.getEntryType();
1860d4d806606fa8210ad09430fab3a230a1c4e3681Greg Bullock        if (entryType == RecipientEntry.ENTRY_TYPE_PERSON) {
1870d4d806606fa8210ad09430fab3a230a1c4e3681Greg Bullock            setViewVisibility(viewHolder.personViewGroup, View.VISIBLE);
1880d4d806606fa8210ad09430fab3a230a1c4e3681Greg Bullock            setViewVisibility(viewHolder.permissionViewGroup, View.GONE);
189e78ad406f0b2ee0d031b71b33e6094a6961f7c79Greg Bullock            setViewVisibility(viewHolder.permissionBottomDivider, View.GONE);
1900d4d806606fa8210ad09430fab3a230a1c4e3681Greg Bullock        } else if (entryType == RecipientEntry.ENTRY_TYPE_PERMISSION_REQUEST) {
1910d4d806606fa8210ad09430fab3a230a1c4e3681Greg Bullock            setViewVisibility(viewHolder.personViewGroup, View.GONE);
1920d4d806606fa8210ad09430fab3a230a1c4e3681Greg Bullock            setViewVisibility(viewHolder.permissionViewGroup, View.VISIBLE);
193e78ad406f0b2ee0d031b71b33e6094a6961f7c79Greg Bullock            setViewVisibility(viewHolder.permissionBottomDivider, View.VISIBLE);
1940d4d806606fa8210ad09430fab3a230a1c4e3681Greg Bullock        }
1950d4d806606fa8210ad09430fab3a230a1c4e3681Greg Bullock
196b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        return itemView;
197b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    }
198b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin
199b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    /**
2004ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao     * Returns a new view with {@link #getItemLayoutResId(AdapterType)}.
201b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     */
2024ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao    public View newView(AdapterType type) {
2034ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao        return mInflater.inflate(getItemLayoutResId(type), null);
204b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    }
205b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin
206b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    /**
207b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * Returns the same view, or inflates a new one if the given view was null.
208b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     */
2090d4d806606fa8210ad09430fab3a230a1c4e3681Greg Bullock    protected View reuseOrInflateView(View convertView, ViewGroup parent, AdapterType type) {
2100d4d806606fa8210ad09430fab3a230a1c4e3681Greg Bullock        int itemLayout = getItemLayoutResId(type);
2110d4d806606fa8210ad09430fab3a230a1c4e3681Greg Bullock        switch (type) {
212b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin            case BASE_RECIPIENT:
213b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin            case RECIPIENT_ALTERNATES:
214b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                break;
215b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin            case SINGLE_RECIPIENT:
2160d4d806606fa8210ad09430fab3a230a1c4e3681Greg Bullock                itemLayout = getAlternateItemLayoutResId(type);
217b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                break;
218b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        }
219b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        return convertView != null ? convertView : mInflater.inflate(itemLayout, parent, false);
220b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    }
221b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin
222b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    /**
223b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * Binds the text to the given text view. If the text was null, hides the text view.
224b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     */
225b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    protected void bindTextToView(CharSequence text, TextView view) {
226b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        if (view == null) {
227b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin            return;
228b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        }
229b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin
230b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        if (text != null) {
231b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin            view.setText(text);
232b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin            view.setVisibility(View.VISIBLE);
233b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        } else {
234b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin            view.setVisibility(View.GONE);
235b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        }
236b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    }
237b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin
238b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    /**
239b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * Binds the avatar icon to the image view. If we don't want to show the image, hides the
240b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * image view.
241b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     */
242b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    protected void bindIconToView(boolean showImage, RecipientEntry entry, ImageView view,
243b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        AdapterType type) {
244b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        if (view == null) {
245b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin            return;
246b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        }
247b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin
248b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        if (showImage) {
249b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin            switch (type) {
250b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                case BASE_RECIPIENT:
251b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                    byte[] photoBytes = entry.getPhotoBytes();
252b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                    if (photoBytes != null && photoBytes.length > 0) {
253b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                        final Bitmap photo = BitmapFactory.decodeByteArray(photoBytes, 0,
254b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                            photoBytes.length);
255b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                        view.setImageBitmap(photo);
256b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                    } else {
257b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                        view.setImageResource(getDefaultPhotoResId());
258b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                    }
259b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                    break;
260b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                case RECIPIENT_ALTERNATES:
261b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                    Uri thumbnailUri = entry.getPhotoThumbnailUri();
262b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                    if (thumbnailUri != null) {
263b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                        // TODO: see if this needs to be done outside the main thread
264b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                        // as it may be too slow to get immediately.
2657a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy                        view.setImageURI(thumbnailUri);
266b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                    } else {
267b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                        view.setImageResource(getDefaultPhotoResId());
268b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                    }
269b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                    break;
270b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                case SINGLE_RECIPIENT:
271b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                default:
272b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin                    break;
273b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin            }
274b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin            view.setVisibility(View.VISIBLE);
275b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        } else {
276b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin            view.setVisibility(View.GONE);
277b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        }
278b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    }
279b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin
2806c3f99e2e9f0f1ada622c7ab25876b69fa82b146Jin Cao    protected void bindDrawableToDeleteView(final StateListDrawable drawable, String recipient,
2816c3f99e2e9f0f1ada622c7ab25876b69fa82b146Jin Cao            ImageView view) {
2824db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao        if (view == null) {
2834db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao            return;
2844db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao        }
2854db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao        if (drawable == null) {
2864db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao            view.setVisibility(View.GONE);
287ffc0111fa742c72f2457cecc1116e4ea3c6c8c6eJin Cao        } else {
2886c3f99e2e9f0f1ada622c7ab25876b69fa82b146Jin Cao            final Resources res = mContext.getResources();
289ffc0111fa742c72f2457cecc1116e4ea3c6c8c6eJin Cao            view.setImageDrawable(drawable);
2906c3f99e2e9f0f1ada622c7ab25876b69fa82b146Jin Cao            view.setContentDescription(
2916c3f99e2e9f0f1ada622c7ab25876b69fa82b146Jin Cao                    res.getString(R.string.dropdown_delete_button_desc, recipient));
292ffc0111fa742c72f2457cecc1116e4ea3c6c8c6eJin Cao            if (mDeleteListener != null) {
293ffc0111fa742c72f2457cecc1116e4ea3c6c8c6eJin Cao                view.setOnClickListener(new View.OnClickListener() {
294ffc0111fa742c72f2457cecc1116e4ea3c6c8c6eJin Cao                    @Override
295ffc0111fa742c72f2457cecc1116e4ea3c6c8c6eJin Cao                    public void onClick(View view) {
296ffc0111fa742c72f2457cecc1116e4ea3c6c8c6eJin Cao                        if (drawable.getCurrent() != null) {
297ffc0111fa742c72f2457cecc1116e4ea3c6c8c6eJin Cao                            mDeleteListener.onChipDelete();
298ffc0111fa742c72f2457cecc1116e4ea3c6c8c6eJin Cao                        }
2994db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao                    }
300ffc0111fa742c72f2457cecc1116e4ea3c6c8c6eJin Cao                });
301ffc0111fa742c72f2457cecc1116e4ea3c6c8c6eJin Cao            }
3024db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao        }
3034db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao    }
3044db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao
305f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic    protected void bindIndicatorToView(
306f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic            @DrawableRes int indicatorIconId, String indicatorText, TextView view) {
30784f848c6601f1759689c5318e8d01924ce2f0b2bBraden Walker        if (view != null) {
308f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic            if (indicatorText != null || indicatorIconId != 0) {
30984f848c6601f1759689c5318e8d01924ce2f0b2bBraden Walker                view.setText(indicatorText);
310f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic                view.setVisibility(View.VISIBLE);
311f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic                final Drawable indicatorIcon;
312f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic                if (indicatorIconId != 0) {
313f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic                    indicatorIcon = mContext.getDrawable(indicatorIconId).mutate();
31484f848c6601f1759689c5318e8d01924ce2f0b2bBraden Walker                    indicatorIcon.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN);
31584f848c6601f1759689c5318e8d01924ce2f0b2bBraden Walker                } else {
316f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic                    indicatorIcon = null;
31784f848c6601f1759689c5318e8d01924ce2f0b2bBraden Walker                }
318f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic                view.setCompoundDrawablesRelativeWithIntrinsicBounds(
319f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic                        indicatorIcon, null, null, null);
32084f848c6601f1759689c5318e8d01924ce2f0b2bBraden Walker            } else {
32184f848c6601f1759689c5318e8d01924ce2f0b2bBraden Walker                view.setVisibility(View.GONE);
32284f848c6601f1759689c5318e8d01924ce2f0b2bBraden Walker            }
32384f848c6601f1759689c5318e8d01924ce2f0b2bBraden Walker        }
32484f848c6601f1759689c5318e8d01924ce2f0b2bBraden Walker    }
32584f848c6601f1759689c5318e8d01924ce2f0b2bBraden Walker
326f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic    protected void bindPermissionRequestDismissView(ImageView view) {
327f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic        if (view == null) {
328f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic            return;
329f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic        }
330f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic        view.setOnClickListener(new OnClickListener() {
331f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic            @Override
332f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic            public void onClick(View v) {
333f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic                if (mPermissionRequestDismissedListener != null) {
334f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic                    mPermissionRequestDismissedListener.onPermissionRequestDismissed();
335f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic                }
336f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic            }
337f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic        });
338f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic    }
339f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic
340f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic    protected void setViewVisibility(View view, int visibility) {
341f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic        if (view != null) {
342f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic            view.setVisibility(visibility);
343f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic        }
344f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic    }
345f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic
346b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    protected CharSequence getDestinationType(RecipientEntry entry) {
347b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        return mQuery.getTypeLabel(mContext.getResources(), entry.getDestinationType(),
348b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin            entry.getDestinationLabel()).toString().toUpperCase();
349b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    }
350b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin
351b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    /**
352b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * Returns a layout id for each item inside auto-complete list.
353b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     *
354b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * Each View must contain two TextViews (for display name and destination) and one ImageView
355b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * (for photo). Ids for those should be available via {@link #getDisplayNameResId()},
356b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * {@link #getDestinationResId()}, and {@link #getPhotoResId()}.
357b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     */
3580d4d806606fa8210ad09430fab3a230a1c4e3681Greg Bullock    protected @LayoutRes int getItemLayoutResId(AdapterType type) {
3590d4d806606fa8210ad09430fab3a230a1c4e3681Greg Bullock        switch (type) {
3604ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao            case BASE_RECIPIENT:
3614ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao                return R.layout.chips_autocomplete_recipient_dropdown_item;
3624ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao            case RECIPIENT_ALTERNATES:
3634ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao                return R.layout.chips_recipient_dropdown_item;
3644ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao            default:
3654ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao                return R.layout.chips_recipient_dropdown_item;
3664ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao        }
367b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    }
368b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin
369b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    /**
370b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * Returns a layout id for each item inside alternate auto-complete list.
371b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     *
372b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * Each View must contain two TextViews (for display name and destination) and one ImageView
373b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * (for photo). Ids for those should be available via {@link #getDisplayNameResId()},
374b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * {@link #getDestinationResId()}, and {@link #getPhotoResId()}.
375b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     */
3764ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao    protected @LayoutRes int getAlternateItemLayoutResId(AdapterType type) {
3774ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao        switch (type) {
3784ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao            case BASE_RECIPIENT:
3794ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao                return R.layout.chips_autocomplete_recipient_dropdown_item;
3804ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao            case RECIPIENT_ALTERNATES:
3814ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao                return R.layout.chips_recipient_dropdown_item;
3824ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao            default:
3834ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao                return R.layout.chips_recipient_dropdown_item;
3844ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao        }
385b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    }
386b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin
387b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    /**
388b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * Returns a resource ID representing an image which should be shown when ther's no relevant
389b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * photo is available.
390b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     */
3914db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao    protected @DrawableRes int getDefaultPhotoResId() {
392b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        return R.drawable.ic_contact_picture;
393b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    }
394b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin
395b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    /**
396f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic     * Returns an id for the ViewGroup in an item View that contains the person ui elements.
397f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic     */
398f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic    protected @IdRes int getPersonGroupResId() {
399f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic        return R.id.chip_person_wrapper;
400f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic    }
401f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic
402f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic    /**
403b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * Returns an id for TextView in an item View for showing a display name. By default
404b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * {@link android.R.id#title} is returned.
405b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     */
4064db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao    protected @IdRes int getDisplayNameResId() {
407b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        return android.R.id.title;
408b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    }
409b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin
410b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    /**
411b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * Returns an id for TextView in an item View for showing a destination
412b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * (an email address or a phone number).
413b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * By default {@link android.R.id#text1} is returned.
414b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     */
4154db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao    protected @IdRes int getDestinationResId() {
416b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        return android.R.id.text1;
417b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    }
418b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin
419b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    /**
420b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * Returns an id for TextView in an item View for showing the type of the destination.
421b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * By default {@link android.R.id#text2} is returned.
422b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     */
4234db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao    protected @IdRes int getDestinationTypeResId() {
424b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        return android.R.id.text2;
425b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    }
426b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin
427b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    /**
428b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * Returns an id for ImageView in an item View for showing photo image for a person. In default
429b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * {@link android.R.id#icon} is returned.
430b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     */
4314db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao    protected @IdRes int getPhotoResId() {
432b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        return android.R.id.icon;
433b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    }
434b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin
435b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    /**
4364db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao     * Returns an id for ImageView in an item View for showing the delete button. In default
4374db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao     * {@link android.R.id#icon1} is returned.
4384db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao     */
4394db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao    protected @IdRes int getDeleteResId() { return android.R.id.icon1; }
4404db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao
4414db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao    /**
442f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic     * Returns an id for the ViewGroup in an item View that contains the request permission ui
443f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic     * elements.
444f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic     */
445f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic    protected @IdRes int getPermissionGroupResId() {
446f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic        return R.id.chip_permission_wrapper;
447f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic    }
448f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic
449f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic    /**
450f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic     * Returns an id for ImageView in an item View for dismissing the permission request. In default
451f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic     * {@link android.R.id#icon2} is returned.
452f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic     */
453f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic    protected @IdRes int getPermissionRequestDismissResId() {
454f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic        return android.R.id.icon2;
455f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic    }
456f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic
457f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic    /**
458d829c9383940496eedd0ab6027efad36a0ec235cBen Brosbe     * Given a constraint and a recipient entry, tries to find the constraint in the name and
459d829c9383940496eedd0ab6027efad36a0ec235cBen Brosbe     * destination in the recipient entry. A foreground font color style will be applied to the
460d829c9383940496eedd0ab6027efad36a0ec235cBen Brosbe     * section that matches the constraint. As soon as a match has been found, no further matches
461d829c9383940496eedd0ab6027efad36a0ec235cBen Brosbe     * are attempted.
462d829c9383940496eedd0ab6027efad36a0ec235cBen Brosbe     *
463d829c9383940496eedd0ab6027efad36a0ec235cBen Brosbe     * @param constraint A string that we will attempt to find within the results.
464d829c9383940496eedd0ab6027efad36a0ec235cBen Brosbe     * @param entry The recipient entry to style results for.
465d829c9383940496eedd0ab6027efad36a0ec235cBen Brosbe     *
466d829c9383940496eedd0ab6027efad36a0ec235cBen Brosbe     * @return An array of CharSequences, the length determined by the length of results. Each
467d829c9383940496eedd0ab6027efad36a0ec235cBen Brosbe     *     CharSequence will either be a styled SpannableString or just the input String.
468d829c9383940496eedd0ab6027efad36a0ec235cBen Brosbe     */
469d829c9383940496eedd0ab6027efad36a0ec235cBen Brosbe    protected CharSequence[] getStyledResults(@Nullable String constraint, RecipientEntry entry) {
470d829c9383940496eedd0ab6027efad36a0ec235cBen Brosbe      return getStyledResults(constraint, entry.getDisplayName(), entry.getDestination());
471d829c9383940496eedd0ab6027efad36a0ec235cBen Brosbe    }
472d829c9383940496eedd0ab6027efad36a0ec235cBen Brosbe
473d829c9383940496eedd0ab6027efad36a0ec235cBen Brosbe    /**
474e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy     * Given a constraint and results, tries to find the constraint in those results, one at a time.
475e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy     * A foreground font color style will be applied to the section that matches the constraint. As
476e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy     * soon as a match has been found, no further matches are attempted.
477e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy     *
478e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy     * @param constraint A string that we will attempt to find within the results.
479e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy     * @param results Strings that may contain the constraint. The order given is the order used to
480e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy     *     search for the constraint.
481e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy     *
482e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy     * @return An array of CharSequences, the length determined by the length of results. Each
483e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy     *     CharSequence will either be a styled SpannableString or just the input String.
484e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy     */
485e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy    protected CharSequence[] getStyledResults(@Nullable String constraint, String... results) {
486e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy        if (isAllWhitespace(constraint)) {
487e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy            return results;
488e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy        }
489e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy
490e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy        CharSequence[] styledResults = new CharSequence[results.length];
491e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy        boolean foundMatch = false;
492e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy        for (int i = 0; i < results.length; i++) {
493e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy            String result = results[i];
494e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy            if (result == null) {
495e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy                continue;
496e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy            }
497e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy
498e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy            if (!foundMatch) {
499e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy                int index = result.toLowerCase().indexOf(constraint.toLowerCase());
500e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy                if (index != -1) {
501e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy                    SpannableStringBuilder styled = SpannableStringBuilder.valueOf(result);
502e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy                    ForegroundColorSpan highlightSpan =
503e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy                            new ForegroundColorSpan(mContext.getResources().getColor(
504e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy                                    R.color.chips_dropdown_text_highlighted));
505e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy                    styled.setSpan(highlightSpan,
506e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy                            index, index + constraint.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
507e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy                    styledResults[i] = styled;
508e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy                    foundMatch = true;
509e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy                    continue;
510e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy                }
511e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy            }
512e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy            styledResults[i] = result;
513e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy        }
514e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy        return styledResults;
515e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy    }
516e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy
517e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy    private static boolean isAllWhitespace(@Nullable String string) {
518e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy        if (TextUtils.isEmpty(string)) {
519e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy            return true;
520e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy        }
521e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy
522e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy        for (int i = 0; i < string.length(); ++i) {
523e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy            if (!Character.isWhitespace(string.charAt(i))) {
524e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy                return false;
525e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy            }
526e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy        }
527e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy
528e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy        return true;
529e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy    }
530e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy
531e5d17d57be3b89a6adb7d429a4cb3cb1fbb422ffScott Kennedy    /**
532b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * A holder class the view. Uses the getters in DropdownChipLayouter to find the id of the
533b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     * corresponding views.
534b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin     */
535b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    protected class ViewHolder {
5360d4d806606fa8210ad09430fab3a230a1c4e3681Greg Bullock        public final ViewGroup personViewGroup;
537b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        public final TextView displayNameView;
538b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        public final TextView destinationView;
539b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        public final TextView destinationTypeView;
54084f848c6601f1759689c5318e8d01924ce2f0b2bBraden Walker        public final TextView indicatorView;
541b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        public final ImageView imageView;
5424db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao        public final ImageView deleteView;
543b58c9a621a250c6119be2d5a77164b940a8559b0Jin Cao        public final View topDivider;
5446f86e3b4ab4137d43769d78abd9a45ed84e6e50dScott Kennedy        public final View bottomDivider;
545e78ad406f0b2ee0d031b71b33e6094a6961f7c79Greg Bullock        public final View permissionBottomDivider;
546b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin
5470d4d806606fa8210ad09430fab3a230a1c4e3681Greg Bullock        public final ViewGroup permissionViewGroup;
548f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic        public final ImageView permissionRequestDismissView;
549f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic
550b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        public ViewHolder(View view) {
5510d4d806606fa8210ad09430fab3a230a1c4e3681Greg Bullock            personViewGroup = (ViewGroup) view.findViewById(getPersonGroupResId());
552b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin            displayNameView = (TextView) view.findViewById(getDisplayNameResId());
553b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin            destinationView = (TextView) view.findViewById(getDestinationResId());
554b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin            destinationTypeView = (TextView) view.findViewById(getDestinationTypeResId());
555b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin            imageView = (ImageView) view.findViewById(getPhotoResId());
5564db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao            deleteView = (ImageView) view.findViewById(getDeleteResId());
557b58c9a621a250c6119be2d5a77164b940a8559b0Jin Cao            topDivider = view.findViewById(R.id.chip_autocomplete_top_divider);
558e78ad406f0b2ee0d031b71b33e6094a6961f7c79Greg Bullock
5596f86e3b4ab4137d43769d78abd9a45ed84e6e50dScott Kennedy            bottomDivider = view.findViewById(R.id.chip_autocomplete_bottom_divider);
560e78ad406f0b2ee0d031b71b33e6094a6961f7c79Greg Bullock            permissionBottomDivider = view.findViewById(R.id.chip_permission_bottom_divider);
561e78ad406f0b2ee0d031b71b33e6094a6961f7c79Greg Bullock
56284f848c6601f1759689c5318e8d01924ce2f0b2bBraden Walker            indicatorView = (TextView) view.findViewById(R.id.chip_indicator_text);
563f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic
5640d4d806606fa8210ad09430fab3a230a1c4e3681Greg Bullock            permissionViewGroup = (ViewGroup) view.findViewById(getPermissionGroupResId());
565f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic            permissionRequestDismissView =
566f1ad4f6dba7c6ea28f529736b8662faa6fb498f8Milos Stankovic                    (ImageView) view.findViewById(getPermissionRequestDismissResId());
567b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin        }
568b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin    }
569b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin}
570