RecipientAlternatesAdapter.java revision 16923ee63a79fce4be3f62b08bcd1f80617c1205
184dd9a88f0d9984996e951e59e73cb76cd2eaa5eMindy Pereira/* 284dd9a88f0d9984996e951e59e73cb76cd2eaa5eMindy Pereira * Copyright (C) 2011 The Android Open Source Project 384dd9a88f0d9984996e951e59e73cb76cd2eaa5eMindy Pereira * 484dd9a88f0d9984996e951e59e73cb76cd2eaa5eMindy Pereira * Licensed under the Apache License, Version 2.0 (the "License"); 584dd9a88f0d9984996e951e59e73cb76cd2eaa5eMindy Pereira * you may not use this file except in compliance with the License. 684dd9a88f0d9984996e951e59e73cb76cd2eaa5eMindy Pereira * You may obtain a copy of the License at 784dd9a88f0d9984996e951e59e73cb76cd2eaa5eMindy Pereira * 884dd9a88f0d9984996e951e59e73cb76cd2eaa5eMindy Pereira * http://www.apache.org/licenses/LICENSE-2.0 984dd9a88f0d9984996e951e59e73cb76cd2eaa5eMindy Pereira * 1084dd9a88f0d9984996e951e59e73cb76cd2eaa5eMindy Pereira * Unless required by applicable law or agreed to in writing, software 1184dd9a88f0d9984996e951e59e73cb76cd2eaa5eMindy Pereira * distributed under the License is distributed on an "AS IS" BASIS, 1284dd9a88f0d9984996e951e59e73cb76cd2eaa5eMindy Pereira * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1384dd9a88f0d9984996e951e59e73cb76cd2eaa5eMindy Pereira * See the License for the specific language governing permissions and 1484dd9a88f0d9984996e951e59e73cb76cd2eaa5eMindy Pereira * limitations under the License. 1584dd9a88f0d9984996e951e59e73cb76cd2eaa5eMindy Pereira */ 1697d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira 1797d7768576ff27d779d68f77e23925b69f3290bcMindy Pereirapackage com.android.ex.chips; 1897d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira 1916923ee63a79fce4be3f62b08bcd1f80617c1205mindypimport android.accounts.Account; 2016923ee63a79fce4be3f62b08bcd1f80617c1205mindypimport android.content.ContentResolver; 2197d7768576ff27d779d68f77e23925b69f3290bcMindy Pereiraimport android.content.Context; 2297d7768576ff27d779d68f77e23925b69f3290bcMindy Pereiraimport android.database.Cursor; 23a5d37c8a968edf94755215617b593d3f61738a92Makoto Onukiimport android.database.MatrixCursor; 2416923ee63a79fce4be3f62b08bcd1f80617c1205mindypimport android.net.Uri; 2516923ee63a79fce4be3f62b08bcd1f80617c1205mindypimport android.provider.ContactsContract; 261852931de1e24e77cb708f4ba010eaa269426657Mindy Pereiraimport android.text.util.Rfc822Token; 271852931de1e24e77cb708f4ba010eaa269426657Mindy Pereiraimport android.text.util.Rfc822Tokenizer; 2818987c44006700a2bfe614ec1e39a29ed5b23d78Mindy Pereiraimport android.util.Log; 2997d7768576ff27d779d68f77e23925b69f3290bcMindy Pereiraimport android.view.LayoutInflater; 3097d7768576ff27d779d68f77e23925b69f3290bcMindy Pereiraimport android.view.View; 3197d7768576ff27d779d68f77e23925b69f3290bcMindy Pereiraimport android.view.ViewGroup; 3297d7768576ff27d779d68f77e23925b69f3290bcMindy Pereiraimport android.widget.CursorAdapter; 3367ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereiraimport android.widget.ImageView; 3497d7768576ff27d779d68f77e23925b69f3290bcMindy Pereiraimport android.widget.TextView; 3597d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira 3616923ee63a79fce4be3f62b08bcd1f80617c1205mindypimport com.android.ex.chips.BaseRecipientAdapter.DirectoryListQuery; 3716923ee63a79fce4be3f62b08bcd1f80617c1205mindypimport com.android.ex.chips.BaseRecipientAdapter.DirectorySearchParams; 3880f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylorimport com.android.ex.chips.Queries.Query; 39a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki 4003cfe3eee5635e419ab1d70d463b2b8beac72f00Mindy Pereiraimport java.util.ArrayList; 411852931de1e24e77cb708f4ba010eaa269426657Mindy Pereiraimport java.util.HashMap; 42a5d37c8a968edf94755215617b593d3f61738a92Makoto Onukiimport java.util.HashSet; 4316923ee63a79fce4be3f62b08bcd1f80617c1205mindypimport java.util.List; 441852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira 4580f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor/** 4680f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor * RecipientAlternatesAdapter backs the RecipientEditTextView for managing contacts 4780f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor * queried by email or by phone number. 4880f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor */ 4997d7768576ff27d779d68f77e23925b69f3290bcMindy Pereirapublic class RecipientAlternatesAdapter extends CursorAdapter { 501852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira static final int MAX_LOOKUPS = 50; 5197d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira private final LayoutInflater mLayoutInflater; 5297d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira 5397d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira private final long mCurrentId; 5497d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira 55007a76baab414c9d432d31c661668b1bd07e3f80Mindy Pereira private int mCheckedItemPosition = -1; 56007a76baab414c9d432d31c661668b1bd07e3f80Mindy Pereira 575086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira private OnCheckedItemChangedListener mCheckedItemChangedListener; 585086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira 5918987c44006700a2bfe614ec1e39a29ed5b23d78Mindy Pereira private static final String TAG = "RecipAlternates"; 6018987c44006700a2bfe614ec1e39a29ed5b23d78Mindy Pereira 6180f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor public static final int QUERY_TYPE_EMAIL = 0; 6280f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor public static final int QUERY_TYPE_PHONE = 1; 6380f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor private Query mQuery; 6480f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor 6516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp public interface RecipientMatchCallback { 6616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp public void matchesFound(HashMap<String, RecipientEntry> results); 6716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 6816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp 6916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp public static void getMatchingRecipients(Context context, ArrayList<String> inAddresses, 7016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp Account account, RecipientMatchCallback callback) { 7116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp getMatchingRecipients(context, inAddresses, QUERY_TYPE_EMAIL, account, callback); 7280f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } 7380f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor 741852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira /** 751852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira * Get a HashMap of address to RecipientEntry that contains all contact 761852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira * information for a contact with the provided address, if one exists. This 771852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira * may block the UI, so run it in an async task. 781852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira * 791852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira * @param context Context. 807211747e51623ae1305053f533c09dd335e013a2Daisuke Miyakawa * @param inAddresses Array of addresses on which to perform the lookup. 8116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp * @param callback RecipientMatchCallback called when a match or matches are found. 821852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira * @return HashMap<String,RecipientEntry> 831852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira */ 8416923ee63a79fce4be3f62b08bcd1f80617c1205mindyp public static void getMatchingRecipients(Context context, ArrayList<String> inAddresses, 8516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp int addressType, Account account, RecipientMatchCallback callback) { 8680f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor Queries.Query query; 8780f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor if (addressType == QUERY_TYPE_EMAIL) { 8880f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor query = Queries.EMAIL; 8980f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } else { 9080f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor query = Queries.PHONE; 9180f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } 9203cfe3eee5635e419ab1d70d463b2b8beac72f00Mindy Pereira int addressesSize = Math.min(MAX_LOOKUPS, inAddresses.size()); 9316923ee63a79fce4be3f62b08bcd1f80617c1205mindyp HashSet<String> addresses = new HashSet<String>(); 941852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira StringBuilder bindString = new StringBuilder(); 951852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira // Create the "?" string and set up arguments. 961852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira for (int i = 0; i < addressesSize; i++) { 9703cfe3eee5635e419ab1d70d463b2b8beac72f00Mindy Pereira Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(inAddresses.get(i).toLowerCase()); 9816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp addresses.add(tokens.length > 0 ? tokens[0].getAddress() : inAddresses.get(i)); 991852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira bindString.append("?"); 1001852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira if (i < addressesSize - 1) { 1011852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira bindString.append(","); 1021852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira } 1031852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira } 1041852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira 10518987c44006700a2bfe614ec1e39a29ed5b23d78Mindy Pereira if (Log.isLoggable(TAG, Log.DEBUG)) { 10618987c44006700a2bfe614ec1e39a29ed5b23d78Mindy Pereira Log.d(TAG, "Doing reverse lookup for " + addresses.toString()); 10718987c44006700a2bfe614ec1e39a29ed5b23d78Mindy Pereira } 10818987c44006700a2bfe614ec1e39a29ed5b23d78Mindy Pereira 10916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp String[] addressArray = new String[addresses.size()]; 11016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp addresses.toArray(addressArray); 11116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp HashMap<String, RecipientEntry> recipientEntries = null; 11216923ee63a79fce4be3f62b08bcd1f80617c1205mindyp Cursor c = null; 11316923ee63a79fce4be3f62b08bcd1f80617c1205mindyp 11416923ee63a79fce4be3f62b08bcd1f80617c1205mindyp try { 11516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp c = context.getContentResolver().query( 11616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp query.getContentUri(), 11716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp query.getProjection(), 11816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp query.getProjection()[Queries.Query.DESTINATION] + " IN (" 11916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp + bindString.toString() + ")", addressArray, null); 12016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp recipientEntries = processContactEntries(c); 12116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp callback.matchesFound(recipientEntries); 12216923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } finally { 12316923ee63a79fce4be3f62b08bcd1f80617c1205mindyp if (c != null) { 12416923ee63a79fce4be3f62b08bcd1f80617c1205mindyp c.close(); 12516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 12616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 12716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp // See if any entries did not resolve; if so, we need to check other 12816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp // directories 12916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp if (recipientEntries.size() < addresses.size()) { 13016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp final List<DirectorySearchParams> paramsList; 13116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp Cursor directoryCursor = context.getContentResolver().query(DirectoryListQuery.URI, 13216923ee63a79fce4be3f62b08bcd1f80617c1205mindyp DirectoryListQuery.PROJECTION, null, null, null); 13316923ee63a79fce4be3f62b08bcd1f80617c1205mindyp paramsList = BaseRecipientAdapter.setupOtherDirectories(context, directoryCursor, 13416923ee63a79fce4be3f62b08bcd1f80617c1205mindyp account); 13516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp // Run a directory query for each unmatched recipient. 13616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp HashSet<String> unresolvedAddresses = new HashSet<String>(); 13716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp for (String address : addresses) { 13816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp if (!recipientEntries.containsKey(address)) { 13916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp unresolvedAddresses.add(address); 14016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 14116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 14216923ee63a79fce4be3f62b08bcd1f80617c1205mindyp Cursor directoryContactsCursor = null; 14316923ee63a79fce4be3f62b08bcd1f80617c1205mindyp for (String unresolvedAddress : unresolvedAddresses) { 14416923ee63a79fce4be3f62b08bcd1f80617c1205mindyp for (int i = 0; i < paramsList.size(); i++) { 14516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp try { 14616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp directoryContactsCursor = doQuery(unresolvedAddress, 1, 14716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp paramsList.get(i).directoryId, account, 14816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp context.getContentResolver(), query); 14916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } finally { 15016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp if (directoryContactsCursor != null 15116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp && directoryContactsCursor.getCount() == 0) { 15216923ee63a79fce4be3f62b08bcd1f80617c1205mindyp directoryContactsCursor.close(); 15316923ee63a79fce4be3f62b08bcd1f80617c1205mindyp directoryContactsCursor = null; 15416923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } else { 15516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp break; 15618987c44006700a2bfe614ec1e39a29ed5b23d78Mindy Pereira } 15716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 15816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 15916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp if (directoryContactsCursor != null) { 16016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp try { 16116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp callback.matchesFound(processContactEntries(directoryContactsCursor)); 16216923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } finally { 16316923ee63a79fce4be3f62b08bcd1f80617c1205mindyp directoryContactsCursor.close(); 16416923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 1651852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira } 1661852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira } 1671852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira } 16816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 16916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp 17016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp private static HashMap<String, RecipientEntry> processContactEntries(Cursor c) { 17116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp HashMap<String, RecipientEntry> recipientEntries = new HashMap<String, RecipientEntry>(); 17216923ee63a79fce4be3f62b08bcd1f80617c1205mindyp if (c != null && c.moveToFirst()) { 17316923ee63a79fce4be3f62b08bcd1f80617c1205mindyp do { 17416923ee63a79fce4be3f62b08bcd1f80617c1205mindyp String address = c.getString(Queries.Query.DESTINATION); 17516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp recipientEntries.put(address, RecipientEntry.constructTopLevelEntry( 17616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp c.getString(Queries.Query.NAME), 17716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp c.getInt(Queries.Query.DISPLAY_NAME_SOURCE), 17816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp c.getString(Queries.Query.DESTINATION), 17916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp c.getInt(Queries.Query.DESTINATION_TYPE), 18016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp c.getString(Queries.Query.DESTINATION_LABEL), 18116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp c.getLong(Queries.Query.CONTACT_ID), 18216923ee63a79fce4be3f62b08bcd1f80617c1205mindyp c.getLong(Queries.Query.DATA_ID), 18316923ee63a79fce4be3f62b08bcd1f80617c1205mindyp c.getString(Queries.Query.PHOTO_THUMBNAIL_URI), 18416923ee63a79fce4be3f62b08bcd1f80617c1205mindyp true)); 18516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp if (Log.isLoggable(TAG, Log.DEBUG)) { 18616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp Log.d(TAG, "Received reverse look up information for " + address 18716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp + " RESULTS: " 18816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp + " NAME : " + c.getString(Queries.Query.NAME) 18916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp + " CONTACT ID : " + c.getLong(Queries.Query.CONTACT_ID) 19016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp + " ADDRESS :" + c.getString(Queries.Query.DESTINATION)); 19116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 19216923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } while (c.moveToNext()); 19316923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 1941852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira return recipientEntries; 1951852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira } 1961852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira 19716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp private static Cursor doQuery(CharSequence constraint, int limit, Long directoryId, 19816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp Account account, ContentResolver resolver, Query query) { 19916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp final Uri.Builder builder = query 20016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp .getContentFilterUri() 20116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp .buildUpon() 20216923ee63a79fce4be3f62b08bcd1f80617c1205mindyp .appendPath(constraint.toString()) 20316923ee63a79fce4be3f62b08bcd1f80617c1205mindyp .appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY, 20416923ee63a79fce4be3f62b08bcd1f80617c1205mindyp String.valueOf(limit + BaseRecipientAdapter.ALLOWANCE_FOR_DUPLICATES)); 20516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp if (directoryId != null) { 20616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, 20716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp String.valueOf(directoryId)); 20816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 20916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp if (account != null) { 21016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp builder.appendQueryParameter(BaseRecipientAdapter.PRIMARY_ACCOUNT_NAME, account.name); 21116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp builder.appendQueryParameter(BaseRecipientAdapter.PRIMARY_ACCOUNT_TYPE, account.type); 21216923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 21316923ee63a79fce4be3f62b08bcd1f80617c1205mindyp final Cursor cursor = resolver.query(builder.build(), query.getProjection(), null, null, 21416923ee63a79fce4be3f62b08bcd1f80617c1205mindyp null); 21516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp return cursor; 21616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 21716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp 2185086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira public RecipientAlternatesAdapter(Context context, long contactId, long currentId, int viewId, 2195086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira OnCheckedItemChangedListener listener) { 22080f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor this(context, contactId, currentId, viewId, QUERY_TYPE_EMAIL, listener); 22180f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } 22280f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor 22380f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor public RecipientAlternatesAdapter(Context context, long contactId, long currentId, int viewId, 22480f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor int queryMode, OnCheckedItemChangedListener listener) { 22580f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor super(context, getCursorForConstruction(context, contactId, queryMode), 0); 22697d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira mLayoutInflater = LayoutInflater.from(context); 22797d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira mCurrentId = currentId; 2285086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira mCheckedItemChangedListener = listener; 22980f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor 23080f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor if (queryMode == QUERY_TYPE_EMAIL) { 23180f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor mQuery = Queries.EMAIL; 23280f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } else if (queryMode == QUERY_TYPE_PHONE) { 23380f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor mQuery = Queries.PHONE; 23480f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } else { 23580f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor mQuery = Queries.EMAIL; 23680f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor Log.e(TAG, "Unsupported query type: " + queryMode); 23780f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } 23880f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } 23980f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor 24080f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor private static Cursor getCursorForConstruction(Context context, long contactId, int queryType) { 241a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki final Cursor cursor; 24280f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor if (queryType == QUERY_TYPE_EMAIL) { 243a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki cursor = context.getContentResolver().query( 24480f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor Queries.EMAIL.getContentUri(), 24580f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor Queries.EMAIL.getProjection(), 246a62ba492f901e024b249e0138e96374b09766a36Mindy Pereira Queries.EMAIL.getProjection()[Queries.Query.CONTACT_ID] + " =?", new String[] { 24780f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor String.valueOf(contactId) 24880f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor }, null); 24980f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } else { 250a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki cursor = context.getContentResolver().query( 25180f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor Queries.PHONE.getContentUri(), 25280f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor Queries.PHONE.getProjection(), 2539c17ab5f3bf0f88e3641faf98931c4f9e7d65366Tom Taylor Queries.PHONE.getProjection()[Queries.Query.CONTACT_ID] + " =?", new String[] { 25480f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor String.valueOf(contactId) 25580f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor }, null); 25680f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } 257a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki return removeDuplicateDestinations(cursor); 258a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki } 259a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki 260a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki /** 261a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki * @return a new cursor based on the given cursor with all duplicate destinations removed. 262a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki * 263a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki * It's only intended to use for the alternate list, so... 264a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki * - This method ignores all other fields and dedupe solely on the destination. Normally, 265a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki * if a cursor contains multiple contacts and they have the same destination, we'd still want 266a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki * to show both. 267a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki * - This method creates a MatrixCursor, so all data will be kept in memory. We wouldn't want 268a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki * to do this if the original cursor is large, but it's okay here because the alternate list 269a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki * won't be that big. 270a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki */ 271a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki // Visible for testing 272a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki /* package */ static Cursor removeDuplicateDestinations(Cursor original) { 273a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki final MatrixCursor result = new MatrixCursor( 274a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki original.getColumnNames(), original.getCount()); 275a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki final HashSet<String> destinationsSeen = new HashSet<String>(); 276a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki 277a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki original.moveToPosition(-1); 278a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki while (original.moveToNext()) { 279a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki final String destination = original.getString(Query.DESTINATION); 280a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki if (destinationsSeen.contains(destination)) { 281a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki continue; 282a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki } 283a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki destinationsSeen.add(destination); 284a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki 285a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki result.addRow(new Object[] { 286a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki original.getString(Query.NAME), 287a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki original.getString(Query.DESTINATION), 288a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki original.getInt(Query.DESTINATION_TYPE), 289a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki original.getString(Query.DESTINATION_LABEL), 290a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki original.getLong(Query.CONTACT_ID), 291a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki original.getLong(Query.DATA_ID), 292a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki original.getString(Query.PHOTO_THUMBNAIL_URI), 293a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki original.getInt(Query.DISPLAY_NAME_SOURCE) 294a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki }); 295a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki } 296a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki 297a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki return result; 29897d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira } 29997d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira 30097d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira @Override 30197d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira public long getItemId(int position) { 30297d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira Cursor c = getCursor(); 3033bb52162b7e842243d4a14e73c15b20dbd1804d7Mindy Pereira if (c.moveToPosition(position)) { 30480f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor c.getLong(Queries.Query.DATA_ID); 3053bb52162b7e842243d4a14e73c15b20dbd1804d7Mindy Pereira } 3063bb52162b7e842243d4a14e73c15b20dbd1804d7Mindy Pereira return -1; 30797d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira } 30897d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira 30997d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira public RecipientEntry getRecipientEntry(int position) { 31097d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira Cursor c = getCursor(); 31197d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira c.moveToPosition(position); 31280f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor return RecipientEntry.constructTopLevelEntry( 31380f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor c.getString(Queries.Query.NAME), 31400adb32f3cea49ec82467c0e1a9e42659b556836Makoto Onuki c.getInt(Queries.Query.DISPLAY_NAME_SOURCE), 31580f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor c.getString(Queries.Query.DESTINATION), 31680f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor c.getInt(Queries.Query.DESTINATION_TYPE), 31780f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor c.getString(Queries.Query.DESTINATION_LABEL), 31880f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor c.getLong(Queries.Query.CONTACT_ID), 31980f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor c.getLong(Queries.Query.DATA_ID), 320ccb8e237ec80934d1c983bb61f66b75541786ddcmindyp c.getString(Queries.Query.PHOTO_THUMBNAIL_URI), 321ccb8e237ec80934d1c983bb61f66b75541786ddcmindyp true); 32297d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira } 32397d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira 32497d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira @Override 32597d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira public View getView(int position, View convertView, ViewGroup parent) { 32667ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira Cursor cursor = getCursor(); 32767ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira cursor.moveToPosition(position); 32897d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira if (convertView == null) { 329007a76baab414c9d432d31c661668b1bd07e3f80Mindy Pereira convertView = newView(); 330007a76baab414c9d432d31c661668b1bd07e3f80Mindy Pereira } 33180f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor if (cursor.getLong(Queries.Query.DATA_ID) == mCurrentId) { 332007a76baab414c9d432d31c661668b1bd07e3f80Mindy Pereira mCheckedItemPosition = position; 3335086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira if (mCheckedItemChangedListener != null) { 3345086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira mCheckedItemChangedListener.onCheckedItemChanged(mCheckedItemPosition); 3355086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira } 33697d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira } 33767ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira bindView(convertView, convertView.getContext(), cursor); 33897d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira return convertView; 33997d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira } 34097d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira 34167ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira // TODO: this is VERY similar to the BaseRecipientAdapter. Can we combine 34267ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira // somehow? 34397d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira @Override 34497d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira public void bindView(View view, Context context, Cursor cursor) { 34567ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira int position = cursor.getPosition(); 34667ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira 347102cf10189b2c13045b885a5479333ae3b304491Daisuke Miyakawa TextView display = (TextView) view.findViewById(android.R.id.title); 34867ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira ImageView imageView = (ImageView) view.findViewById(android.R.id.icon); 34967ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira RecipientEntry entry = getRecipientEntry(position); 35067ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira if (position == 0) { 35180f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor display.setText(cursor.getString(Queries.Query.NAME)); 35267ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira display.setVisibility(View.VISIBLE); 35367ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira // TODO: see if this needs to be done outside the main thread 35467ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira // as it may be too slow to get immediately. 35567ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira imageView.setImageURI(entry.getPhotoThumbnailUri()); 35667ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira imageView.setVisibility(View.VISIBLE); 35767ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira } else { 35867ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira display.setVisibility(View.GONE); 35967ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira imageView.setVisibility(View.GONE); 36067ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira } 361102cf10189b2c13045b885a5479333ae3b304491Daisuke Miyakawa TextView destination = (TextView) view.findViewById(android.R.id.text1); 36280f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor destination.setText(cursor.getString(Queries.Query.DESTINATION)); 363102cf10189b2c13045b885a5479333ae3b304491Daisuke Miyakawa 364102cf10189b2c13045b885a5479333ae3b304491Daisuke Miyakawa TextView destinationType = (TextView) view.findViewById(android.R.id.text2); 365f908b64e75e0bb38ff2806232ca57c93189156eaMindy Pereira if (destinationType != null) { 36680f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor destinationType.setText(mQuery.getTypeLabel(context.getResources(), 36780f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor cursor.getInt(Queries.Query.DESTINATION_TYPE), 36880f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor cursor.getString(Queries.Query.DESTINATION_LABEL)).toString().toUpperCase()); 369f908b64e75e0bb38ff2806232ca57c93189156eaMindy Pereira } 37097d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira } 37197d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira 37297d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira @Override 37397d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira public View newView(Context context, Cursor cursor, ViewGroup parent) { 374007a76baab414c9d432d31c661668b1bd07e3f80Mindy Pereira return newView(); 375007a76baab414c9d432d31c661668b1bd07e3f80Mindy Pereira } 376007a76baab414c9d432d31c661668b1bd07e3f80Mindy Pereira 377007a76baab414c9d432d31c661668b1bd07e3f80Mindy Pereira private View newView() { 37852c441e2c03e0f48572348953b985a4bf989c057Mindy Pereira return mLayoutInflater.inflate(R.layout.chips_recipient_dropdown_item, null); 37997d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira } 38097d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira 3815086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira /*package*/ static interface OnCheckedItemChangedListener { 3825086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira public void onCheckedItemChanged(int position); 38397d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira } 38497d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira} 385