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