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; 40f677450d82e7b961fda2a18fea2ad51e88437e8bYorke Leeimport com.android.contacts.common.ContactPhotoManager; 41e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.group.SuggestedMemberListAdapter.SuggestedMember; 42e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Cheng 43c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport java.util.ArrayList; 44c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport java.util.Arrays; 45c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport java.util.HashMap; 46c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanimport java.util.List; 47c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 48c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan/** 49c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan * This adapter provides suggested contacts that can be added to a group for an 50c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan * {@link AutoCompleteTextView} within the group editor. 51c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan */ 52c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuanpublic class SuggestedMemberListAdapter extends ArrayAdapter<SuggestedMember> { 53c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 54c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan private static final String[] PROJECTION_FILTERED_MEMBERS = new String[] { 55c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan RawContacts._ID, // 0 56c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan RawContacts.CONTACT_ID, // 1 57c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan RawContacts.DISPLAY_NAME_PRIMARY // 2 58c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan }; 59c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 60c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan private static final int RAW_CONTACT_ID_COLUMN_INDEX = 0; 61c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan private static final int CONTACT_ID_COLUMN_INDEX = 1; 62c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan private static final int DISPLAY_NAME_PRIMARY_COLUMN_INDEX = 2; 63c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 64c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan private static final String[] PROJECTION_MEMBER_DATA = new String[] { 65c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan RawContacts._ID, // 0 66c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan RawContacts.CONTACT_ID, // 1 67c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan Data.MIMETYPE, // 2 68c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan Data.DATA1, // 3 69c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan Photo.PHOTO, // 4 70c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan }; 71c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 72c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan private static final int MIMETYPE_COLUMN_INDEX = 2; 73c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan private static final int DATA_COLUMN_INDEX = 3; 74c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan private static final int PHOTO_COLUMN_INDEX = 4; 75c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 76c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan private Filter mFilter; 77c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan private ContentResolver mContentResolver; 78c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan private LayoutInflater mInflater; 79c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 80f75900ed2bafa5411c46e8fde0b8dccbc6753176Makoto Onuki private String mAccountType; 81f75900ed2bafa5411c46e8fde0b8dccbc6753176Makoto Onuki private String mAccountName; 82f75900ed2bafa5411c46e8fde0b8dccbc6753176Makoto Onuki private String mDataSet; 83c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 842d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan // TODO: Make this a Map for better performance when we check if a new contact is in the list 852d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan // or not 86f81b6d9ba129f0220de93aa9a7426547889755c3Makoto Onuki private final List<Long> mExistingMemberContactIds = new ArrayList<Long>(); 87c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 88c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan private static final int SUGGESTIONS_LIMIT = 5; 89c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 90c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan public SuggestedMemberListAdapter(Context context, int textViewResourceId) { 91c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan super(context, textViewResourceId); 92c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 93c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 94c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 95c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan public void setAccountType(String accountType) { 96c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan mAccountType = accountType; 97c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 98c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 99c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan public void setAccountName(String accountName) { 100c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan mAccountName = accountName; 101c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 102c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 1032b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro public void setDataSet(String dataSet) { 1042b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro mDataSet = dataSet; 1052b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro } 1062b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro 107c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan public void setContentResolver(ContentResolver resolver) { 108c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan mContentResolver = resolver; 109c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 110c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 111f81b6d9ba129f0220de93aa9a7426547889755c3Makoto Onuki public void updateExistingMembersList(List<GroupEditorFragment.Member> list) { 112f81b6d9ba129f0220de93aa9a7426547889755c3Makoto Onuki mExistingMemberContactIds.clear(); 113f81b6d9ba129f0220de93aa9a7426547889755c3Makoto Onuki for (GroupEditorFragment.Member member : list) { 114f81b6d9ba129f0220de93aa9a7426547889755c3Makoto Onuki mExistingMemberContactIds.add(member.getContactId()); 115f81b6d9ba129f0220de93aa9a7426547889755c3Makoto Onuki } 116c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 117c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 118c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan public void addNewMember(long contactId) { 119c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan mExistingMemberContactIds.add(contactId); 120c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 121c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 122c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan public void removeMember(long contactId) { 123c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan if (mExistingMemberContactIds.contains(contactId)) { 124c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan mExistingMemberContactIds.remove(contactId); 125c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 126c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 127c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 128c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan @Override 129c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan public View getView(int position, View convertView, ViewGroup parent) { 130c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan View result = convertView; 131c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan if (result == null) { 132c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan result = mInflater.inflate(R.layout.group_member_suggestion, parent, false); 133c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 134c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan // TODO: Use a viewholder 135c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan SuggestedMember member = getItem(position); 136c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan TextView text1 = (TextView) result.findViewById(R.id.text1); 137c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan TextView text2 = (TextView) result.findViewById(R.id.text2); 138c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan ImageView icon = (ImageView) result.findViewById(R.id.icon); 139c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan text1.setText(member.getDisplayName()); 140c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan if (member.hasExtraInfo()) { 141c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan text2.setText(member.getExtraInfo()); 142c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } else { 143c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan text2.setVisibility(View.GONE); 144c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 145c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan byte[] byteArray = member.getPhotoByteArray(); 146c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan if (byteArray == null) { 147f677450d82e7b961fda2a18fea2ad51e88437e8bYorke Lee icon.setImageDrawable(ContactPhotoManager.getDefaultAvatarDrawableForContact( 148f677450d82e7b961fda2a18fea2ad51e88437e8bYorke Lee icon.getResources(), false, null)); 14959b46720e92799a29d84e6e31fb3eeea60166f0dMakoto Onuki } else { 150c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan Bitmap bitmap = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length); 151c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan icon.setImageBitmap(bitmap); 152c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 15359b46720e92799a29d84e6e31fb3eeea60166f0dMakoto Onuki result.setTag(member); 154c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan return result; 155c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 156c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 157c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan @Override 158c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan public Filter getFilter() { 159c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan if (mFilter == null) { 160c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan mFilter = new SuggestedMemberFilter(); 161c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 162c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan return mFilter; 163c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 164c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 165c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan /** 166c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan * This filter queries for raw contacts that match the given account name and account type, 167c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan * as well as the search query. 168c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan */ 169c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan public class SuggestedMemberFilter extends Filter { 170c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 171c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan @Override 172c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan protected FilterResults performFiltering(CharSequence prefix) { 173c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan FilterResults results = new FilterResults(); 174c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan if (mContentResolver == null || TextUtils.isEmpty(prefix)) { 175c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan return results; 176c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 177c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 178de4e404bd88cb60a8286e17383a49534efcc0e56Katherine Kuan // Create a list to store the suggested contacts (which will be alphabetically ordered), 179de4e404bd88cb60a8286e17383a49534efcc0e56Katherine Kuan // but also keep a map of raw contact IDs to {@link SuggestedMember}s to make it easier 180de4e404bd88cb60a8286e17383a49534efcc0e56Katherine Kuan // to add supplementary data to the contact (photo, phone, email) to the members based 181de4e404bd88cb60a8286e17383a49534efcc0e56Katherine Kuan // on raw contact IDs after the second query is completed. 182de4e404bd88cb60a8286e17383a49534efcc0e56Katherine Kuan List<SuggestedMember> suggestionsList = new ArrayList<SuggestedMember>(); 183c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan HashMap<Long, SuggestedMember> suggestionsMap = new HashMap<Long, SuggestedMember>(); 184c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 185c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan // First query for all the raw contacts that match the given search query 186c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan // and have the same account name and type as specified in this adapter 187c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan String searchQuery = prefix.toString() + "%"; 1882b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro String accountClause = RawContacts.ACCOUNT_NAME + "=? AND " + 1892b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro RawContacts.ACCOUNT_TYPE + "=?"; 1902b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro String[] args; 1912b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro if (mDataSet == null) { 1922b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro accountClause += " AND " + RawContacts.DATA_SET + " IS NULL"; 1932b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro args = new String[] {mAccountName, mAccountType, searchQuery, searchQuery}; 1942b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro } else { 1952b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro accountClause += " AND " + RawContacts.DATA_SET + "=?"; 1962b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro args = new String[] { 1972b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro mAccountName, mAccountType, mDataSet, searchQuery, searchQuery 1982b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro }; 1992b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro } 2002b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro 201c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan Cursor cursor = mContentResolver.query( 202c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan RawContacts.CONTENT_URI, PROJECTION_FILTERED_MEMBERS, 2032b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro accountClause + " AND (" + 204c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan RawContacts.DISPLAY_NAME_PRIMARY + " LIKE ? OR " + 205c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan RawContacts.DISPLAY_NAME_ALTERNATIVE + " LIKE ? )", 206de4e404bd88cb60a8286e17383a49534efcc0e56Katherine Kuan args, RawContacts.DISPLAY_NAME_PRIMARY + " COLLATE LOCALIZED ASC"); 207c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 208c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan if (cursor == null) { 209c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan return results; 210c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 211c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 212c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan // Read back the results from the cursor and filter out existing group members. 213c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan // For valid suggestions, add them to the hash map of suggested members. 214c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan try { 215c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan cursor.moveToPosition(-1); 216c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan while (cursor.moveToNext() && suggestionsMap.keySet().size() < SUGGESTIONS_LIMIT) { 2172d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan long rawContactId = cursor.getLong(RAW_CONTACT_ID_COLUMN_INDEX); 218c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan long contactId = cursor.getLong(CONTACT_ID_COLUMN_INDEX); 219c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan // Filter out contacts that have already been added to this group 220c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan if (mExistingMemberContactIds.contains(contactId)) { 221c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan continue; 222c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 223c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan // Otherwise, add the contact as a suggested new group member 224c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan String displayName = cursor.getString(DISPLAY_NAME_PRIMARY_COLUMN_INDEX); 225de4e404bd88cb60a8286e17383a49534efcc0e56Katherine Kuan SuggestedMember member = new SuggestedMember(rawContactId, displayName, 226de4e404bd88cb60a8286e17383a49534efcc0e56Katherine Kuan contactId); 227de4e404bd88cb60a8286e17383a49534efcc0e56Katherine Kuan // Store the member in the list of suggestions and add it to the hash map too. 228de4e404bd88cb60a8286e17383a49534efcc0e56Katherine Kuan suggestionsList.add(member); 229de4e404bd88cb60a8286e17383a49534efcc0e56Katherine Kuan suggestionsMap.put(rawContactId, member); 230c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 231c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } finally { 232c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan cursor.close(); 233c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 234c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 235c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan int numSuggestions = suggestionsMap.keySet().size(); 236c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan if (numSuggestions == 0) { 237c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan return results; 238c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 239c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 240c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan // Create a part of the selection string for the next query with the pattern (?, ?, ?) 241c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan // where the number of comma-separated question marks represent the number of raw 242c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan // contact IDs found in the previous query (while respective the SUGGESTION_LIMIT) 243c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan final StringBuilder rawContactIdSelectionBuilder = new StringBuilder(); 244c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan final String[] questionMarks = new String[numSuggestions]; 245c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan Arrays.fill(questionMarks, "?"); 246c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan rawContactIdSelectionBuilder.append(RawContacts._ID + " IN (") 247c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan .append(TextUtils.join(",", questionMarks)) 248c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan .append(")"); 249c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 250c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan // Construct the selection args based on the raw contact IDs we're interested in 251c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan // (as well as the photo, email, and phone mimetypes) 252c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan List<String> selectionArgs = new ArrayList<String>(); 253c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan selectionArgs.add(Photo.CONTENT_ITEM_TYPE); 254c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan selectionArgs.add(Email.CONTENT_ITEM_TYPE); 255c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan selectionArgs.add(Phone.CONTENT_ITEM_TYPE); 256c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan for (Long rawContactId : suggestionsMap.keySet()) { 257c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan selectionArgs.add(String.valueOf(rawContactId)); 258c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 259c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 260c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan // Perform a second query to retrieve a photo and possibly a phone number or email 261c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan // address for the suggested contact 262c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan Cursor memberDataCursor = mContentResolver.query( 263c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan RawContactsEntity.CONTENT_URI, PROJECTION_MEMBER_DATA, 264c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan "(" + Data.MIMETYPE + "=? OR " + Data.MIMETYPE + "=? OR " + Data.MIMETYPE + 265c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan "=?) AND " + rawContactIdSelectionBuilder.toString(), 266c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan selectionArgs.toArray(new String[0]), null); 267c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 26813c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner if (memberDataCursor != null) { 26913c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner try { 27013c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner memberDataCursor.moveToPosition(-1); 27113c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner while (memberDataCursor.moveToNext()) { 27213c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner long rawContactId = memberDataCursor.getLong(RAW_CONTACT_ID_COLUMN_INDEX); 27313c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner SuggestedMember member = suggestionsMap.get(rawContactId); 27413c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner if (member == null) { 27513c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner continue; 27613c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner } 27713c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner String mimetype = memberDataCursor.getString(MIMETYPE_COLUMN_INDEX); 27813c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner if (Photo.CONTENT_ITEM_TYPE.equals(mimetype)) { 27913c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner // Set photo 28013c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner byte[] bitmapArray = memberDataCursor.getBlob(PHOTO_COLUMN_INDEX); 28113c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner member.setPhotoByteArray(bitmapArray); 28213c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner } else if (Email.CONTENT_ITEM_TYPE.equals(mimetype) || 28313c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner Phone.CONTENT_ITEM_TYPE.equals(mimetype)) { 28413c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner // Set at most 1 extra piece of contact info that can be a phone number or 28513c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner // email 28613c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner if (!member.hasExtraInfo()) { 28713c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner String info = memberDataCursor.getString(DATA_COLUMN_INDEX); 28813c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner member.setExtraInfo(info); 28913c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner } 290c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 291c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 29213c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner } finally { 29313c42f4ebb1c7f31750262946ce3b390c93d5320Jay Shrauner memberDataCursor.close(); 294c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 295c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 296de4e404bd88cb60a8286e17383a49534efcc0e56Katherine Kuan results.values = suggestionsList; 297c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan return results; 298c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 299c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 300c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan @Override 301c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan protected void publishResults(CharSequence constraint, FilterResults results) { 30218958a29b3eddb6fc42cf651ec0eed27103f534dDaniel Lehmann @SuppressWarnings("unchecked") 303de4e404bd88cb60a8286e17383a49534efcc0e56Katherine Kuan List<SuggestedMember> suggestionsList = (List<SuggestedMember>) results.values; 304de4e404bd88cb60a8286e17383a49534efcc0e56Katherine Kuan if (suggestionsList == null) { 305c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan return; 306c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 307c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 308c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan // Clear out the existing suggestions in this adapter 309c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan clear(); 310c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 311c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan // Add all the suggested members to this adapter 312de4e404bd88cb60a8286e17383a49534efcc0e56Katherine Kuan for (SuggestedMember member : suggestionsList) { 313c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan add(member); 314c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 315c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 316c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan notifyDataSetChanged(); 317c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 318c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 319c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 320c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan /** 321c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan * This represents a single contact that is a suggestion for the user to add to a group. 322c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan */ 3232d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan // TODO: Merge this with the {@link GroupEditorFragment} Member class once we can find the 3242d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan // lookup URI for this contact using the autocomplete filter queries 325c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan public class SuggestedMember { 326c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 3272d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan private long mRawContactId; 328c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan private long mContactId; 329c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan private String mDisplayName; 330c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan private String mExtraInfo; 331c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan private byte[] mPhoto; 332c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 3332d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan public SuggestedMember(long rawContactId, String displayName, long contactId) { 3342d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan mRawContactId = rawContactId; 335c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan mDisplayName = displayName; 336c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan mContactId = contactId; 337c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 338c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 339c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan public String getDisplayName() { 340c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan return mDisplayName; 341c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 342c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 343c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan public String getExtraInfo() { 344c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan return mExtraInfo; 345c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 346c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 3472d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan public long getRawContactId() { 3482d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan return mRawContactId; 3492d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan } 3502d851cc895ffc7afd322298c7d4391ca5bea1a2dKatherine Kuan 351c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan public long getContactId() { 352c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan return mContactId; 353c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 354c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 355c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan public byte[] getPhotoByteArray() { 356c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan return mPhoto; 357c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 358c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 359c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan public boolean hasExtraInfo() { 360c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan return mExtraInfo != null; 361c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 362c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 363c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan /** 364c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan * Set a phone number or email to distinguish this contact 365c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan */ 366c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan public void setExtraInfo(String info) { 367c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan mExtraInfo = info; 368c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 369c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan 370c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan public void setPhotoByteArray(byte[] photo) { 371c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan mPhoto = photo; 372c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 3736ae983fc9fff8ec820fd09d0d5b997bcbea31a43Makoto Onuki 3746ae983fc9fff8ec820fd09d0d5b997bcbea31a43Makoto Onuki @Override 3756ae983fc9fff8ec820fd09d0d5b997bcbea31a43Makoto Onuki public String toString() { 3766ae983fc9fff8ec820fd09d0d5b997bcbea31a43Makoto Onuki return getDisplayName(); 3776ae983fc9fff8ec820fd09d0d5b997bcbea31a43Makoto Onuki } 378c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan } 379c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan} 380