SuggestedMemberListAdapter.java revision 6ae983fc9fff8ec820fd09d0d5b997bcbea31a43
1c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan/*
2c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan * Copyright (C) 2011 The Android Open Source Project
3c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan *
4c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan * Licensed under the Apache License, Version 2.0 (the "License");
5c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan * you may not use this file except in compliance with the License.
6c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan * You may obtain a copy of the License at
7c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan *
8c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan *      http://www.apache.org/licenses/LICENSE-2.0
9c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan *
10c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan * Unless required by applicable law or agreed to in writing, software
11c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan * distributed under the License is distributed on an "AS IS" BASIS,
12c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan * See the License for the specific language governing permissions and
14c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan * limitations under the License.
15c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan */
16c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanpackage com.android.contacts.group;
17c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
18c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport com.android.contacts.R;
19c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport com.android.contacts.group.SuggestedMemberListAdapter.SuggestedMember;
20c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
21c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.content.ContentResolver;
22c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.content.Context;
23c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.database.Cursor;
24c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.graphics.Bitmap;
25c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.graphics.BitmapFactory;
26c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.provider.ContactsContract.CommonDataKinds.Email;
27c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.provider.ContactsContract.CommonDataKinds.Phone;
28c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.provider.ContactsContract.CommonDataKinds.Photo;
29c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.provider.ContactsContract.Contacts.Data;
30c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.provider.ContactsContract.RawContacts;
31c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.provider.ContactsContract.RawContactsEntity;
32c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.text.TextUtils;
33c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.view.LayoutInflater;
34c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.view.View;
35c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.view.ViewGroup;
36c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.widget.ArrayAdapter;
37c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.widget.AutoCompleteTextView;
38c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.widget.Filter;
39c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.widget.ImageView;
40c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.widget.TextView;
41c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
42c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport java.util.ArrayList;
43c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport java.util.Arrays;
44c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport java.util.HashMap;
45c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport java.util.List;
46c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
47c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan/**
48c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan * This adapter provides suggested contacts that can be added to a group for an
49c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan * {@link AutoCompleteTextView} within the group editor.
50c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan */
51c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanpublic class SuggestedMemberListAdapter extends ArrayAdapter<SuggestedMember> {
52c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
53c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    private static final String[] PROJECTION_FILTERED_MEMBERS = new String[] {
54c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        RawContacts._ID,                        // 0
55c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        RawContacts.CONTACT_ID,                 // 1
56c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        RawContacts.DISPLAY_NAME_PRIMARY        // 2
57c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    };
58c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
59c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    private static final int RAW_CONTACT_ID_COLUMN_INDEX = 0;
60c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    private static final int CONTACT_ID_COLUMN_INDEX = 1;
61c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    private static final int DISPLAY_NAME_PRIMARY_COLUMN_INDEX = 2;
62c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
63c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    private static final String[] PROJECTION_MEMBER_DATA = new String[] {
64c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        RawContacts._ID,                        // 0
65c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        RawContacts.CONTACT_ID,                 // 1
66c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        Data.MIMETYPE,                          // 2
67c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        Data.DATA1,                             // 3
68c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        Photo.PHOTO,                            // 4
69c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    };
70c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
71c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    private static final int MIMETYPE_COLUMN_INDEX = 2;
72c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    private static final int DATA_COLUMN_INDEX = 3;
73c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    private static final int PHOTO_COLUMN_INDEX = 4;
74c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
75c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    private Filter mFilter;
76c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    private ContentResolver mContentResolver;
77c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    private LayoutInflater mInflater;
78c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
79c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    private String mAccountType = "";
80c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    private String mAccountName = "";
812b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro    private String mDataSet = "";
82c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
832d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan    // TODO: Make this a Map for better performance when we check if a new contact is in the list
842d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan    // or not
85c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    private List<Long> mExistingMemberContactIds = new ArrayList<Long>();
86c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
87c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    private static final int SUGGESTIONS_LIMIT = 5;
88c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
89c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    public SuggestedMemberListAdapter(Context context, int textViewResourceId) {
90c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        super(context, textViewResourceId);
91c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
92c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    }
93c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
94c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    public void setAccountType(String accountType) {
95c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        mAccountType = accountType;
96c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    }
97c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
98c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    public void setAccountName(String accountName) {
99c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        mAccountName = accountName;
100c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    }
101c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
1022b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro    public void setDataSet(String dataSet) {
1032b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro        mDataSet = dataSet;
1042b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro    }
1052b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro
106c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    public void setContentResolver(ContentResolver resolver) {
107c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        mContentResolver = resolver;
108c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    }
109c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
110c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    public void updateExistingMembersList(List<Long> listContactIds) {
111c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        mExistingMemberContactIds = listContactIds;
112c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    }
113c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
114c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    public void addNewMember(long contactId) {
115c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        mExistingMemberContactIds.add(contactId);
116c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    }
117c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
118c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    public void removeMember(long contactId) {
119c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        if (mExistingMemberContactIds.contains(contactId)) {
120c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            mExistingMemberContactIds.remove(contactId);
121c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        }
122c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    }
123c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
124c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    @Override
125c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    public View getView(int position, View convertView, ViewGroup parent) {
126c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        View result = convertView;
127c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        if (result == null) {
128c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            result = mInflater.inflate(R.layout.group_member_suggestion, parent, false);
129c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        }
130c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        // TODO: Use a viewholder
131c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        SuggestedMember member = getItem(position);
132c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        TextView text1 = (TextView) result.findViewById(R.id.text1);
133c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        TextView text2 = (TextView) result.findViewById(R.id.text2);
134c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        ImageView icon = (ImageView) result.findViewById(R.id.icon);
135c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        text1.setText(member.getDisplayName());
136c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        if (member.hasExtraInfo()) {
137c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            text2.setText(member.getExtraInfo());
138c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        } else {
139c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            text2.setVisibility(View.GONE);
140c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        }
141c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        byte[] byteArray = member.getPhotoByteArray();
142c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        if (byteArray == null) {
143c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            icon.setImageResource(R.drawable.ic_contact_picture);
144c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        }
145c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        else {
146c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            Bitmap bitmap = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length);
147c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            icon.setImageBitmap(bitmap);
148c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        }
149c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        return result;
150c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    }
151c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
152c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    @Override
153c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    public Filter getFilter() {
154c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        if (mFilter == null) {
155c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            mFilter = new SuggestedMemberFilter();
156c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        }
157c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        return mFilter;
158c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    }
159c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
160c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    /**
161c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan     * This filter queries for raw contacts that match the given account name and account type,
162c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan     * as well as the search query.
163c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan     */
164c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    public class SuggestedMemberFilter extends Filter {
165c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
166c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        @Override
167c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        protected FilterResults performFiltering(CharSequence prefix) {
168c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            FilterResults results = new FilterResults();
169c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            if (mContentResolver == null || TextUtils.isEmpty(prefix)) {
170c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                return results;
171c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            }
172c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
173c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            // Map of raw contact IDs to {@link SuggestedMember} objects
174c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            HashMap<Long, SuggestedMember> suggestionsMap = new HashMap<Long, SuggestedMember>();
175c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
176c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            // First query for all the raw contacts that match the given search query
177c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            // and have the same account name and type as specified in this adapter
178c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            String searchQuery = prefix.toString() + "%";
1792b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            String accountClause = RawContacts.ACCOUNT_NAME + "=? AND " +
1802b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                    RawContacts.ACCOUNT_TYPE + "=?";
1812b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            String[] args;
1822b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            if (mDataSet == null) {
1832b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                accountClause += " AND " + RawContacts.DATA_SET + " IS NULL";
1842b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                args = new String[] {mAccountName, mAccountType, searchQuery, searchQuery};
1852b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            } else {
1862b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                accountClause += " AND " + RawContacts.DATA_SET + "=?";
1872b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                args = new String[] {
1882b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                        mAccountName, mAccountType, mDataSet, searchQuery, searchQuery
1892b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                };
1902b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            }
1912b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro
192c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            Cursor cursor = mContentResolver.query(
193c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    RawContacts.CONTENT_URI, PROJECTION_FILTERED_MEMBERS,
1942b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                    accountClause + " AND (" +
195c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    RawContacts.DISPLAY_NAME_PRIMARY + " LIKE ? OR " +
196c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    RawContacts.DISPLAY_NAME_ALTERNATIVE + " LIKE ? )",
1972b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                    args, null);
198c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
199c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            if (cursor == null) {
200c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                return results;
201c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            }
202c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
203c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            // Read back the results from the cursor and filter out existing group members.
204c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            // For valid suggestions, add them to the hash map of suggested members.
205c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            try {
206c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                cursor.moveToPosition(-1);
207c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                while (cursor.moveToNext() && suggestionsMap.keySet().size() < SUGGESTIONS_LIMIT) {
2082d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan                    long rawContactId = cursor.getLong(RAW_CONTACT_ID_COLUMN_INDEX);
209c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    long contactId = cursor.getLong(CONTACT_ID_COLUMN_INDEX);
210c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    // Filter out contacts that have already been added to this group
211c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    if (mExistingMemberContactIds.contains(contactId)) {
212c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                        continue;
213c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    }
214c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    // Otherwise, add the contact as a suggested new group member
215c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    String displayName = cursor.getString(DISPLAY_NAME_PRIMARY_COLUMN_INDEX);
2162d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan                    suggestionsMap.put(rawContactId, new SuggestedMember(rawContactId,
2172d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan                            displayName, contactId));
218c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                }
219c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            } finally {
220c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                cursor.close();
221c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            }
222c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
223c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            int numSuggestions = suggestionsMap.keySet().size();
224c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            if (numSuggestions == 0) {
225c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                return results;
226c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            }
227c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
228c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            // Create a part of the selection string for the next query with the pattern (?, ?, ?)
229c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            // where the number of comma-separated question marks represent the number of raw
230c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            // contact IDs found in the previous query (while respective the SUGGESTION_LIMIT)
231c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            final StringBuilder rawContactIdSelectionBuilder = new StringBuilder();
232c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            final String[] questionMarks = new String[numSuggestions];
233c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            Arrays.fill(questionMarks, "?");
234c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            rawContactIdSelectionBuilder.append(RawContacts._ID + " IN (")
235c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    .append(TextUtils.join(",", questionMarks))
236c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    .append(")");
237c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
238c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            // Construct the selection args based on the raw contact IDs we're interested in
239c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            // (as well as the photo, email, and phone mimetypes)
240c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            List<String> selectionArgs = new ArrayList<String>();
241c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            selectionArgs.add(Photo.CONTENT_ITEM_TYPE);
242c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            selectionArgs.add(Email.CONTENT_ITEM_TYPE);
243c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            selectionArgs.add(Phone.CONTENT_ITEM_TYPE);
244c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            for (Long rawContactId : suggestionsMap.keySet()) {
245c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                selectionArgs.add(String.valueOf(rawContactId));
246c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            }
247c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
248c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            // Perform a second query to retrieve a photo and possibly a phone number or email
249c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            // address for the suggested contact
250c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            Cursor memberDataCursor = mContentResolver.query(
251c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    RawContactsEntity.CONTENT_URI, PROJECTION_MEMBER_DATA,
252c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    "(" + Data.MIMETYPE + "=? OR " + Data.MIMETYPE + "=? OR " + Data.MIMETYPE +
253c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    "=?) AND " + rawContactIdSelectionBuilder.toString(),
254c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    selectionArgs.toArray(new String[0]), null);
255c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
256c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            try {
257c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                memberDataCursor.moveToPosition(-1);
258c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                while (memberDataCursor.moveToNext()) {
259c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    long rawContactId = memberDataCursor.getLong(RAW_CONTACT_ID_COLUMN_INDEX);
260c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    SuggestedMember member = suggestionsMap.get(rawContactId);
261c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    if (member == null) {
262c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                        continue;
263c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    }
264c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    String mimetype = memberDataCursor.getString(MIMETYPE_COLUMN_INDEX);
265c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    if (Photo.CONTENT_ITEM_TYPE.equals(mimetype)) {
266c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                        // Set photo
267c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                        byte[] bitmapArray = memberDataCursor.getBlob(PHOTO_COLUMN_INDEX);
268c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                        member.setPhotoByteArray(bitmapArray);
269c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    } else if (Email.CONTENT_ITEM_TYPE.equals(mimetype) ||
270c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                            Phone.CONTENT_ITEM_TYPE.equals(mimetype)) {
271c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                        // Set at most 1 extra piece of contact info that can be a phone number or
272c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                        // email
273c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                        if (!member.hasExtraInfo()) {
274c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                            String info = memberDataCursor.getString(DATA_COLUMN_INDEX);
275c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                            member.setExtraInfo(info);
276c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                        }
277c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    }
278c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                }
279c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            } finally {
280c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                memberDataCursor.close();
281c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            }
282c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            results.values = suggestionsMap;
283c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            return results;
284c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        }
285c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
286c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        @Override
287c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        protected void publishResults(CharSequence constraint, FilterResults results) {
288c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            HashMap<Long, SuggestedMember> map = (HashMap<Long, SuggestedMember>) results.values;
289c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            if (map == null || map.keySet() == null) {
290c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                return;
291c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            }
292c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
293c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            // Clear out the existing suggestions in this adapter
294c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            clear();
295c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
296c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            // Add all the suggested members to this adapter
297c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            for (SuggestedMember member : map.values()) {
298c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                add(member);
299c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            }
300c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
301c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            notifyDataSetChanged();
302c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        }
303c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    }
304c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
305c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    /**
306c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan     * This represents a single contact that is a suggestion for the user to add to a group.
307c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan     */
3082d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan    // TODO: Merge this with the {@link GroupEditorFragment} Member class once we can find the
3092d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan    // lookup URI for this contact using the autocomplete filter queries
310c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    public class SuggestedMember {
311c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
3122d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan        private long mRawContactId;
313c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        private long mContactId;
314c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        private String mDisplayName;
315c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        private String mExtraInfo;
316c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        private byte[] mPhoto;
317c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
3182d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan        public SuggestedMember(long rawContactId, String displayName, long contactId) {
3192d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan            mRawContactId = rawContactId;
320c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            mDisplayName = displayName;
321c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            mContactId = contactId;
322c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        }
323c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
324c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        public String getDisplayName() {
325c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            return mDisplayName;
326c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        }
327c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
328c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        public String getExtraInfo() {
329c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            return mExtraInfo;
330c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        }
331c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
3322d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan        public long getRawContactId() {
3332d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan            return mRawContactId;
3342d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan        }
3352d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan
336c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        public long getContactId() {
337c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            return mContactId;
338c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        }
339c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
340c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        public byte[] getPhotoByteArray() {
341c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            return mPhoto;
342c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        }
343c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
344c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        public boolean hasExtraInfo() {
345c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            return mExtraInfo != null;
346c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        }
347c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
348c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        /**
349c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan         * Set a phone number or email to distinguish this contact
350c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan         */
351c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        public void setExtraInfo(String info) {
352c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            mExtraInfo = info;
353c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        }
354c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
355c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        public void setPhotoByteArray(byte[] photo) {
356c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            mPhoto = photo;
357c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        }
3586ae983fc9fff8ec820fd09d0d5b997bcbea31a43Makoto Onuki
3596ae983fc9fff8ec820fd09d0d5b997bcbea31a43Makoto Onuki        @Override
3606ae983fc9fff8ec820fd09d0d5b997bcbea31a43Makoto Onuki        public String toString() {
3616ae983fc9fff8ec820fd09d0d5b997bcbea31a43Makoto Onuki            return getDisplayName();
3626ae983fc9fff8ec820fd09d0d5b997bcbea31a43Makoto Onuki        }
363c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    }
364c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan}
365