SuggestedMemberListAdapter.java revision 13c42f4ebb1c7f31750262946ce3b390c93d5320
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 android.content.ContentResolver;
19c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.content.Context;
20c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.database.Cursor;
21c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.graphics.Bitmap;
22c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.graphics.BitmapFactory;
23c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.provider.ContactsContract.CommonDataKinds.Email;
24c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.provider.ContactsContract.CommonDataKinds.Phone;
25c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.provider.ContactsContract.CommonDataKinds.Photo;
26c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.provider.ContactsContract.Contacts.Data;
27c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.provider.ContactsContract.RawContacts;
28c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.provider.ContactsContract.RawContactsEntity;
29c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.text.TextUtils;
30c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.view.LayoutInflater;
31c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.view.View;
32c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.view.ViewGroup;
33c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.widget.ArrayAdapter;
34c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.widget.AutoCompleteTextView;
35c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.widget.Filter;
36c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.widget.ImageView;
37c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport android.widget.TextView;
38c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
39e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.R;
40e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.group.SuggestedMemberListAdapter.SuggestedMember;
41e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Cheng
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
79f75900ed2bafa5411c46e8fde0b8dccbc6753176Makoto Onuki    private String mAccountType;
80f75900ed2bafa5411c46e8fde0b8dccbc6753176Makoto Onuki    private String mAccountName;
81f75900ed2bafa5411c46e8fde0b8dccbc6753176Makoto Onuki    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
85f81b6d9ba129f0220de93aa9a7426547889755c3Makoto Onuki    private final 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
110f81b6d9ba129f0220de93aa9a7426547889755c3Makoto Onuki    public void updateExistingMembersList(List<GroupEditorFragment.Member> list) {
111f81b6d9ba129f0220de93aa9a7426547889755c3Makoto Onuki        mExistingMemberContactIds.clear();
112f81b6d9ba129f0220de93aa9a7426547889755c3Makoto Onuki        for (GroupEditorFragment.Member member : list) {
113f81b6d9ba129f0220de93aa9a7426547889755c3Makoto Onuki            mExistingMemberContactIds.add(member.getContactId());
114f81b6d9ba129f0220de93aa9a7426547889755c3Makoto Onuki        }
115c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    }
116c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
117c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    public void addNewMember(long contactId) {
118c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        mExistingMemberContactIds.add(contactId);
119c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    }
120c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
121c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    public void removeMember(long contactId) {
122c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        if (mExistingMemberContactIds.contains(contactId)) {
123c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            mExistingMemberContactIds.remove(contactId);
124c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        }
125c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    }
126c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
127c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    @Override
128c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    public View getView(int position, View convertView, ViewGroup parent) {
129c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        View result = convertView;
130c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        if (result == null) {
131c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            result = mInflater.inflate(R.layout.group_member_suggestion, parent, false);
132c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        }
133c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        // TODO: Use a viewholder
134c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        SuggestedMember member = getItem(position);
135c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        TextView text1 = (TextView) result.findViewById(R.id.text1);
136c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        TextView text2 = (TextView) result.findViewById(R.id.text2);
137c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        ImageView icon = (ImageView) result.findViewById(R.id.icon);
138c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        text1.setText(member.getDisplayName());
139c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        if (member.hasExtraInfo()) {
140c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            text2.setText(member.getExtraInfo());
141c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        } else {
142c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            text2.setVisibility(View.GONE);
143c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        }
144c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        byte[] byteArray = member.getPhotoByteArray();
145c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        if (byteArray == null) {
146ecfc26c3f9495f1a4efed69a1582ff2b0deb2c71Daniel Lehmann            icon.setImageResource(R.drawable.ic_contact_picture_holo_light);
14759b46720e92799a29d84e6e31fb3eeea60166f0dMakoto Onuki        } else {
148c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            Bitmap bitmap = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length);
149c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            icon.setImageBitmap(bitmap);
150c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        }
15159b46720e92799a29d84e6e31fb3eeea60166f0dMakoto Onuki        result.setTag(member);
152c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        return result;
153c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    }
154c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
155c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    @Override
156c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    public Filter getFilter() {
157c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        if (mFilter == null) {
158c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            mFilter = new SuggestedMemberFilter();
159c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        }
160c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        return mFilter;
161c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    }
162c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
163c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    /**
164c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan     * This filter queries for raw contacts that match the given account name and account type,
165c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan     * as well as the search query.
166c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan     */
167c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    public class SuggestedMemberFilter extends Filter {
168c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
169c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        @Override
170c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        protected FilterResults performFiltering(CharSequence prefix) {
171c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            FilterResults results = new FilterResults();
172c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            if (mContentResolver == null || TextUtils.isEmpty(prefix)) {
173c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                return results;
174c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            }
175c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
176de4e404bd88cb60a8286e17383a49534efcc0e56Katherine Kuan            // Create a list to store the suggested contacts (which will be alphabetically ordered),
177de4e404bd88cb60a8286e17383a49534efcc0e56Katherine Kuan            // but also keep a map of raw contact IDs to {@link SuggestedMember}s to make it easier
178de4e404bd88cb60a8286e17383a49534efcc0e56Katherine Kuan            // to add supplementary data to the contact (photo, phone, email) to the members based
179de4e404bd88cb60a8286e17383a49534efcc0e56Katherine Kuan            // on raw contact IDs after the second query is completed.
180de4e404bd88cb60a8286e17383a49534efcc0e56Katherine Kuan            List<SuggestedMember> suggestionsList = new ArrayList<SuggestedMember>();
181c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            HashMap<Long, SuggestedMember> suggestionsMap = new HashMap<Long, SuggestedMember>();
182c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
183c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            // First query for all the raw contacts that match the given search query
184c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            // and have the same account name and type as specified in this adapter
185c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            String searchQuery = prefix.toString() + "%";
1862b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            String accountClause = RawContacts.ACCOUNT_NAME + "=? AND " +
1872b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                    RawContacts.ACCOUNT_TYPE + "=?";
1882b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            String[] args;
1892b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            if (mDataSet == null) {
1902b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                accountClause += " AND " + RawContacts.DATA_SET + " IS NULL";
1912b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                args = new String[] {mAccountName, mAccountType, searchQuery, searchQuery};
1922b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            } else {
1932b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                accountClause += " AND " + RawContacts.DATA_SET + "=?";
1942b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                args = new String[] {
1952b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                        mAccountName, mAccountType, mDataSet, searchQuery, searchQuery
1962b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                };
1972b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            }
1982b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro
199c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            Cursor cursor = mContentResolver.query(
200c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    RawContacts.CONTENT_URI, PROJECTION_FILTERED_MEMBERS,
2012b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                    accountClause + " AND (" +
202c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    RawContacts.DISPLAY_NAME_PRIMARY + " LIKE ? OR " +
203c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    RawContacts.DISPLAY_NAME_ALTERNATIVE + " LIKE ? )",
204de4e404bd88cb60a8286e17383a49534efcc0e56Katherine Kuan                    args, RawContacts.DISPLAY_NAME_PRIMARY + " COLLATE LOCALIZED ASC");
205c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
206c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            if (cursor == null) {
207c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                return results;
208c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            }
209c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
210c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            // Read back the results from the cursor and filter out existing group members.
211c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            // For valid suggestions, add them to the hash map of suggested members.
212c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            try {
213c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                cursor.moveToPosition(-1);
214c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                while (cursor.moveToNext() && suggestionsMap.keySet().size() < SUGGESTIONS_LIMIT) {
2152d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan                    long rawContactId = cursor.getLong(RAW_CONTACT_ID_COLUMN_INDEX);
216c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    long contactId = cursor.getLong(CONTACT_ID_COLUMN_INDEX);
217c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    // Filter out contacts that have already been added to this group
218c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    if (mExistingMemberContactIds.contains(contactId)) {
219c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                        continue;
220c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    }
221c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    // Otherwise, add the contact as a suggested new group member
222c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    String displayName = cursor.getString(DISPLAY_NAME_PRIMARY_COLUMN_INDEX);
223de4e404bd88cb60a8286e17383a49534efcc0e56Katherine Kuan                    SuggestedMember member = new SuggestedMember(rawContactId, displayName,
224de4e404bd88cb60a8286e17383a49534efcc0e56Katherine Kuan                            contactId);
225de4e404bd88cb60a8286e17383a49534efcc0e56Katherine Kuan                    // Store the member in the list of suggestions and add it to the hash map too.
226de4e404bd88cb60a8286e17383a49534efcc0e56Katherine Kuan                    suggestionsList.add(member);
227de4e404bd88cb60a8286e17383a49534efcc0e56Katherine Kuan                    suggestionsMap.put(rawContactId, member);
228c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                }
229c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            } finally {
230c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                cursor.close();
231c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            }
232c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
233c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            int numSuggestions = suggestionsMap.keySet().size();
234c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            if (numSuggestions == 0) {
235c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                return results;
236c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            }
237c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
238c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            // Create a part of the selection string for the next query with the pattern (?, ?, ?)
239c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            // where the number of comma-separated question marks represent the number of raw
240c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            // contact IDs found in the previous query (while respective the SUGGESTION_LIMIT)
241c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            final StringBuilder rawContactIdSelectionBuilder = new StringBuilder();
242c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            final String[] questionMarks = new String[numSuggestions];
243c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            Arrays.fill(questionMarks, "?");
244c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            rawContactIdSelectionBuilder.append(RawContacts._ID + " IN (")
245c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    .append(TextUtils.join(",", questionMarks))
246c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    .append(")");
247c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
248c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            // Construct the selection args based on the raw contact IDs we're interested in
249c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            // (as well as the photo, email, and phone mimetypes)
250c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            List<String> selectionArgs = new ArrayList<String>();
251c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            selectionArgs.add(Photo.CONTENT_ITEM_TYPE);
252c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            selectionArgs.add(Email.CONTENT_ITEM_TYPE);
253c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            selectionArgs.add(Phone.CONTENT_ITEM_TYPE);
254c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            for (Long rawContactId : suggestionsMap.keySet()) {
255c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                selectionArgs.add(String.valueOf(rawContactId));
256c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            }
257c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
258c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            // Perform a second query to retrieve a photo and possibly a phone number or email
259c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            // address for the suggested contact
260c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            Cursor memberDataCursor = mContentResolver.query(
261c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    RawContactsEntity.CONTENT_URI, PROJECTION_MEMBER_DATA,
262c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    "(" + Data.MIMETYPE + "=? OR " + Data.MIMETYPE + "=? OR " + Data.MIMETYPE +
263c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    "=?) AND " + rawContactIdSelectionBuilder.toString(),
264c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    selectionArgs.toArray(new String[0]), null);
265c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
26613c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner            if (memberDataCursor != null) {
26713c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner                try {
26813c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner                    memberDataCursor.moveToPosition(-1);
26913c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner                    while (memberDataCursor.moveToNext()) {
27013c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner                        long rawContactId = memberDataCursor.getLong(RAW_CONTACT_ID_COLUMN_INDEX);
27113c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner                        SuggestedMember member = suggestionsMap.get(rawContactId);
27213c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner                        if (member == null) {
27313c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner                            continue;
27413c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner                        }
27513c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner                        String mimetype = memberDataCursor.getString(MIMETYPE_COLUMN_INDEX);
27613c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner                        if (Photo.CONTENT_ITEM_TYPE.equals(mimetype)) {
27713c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner                            // Set photo
27813c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner                            byte[] bitmapArray = memberDataCursor.getBlob(PHOTO_COLUMN_INDEX);
27913c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner                            member.setPhotoByteArray(bitmapArray);
28013c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner                        } else if (Email.CONTENT_ITEM_TYPE.equals(mimetype) ||
28113c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner                                Phone.CONTENT_ITEM_TYPE.equals(mimetype)) {
28213c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner                            // Set at most 1 extra piece of contact info that can be a phone number or
28313c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner                            // email
28413c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner                            if (!member.hasExtraInfo()) {
28513c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner                                String info = memberDataCursor.getString(DATA_COLUMN_INDEX);
28613c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner                                member.setExtraInfo(info);
28713c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner                            }
288c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                        }
289c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                    }
29013c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner                } finally {
29113c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner                    memberDataCursor.close();
292c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                }
293c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            }
294de4e404bd88cb60a8286e17383a49534efcc0e56Katherine Kuan            results.values = suggestionsList;
295c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            return results;
296c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        }
297c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
298c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        @Override
299c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        protected void publishResults(CharSequence constraint, FilterResults results) {
30018958a29b3eddb6fc42cf651ec0eed27103f534dDaniel Lehmann            @SuppressWarnings("unchecked")
301de4e404bd88cb60a8286e17383a49534efcc0e56Katherine Kuan            List<SuggestedMember> suggestionsList = (List<SuggestedMember>) results.values;
302de4e404bd88cb60a8286e17383a49534efcc0e56Katherine Kuan            if (suggestionsList == null) {
303c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                return;
304c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            }
305c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
306c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            // Clear out the existing suggestions in this adapter
307c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            clear();
308c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
309c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            // Add all the suggested members to this adapter
310de4e404bd88cb60a8286e17383a49534efcc0e56Katherine Kuan            for (SuggestedMember member : suggestionsList) {
311c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan                add(member);
312c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            }
313c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
314c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            notifyDataSetChanged();
315c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        }
316c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    }
317c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
318c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    /**
319c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan     * This represents a single contact that is a suggestion for the user to add to a group.
320c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan     */
3212d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan    // TODO: Merge this with the {@link GroupEditorFragment} Member class once we can find the
3222d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan    // lookup URI for this contact using the autocomplete filter queries
323c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    public class SuggestedMember {
324c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
3252d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan        private long mRawContactId;
326c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        private long mContactId;
327c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        private String mDisplayName;
328c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        private String mExtraInfo;
329c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        private byte[] mPhoto;
330c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
3312d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan        public SuggestedMember(long rawContactId, String displayName, long contactId) {
3322d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan            mRawContactId = rawContactId;
333c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            mDisplayName = displayName;
334c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            mContactId = contactId;
335c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        }
336c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
337c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        public String getDisplayName() {
338c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            return mDisplayName;
339c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        }
340c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
341c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        public String getExtraInfo() {
342c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            return mExtraInfo;
343c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        }
344c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
3452d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan        public long getRawContactId() {
3462d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan            return mRawContactId;
3472d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan        }
3482d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan
349c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        public long getContactId() {
350c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            return mContactId;
351c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        }
352c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
353c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        public byte[] getPhotoByteArray() {
354c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            return mPhoto;
355c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        }
356c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
357c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        public boolean hasExtraInfo() {
358c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            return mExtraInfo != null;
359c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        }
360c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
361c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        /**
362c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan         * Set a phone number or email to distinguish this contact
363c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan         */
364c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        public void setExtraInfo(String info) {
365c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            mExtraInfo = info;
366c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        }
367c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan
368c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        public void setPhotoByteArray(byte[] photo) {
369c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan            mPhoto = photo;
370c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        }
3716ae983fc9fff8ec820fd09d0d5b997bcbea31a43Makoto Onuki
3726ae983fc9fff8ec820fd09d0d5b997bcbea31a43Makoto Onuki        @Override
3736ae983fc9fff8ec820fd09d0d5b997bcbea31a43Makoto Onuki        public String toString() {
3746ae983fc9fff8ec820fd09d0d5b997bcbea31a43Makoto Onuki            return getDisplayName();
3756ae983fc9fff8ec820fd09d0d5b997bcbea31a43Makoto Onuki        }
376c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    }
377c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan}
378