RecipientAlternatesAdapter.java revision 8af0d3b6f34e03c08c8e67be2190da01c59889da
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; 267a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedyimport android.provider.ContactsContract.Contacts; 27ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedyimport android.text.TextUtils; 281852931de1e24e77cb708f4ba010eaa269426657Mindy Pereiraimport android.text.util.Rfc822Token; 291852931de1e24e77cb708f4ba010eaa269426657Mindy Pereiraimport android.text.util.Rfc822Tokenizer; 3018987c44006700a2bfe614ec1e39a29ed5b23d78Mindy Pereiraimport android.util.Log; 3197d7768576ff27d779d68f77e23925b69f3290bcMindy Pereiraimport android.view.View; 3297d7768576ff27d779d68f77e23925b69f3290bcMindy Pereiraimport android.view.ViewGroup; 3397d7768576ff27d779d68f77e23925b69f3290bcMindy Pereiraimport android.widget.CursorAdapter; 3497d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira 3516923ee63a79fce4be3f62b08bcd1f80617c1205mindypimport com.android.ex.chips.BaseRecipientAdapter.DirectoryListQuery; 3616923ee63a79fce4be3f62b08bcd1f80617c1205mindypimport com.android.ex.chips.BaseRecipientAdapter.DirectorySearchParams; 37b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Linimport com.android.ex.chips.DropdownChipLayouter.AdapterType; 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; 4494fa301de71cc110671802eba8376c275b4055a4Scott Kennedyimport java.util.Map; 4594fa301de71cc110671802eba8376c275b4055a4Scott Kennedyimport java.util.Set; 461852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira 4780f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor/** 4880f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor * RecipientAlternatesAdapter backs the RecipientEditTextView for managing contacts 4980f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor * queried by email or by phone number. 5080f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor */ 5197d7768576ff27d779d68f77e23925b69f3290bcMindy Pereirapublic class RecipientAlternatesAdapter extends CursorAdapter { 528af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein public static final int MAX_LOOKUPS = 50; 5397d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira 5497d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira private final long mCurrentId; 5597d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira 56007a76baab414c9d432d31c661668b1bd07e3f80Mindy Pereira private int mCheckedItemPosition = -1; 57007a76baab414c9d432d31c661668b1bd07e3f80Mindy Pereira 585086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira private OnCheckedItemChangedListener mCheckedItemChangedListener; 595086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira 6018987c44006700a2bfe614ec1e39a29ed5b23d78Mindy Pereira private static final String TAG = "RecipAlternates"; 6118987c44006700a2bfe614ec1e39a29ed5b23d78Mindy Pereira 6280f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor public static final int QUERY_TYPE_EMAIL = 0; 6380f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor public static final int QUERY_TYPE_PHONE = 1; 647a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy private final Long mDirectoryId; 65b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin private DropdownChipLayouter mDropdownChipLayouter; 6680f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor 677a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy private static final Map<String, String> sCorrectedPhotoUris = new HashMap<String, String>(); 687a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy 6916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp public interface RecipientMatchCallback { 7094fa301de71cc110671802eba8376c275b4055a4Scott Kennedy public void matchesFound(Map<String, RecipientEntry> results); 7194fa301de71cc110671802eba8376c275b4055a4Scott Kennedy /** 7294fa301de71cc110671802eba8376c275b4055a4Scott Kennedy * Called with all addresses that could not be resolved to valid recipients. 7394fa301de71cc110671802eba8376c275b4055a4Scott Kennedy */ 74f7e202d8b83bfbd73ca47ba7843ebc4dd57c2fa4Scott Kennedy public void matchesNotFound(Set<String> unfoundAddresses); 7516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 7616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp 7776f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert public static void getMatchingRecipients(Context context, BaseRecipientAdapter adapter, 7876f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert ArrayList<String> inAddresses, Account account, RecipientMatchCallback callback) { 7976f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert getMatchingRecipients(context, adapter, inAddresses, QUERY_TYPE_EMAIL, account, callback); 8080f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } 8180f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor 821852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira /** 831852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira * Get a HashMap of address to RecipientEntry that contains all contact 841852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira * information for a contact with the provided address, if one exists. This 851852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira * may block the UI, so run it in an async task. 861852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira * 871852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira * @param context Context. 887211747e51623ae1305053f533c09dd335e013a2Daisuke Miyakawa * @param inAddresses Array of addresses on which to perform the lookup. 8916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp * @param callback RecipientMatchCallback called when a match or matches are found. 901852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira */ 9176f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert public static void getMatchingRecipients(Context context, BaseRecipientAdapter adapter, 9276f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert ArrayList<String> inAddresses, int addressType, Account account, 9376f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert RecipientMatchCallback callback) { 9480f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor Queries.Query query; 9580f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor if (addressType == QUERY_TYPE_EMAIL) { 9680f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor query = Queries.EMAIL; 9780f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } else { 9880f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor query = Queries.PHONE; 9980f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } 10003cfe3eee5635e419ab1d70d463b2b8beac72f00Mindy Pereira int addressesSize = Math.min(MAX_LOOKUPS, inAddresses.size()); 10116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp HashSet<String> addresses = new HashSet<String>(); 1021852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira StringBuilder bindString = new StringBuilder(); 1031852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira // Create the "?" string and set up arguments. 1041852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira for (int i = 0; i < addressesSize; i++) { 10503cfe3eee5635e419ab1d70d463b2b8beac72f00Mindy Pereira Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(inAddresses.get(i).toLowerCase()); 10616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp addresses.add(tokens.length > 0 ? tokens[0].getAddress() : inAddresses.get(i)); 1071852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira bindString.append("?"); 1081852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira if (i < addressesSize - 1) { 1091852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira bindString.append(","); 1101852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira } 1111852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira } 1121852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira 11318987c44006700a2bfe614ec1e39a29ed5b23d78Mindy Pereira if (Log.isLoggable(TAG, Log.DEBUG)) { 11418987c44006700a2bfe614ec1e39a29ed5b23d78Mindy Pereira Log.d(TAG, "Doing reverse lookup for " + addresses.toString()); 11518987c44006700a2bfe614ec1e39a29ed5b23d78Mindy Pereira } 11618987c44006700a2bfe614ec1e39a29ed5b23d78Mindy Pereira 11716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp String[] addressArray = new String[addresses.size()]; 11816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp addresses.toArray(addressArray); 11916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp HashMap<String, RecipientEntry> recipientEntries = null; 12016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp Cursor c = null; 12116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp 12216923ee63a79fce4be3f62b08bcd1f80617c1205mindyp try { 12316923ee63a79fce4be3f62b08bcd1f80617c1205mindyp c = context.getContentResolver().query( 12416923ee63a79fce4be3f62b08bcd1f80617c1205mindyp query.getContentUri(), 12516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp query.getProjection(), 12616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp query.getProjection()[Queries.Query.DESTINATION] + " IN (" 12716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp + bindString.toString() + ")", addressArray, null); 1287a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy recipientEntries = processContactEntries(c, null /* directoryId */); 12916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp callback.matchesFound(recipientEntries); 13016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } finally { 13116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp if (c != null) { 13216923ee63a79fce4be3f62b08bcd1f80617c1205mindyp c.close(); 13316923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 13416923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 1358af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein 1368af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein final Set<String> matchesNotFound = new HashSet<String>(); 1378af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein 1388af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein getMatchingRecipientsFromDirectoryQueries(context, recipientEntries, 1398af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein addresses, account, matchesNotFound, query, callback); 1408af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein 1418af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein getMatchingRecipientsFromExtensionMatcher(adapter, matchesNotFound, callback); 1428af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein } 1438af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein 1448af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein public static void getMatchingRecipientsFromDirectoryQueries(Context context, 1458af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein Map<String, RecipientEntry> recipientEntries, Set<String> addresses, 1468af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein Account account, Set<String> matchesNotFound, 1478af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein RecipientMatchCallback callback) { 1488af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein getMatchingRecipientsFromDirectoryQueries( 1498af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein context, recipientEntries, addresses, account, 1508af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein matchesNotFound, Queries.EMAIL, callback); 1518af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein } 1528af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein 1538af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein private static void getMatchingRecipientsFromDirectoryQueries(Context context, 1548af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein Map<String, RecipientEntry> recipientEntries, Set<String> addresses, 1558af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein Account account, Set<String> matchesNotFound, Queries.Query query, 1568af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein RecipientMatchCallback callback) { 15716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp // See if any entries did not resolve; if so, we need to check other 15816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp // directories 1598af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein 16016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp if (recipientEntries.size() < addresses.size()) { 16116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp final List<DirectorySearchParams> paramsList; 162539c2b12cca5e9bccd9acabc4721c876058a68d4Scott Kennedy Cursor directoryCursor = null; 163539c2b12cca5e9bccd9acabc4721c876058a68d4Scott Kennedy try { 164539c2b12cca5e9bccd9acabc4721c876058a68d4Scott Kennedy directoryCursor = context.getContentResolver().query(DirectoryListQuery.URI, 165539c2b12cca5e9bccd9acabc4721c876058a68d4Scott Kennedy DirectoryListQuery.PROJECTION, null, null, null); 166771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy if (directoryCursor == null) { 167771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy paramsList = null; 168771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy } else { 169771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy paramsList = BaseRecipientAdapter.setupOtherDirectories(context, 170771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy directoryCursor, account); 171771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy } 172539c2b12cca5e9bccd9acabc4721c876058a68d4Scott Kennedy } finally { 173539c2b12cca5e9bccd9acabc4721c876058a68d4Scott Kennedy if (directoryCursor != null) { 174539c2b12cca5e9bccd9acabc4721c876058a68d4Scott Kennedy directoryCursor.close(); 175539c2b12cca5e9bccd9acabc4721c876058a68d4Scott Kennedy } 176539c2b12cca5e9bccd9acabc4721c876058a68d4Scott Kennedy } 17716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp // Run a directory query for each unmatched recipient. 17816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp HashSet<String> unresolvedAddresses = new HashSet<String>(); 17916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp for (String address : addresses) { 18016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp if (!recipientEntries.containsKey(address)) { 18116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp unresolvedAddresses.add(address); 18216923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 18316923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 18494fa301de71cc110671802eba8376c275b4055a4Scott Kennedy 18594fa301de71cc110671802eba8376c275b4055a4Scott Kennedy matchesNotFound.addAll(unresolvedAddresses); 18694fa301de71cc110671802eba8376c275b4055a4Scott Kennedy 187771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy if (paramsList != null) { 188771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy Cursor directoryContactsCursor = null; 189771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy for (String unresolvedAddress : unresolvedAddresses) { 1907a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy Long directoryId = null; 191771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy for (int i = 0; i < paramsList.size(); i++) { 192771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy try { 193771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy directoryContactsCursor = doQuery(unresolvedAddress, 1, 194771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy paramsList.get(i).directoryId, account, 195771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy context.getContentResolver(), query); 196771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy } finally { 197771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy if (directoryContactsCursor != null 198771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy && directoryContactsCursor.getCount() == 0) { 199771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy directoryContactsCursor.close(); 200771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy directoryContactsCursor = null; 201771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy } else { 2027a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy directoryId = paramsList.get(i).directoryId; 203771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy break; 204771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy } 20518987c44006700a2bfe614ec1e39a29ed5b23d78Mindy Pereira } 20616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 207771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy if (directoryContactsCursor != null) { 208771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy try { 209771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy final Map<String, RecipientEntry> entries = 2107a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy processContactEntries(directoryContactsCursor, directoryId); 21194fa301de71cc110671802eba8376c275b4055a4Scott Kennedy 212771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy for (final String address : entries.keySet()) { 213771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy matchesNotFound.remove(address); 214771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy } 21594fa301de71cc110671802eba8376c275b4055a4Scott Kennedy 216771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy callback.matchesFound(entries); 217771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy } finally { 218771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy directoryContactsCursor.close(); 219771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy } 22016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 2211852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira } 2221852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira } 2231852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira } 2248af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein } 22594fa301de71cc110671802eba8376c275b4055a4Scott Kennedy 2268af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein public static void getMatchingRecipientsFromExtensionMatcher(BaseRecipientAdapter adapter, 2278af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein Set<String> matchesNotFound, RecipientMatchCallback callback) { 22876f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert // If no matches found in contact provider or the directories, try the extension 22976f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert // matcher. 23076f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert // todo (aalbert): This whole method needs to be in the adapter? 23176f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert if (adapter != null) { 23276f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert final Map<String, RecipientEntry> entries = 23376f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert adapter.getMatchingRecipients(matchesNotFound); 23476f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert if (entries != null && entries.size() > 0) { 23576f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert callback.matchesFound(entries); 23676f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert for (final String address : entries.keySet()) { 23776f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert matchesNotFound.remove(address); 23876f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert } 23976f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert } 24076f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert } 24194fa301de71cc110671802eba8376c275b4055a4Scott Kennedy callback.matchesNotFound(matchesNotFound); 24216923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 24316923ee63a79fce4be3f62b08bcd1f80617c1205mindyp 2447a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy private static HashMap<String, RecipientEntry> processContactEntries(Cursor c, 2457a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy Long directoryId) { 24616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp HashMap<String, RecipientEntry> recipientEntries = new HashMap<String, RecipientEntry>(); 24716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp if (c != null && c.moveToFirst()) { 24816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp do { 24916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp String address = c.getString(Queries.Query.DESTINATION); 250ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy 251ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy final RecipientEntry newRecipientEntry = RecipientEntry.constructTopLevelEntry( 25216923ee63a79fce4be3f62b08bcd1f80617c1205mindyp c.getString(Queries.Query.NAME), 25316923ee63a79fce4be3f62b08bcd1f80617c1205mindyp c.getInt(Queries.Query.DISPLAY_NAME_SOURCE), 25416923ee63a79fce4be3f62b08bcd1f80617c1205mindyp c.getString(Queries.Query.DESTINATION), 25516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp c.getInt(Queries.Query.DESTINATION_TYPE), 25616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp c.getString(Queries.Query.DESTINATION_LABEL), 25716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp c.getLong(Queries.Query.CONTACT_ID), 2587a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy directoryId, 25916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp c.getLong(Queries.Query.DATA_ID), 26016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp c.getString(Queries.Query.PHOTO_THUMBNAIL_URI), 261514f8a75f72fa2e735418ffb5d6e30aa914fbe7bScott Kennedy true, 2627a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy c.getString(Queries.Query.LOOKUP_KEY)); 263ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy 264ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy /* 265ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy * In certain situations, we may have two results for one address, where one of the 266ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy * results is just the email address, and the other has a name and photo, so we want 267ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy * to use the better one. 268ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy */ 269ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy final RecipientEntry recipientEntry = 270ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy getBetterRecipient(recipientEntries.get(address), newRecipientEntry); 271ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy 272ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy recipientEntries.put(address, recipientEntry); 27316923ee63a79fce4be3f62b08bcd1f80617c1205mindyp if (Log.isLoggable(TAG, Log.DEBUG)) { 27416923ee63a79fce4be3f62b08bcd1f80617c1205mindyp Log.d(TAG, "Received reverse look up information for " + address 27516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp + " RESULTS: " 27616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp + " NAME : " + c.getString(Queries.Query.NAME) 27716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp + " CONTACT ID : " + c.getLong(Queries.Query.CONTACT_ID) 27816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp + " ADDRESS :" + c.getString(Queries.Query.DESTINATION)); 27916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 28016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } while (c.moveToNext()); 28116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 2821852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira return recipientEntries; 2831852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira } 2841852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira 285ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy /** 286ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy * Given two {@link RecipientEntry}s for the same email address, this will return the one that 287ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy * contains more complete information for display purposes. Defaults to <code>entry2</code> if 288ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy * no significant differences are found. 289ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy */ 29078f38a09c9753c0ac1838ce0bfd3a6bc1a307ff7Scott Kennedy static RecipientEntry getBetterRecipient(final RecipientEntry entry1, 291ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy final RecipientEntry entry2) { 292ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy // If only one has passed in, use it 293ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy if (entry2 == null) { 294ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy return entry1; 295ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy } 296ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy 297ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy if (entry1 == null) { 298ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy return entry2; 299ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy } 300ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy 301ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy // If only one has a display name, use it 302ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy if (!TextUtils.isEmpty(entry1.getDisplayName()) 303ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy && TextUtils.isEmpty(entry2.getDisplayName())) { 304ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy return entry1; 305ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy } 306ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy 307ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy if (!TextUtils.isEmpty(entry2.getDisplayName()) 308ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy && TextUtils.isEmpty(entry1.getDisplayName())) { 309ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy return entry2; 310ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy } 311ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy 312ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy // If only one has a display name that is not the same as the destination, use it 313ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy if (!TextUtils.equals(entry1.getDisplayName(), entry1.getDestination()) 314ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy && TextUtils.equals(entry2.getDisplayName(), entry2.getDestination())) { 315ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy return entry1; 316ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy } 317ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy 318ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy if (!TextUtils.equals(entry2.getDisplayName(), entry2.getDestination()) 319ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy && TextUtils.equals(entry1.getDisplayName(), entry1.getDestination())) { 320ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy return entry2; 321ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy } 322ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy 323ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy // If only one has a photo, use it 324ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy if ((entry1.getPhotoThumbnailUri() != null || entry1.getPhotoBytes() != null) 325ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy && (entry2.getPhotoThumbnailUri() == null && entry2.getPhotoBytes() == null)) { 326ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy return entry1; 327ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy } 328ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy 329ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy if ((entry2.getPhotoThumbnailUri() != null || entry2.getPhotoBytes() != null) 330ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy && (entry1.getPhotoThumbnailUri() == null && entry1.getPhotoBytes() == null)) { 331ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy return entry2; 332ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy } 333ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy 334ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy // Go with the second option as a default 335ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy return entry2; 336ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy } 337ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy 33816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp private static Cursor doQuery(CharSequence constraint, int limit, Long directoryId, 33916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp Account account, ContentResolver resolver, Query query) { 34016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp final Uri.Builder builder = query 34116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp .getContentFilterUri() 34216923ee63a79fce4be3f62b08bcd1f80617c1205mindyp .buildUpon() 34316923ee63a79fce4be3f62b08bcd1f80617c1205mindyp .appendPath(constraint.toString()) 34416923ee63a79fce4be3f62b08bcd1f80617c1205mindyp .appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY, 34516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp String.valueOf(limit + BaseRecipientAdapter.ALLOWANCE_FOR_DUPLICATES)); 34616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp if (directoryId != null) { 34716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, 34816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp String.valueOf(directoryId)); 34916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 35016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp if (account != null) { 35116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp builder.appendQueryParameter(BaseRecipientAdapter.PRIMARY_ACCOUNT_NAME, account.name); 35216923ee63a79fce4be3f62b08bcd1f80617c1205mindyp builder.appendQueryParameter(BaseRecipientAdapter.PRIMARY_ACCOUNT_TYPE, account.type); 35316923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 35416923ee63a79fce4be3f62b08bcd1f80617c1205mindyp final Cursor cursor = resolver.query(builder.build(), query.getProjection(), null, null, 35516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp null); 35616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp return cursor; 35716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 35816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp 3597a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy public RecipientAlternatesAdapter(Context context, long contactId, Long directoryId, 3607a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy String lookupKey, long currentId, int queryMode, OnCheckedItemChangedListener listener, 3617a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy DropdownChipLayouter dropdownChipLayouter) { 3627a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy super(context, 3637a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy getCursorForConstruction(context, contactId, directoryId, lookupKey, queryMode), 0); 36497d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira mCurrentId = currentId; 3657a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy mDirectoryId = directoryId; 3665086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira mCheckedItemChangedListener = listener; 36780f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor 368b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin mDropdownChipLayouter = dropdownChipLayouter; 36980f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } 37080f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor 3717a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy private static Cursor getCursorForConstruction(Context context, long contactId, 3727a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy Long directoryId, String lookupKey, int queryType) { 373a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki final Cursor cursor; 3747a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy final String desiredMimeType; 37580f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor if (queryType == QUERY_TYPE_EMAIL) { 3767a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy final Uri uri; 3777a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy final StringBuilder selection = new StringBuilder(); 3787a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy selection.append(Queries.EMAIL.getProjection()[Queries.Query.CONTACT_ID]); 3797a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy selection.append(" = ?"); 3807a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy 3817a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy if (directoryId == null || lookupKey == null) { 3827a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy uri = Queries.EMAIL.getContentUri(); 3837a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy desiredMimeType = null; 3847a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } else { 3857a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy final Uri.Builder builder = Contacts.getLookupUri(contactId, lookupKey).buildUpon(); 3867a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy builder.appendPath(Contacts.Entity.CONTENT_DIRECTORY) 3877a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, 3887a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy String.valueOf(directoryId)); 3897a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy uri = builder.build(); 3907a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy desiredMimeType = ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE; 3917a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } 392a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki cursor = context.getContentResolver().query( 3937a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy uri, 39480f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor Queries.EMAIL.getProjection(), 3957a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy selection.toString(), new String[] { 39680f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor String.valueOf(contactId) 39780f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor }, null); 39880f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } else { 3997a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy final Uri uri; 4007a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy final StringBuilder selection = new StringBuilder(); 4017a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy selection.append(Queries.PHONE.getProjection()[Queries.Query.CONTACT_ID]); 4027a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy selection.append(" = ?"); 4037a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy 4047a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy if (lookupKey == null) { 4057a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy uri = Queries.PHONE.getContentUri(); 4067a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy desiredMimeType = null; 4077a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } else { 4087a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy final Uri.Builder builder = Contacts.getLookupUri(contactId, lookupKey).buildUpon(); 4097a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy builder.appendPath(Contacts.Entity.CONTENT_DIRECTORY) 4107a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, 4117a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy String.valueOf(directoryId)); 4127a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy uri = builder.build(); 4137a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy desiredMimeType = ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE; 4147a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } 415a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki cursor = context.getContentResolver().query( 4167a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy uri, 41780f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor Queries.PHONE.getProjection(), 4187a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy selection.toString(), new String[] { 41980f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor String.valueOf(contactId) 42080f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor }, null); 42180f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } 4227a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy 4237a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy final Cursor resultCursor = removeUndesiredDestinations(cursor, desiredMimeType, lookupKey); 4247a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy cursor.close(); 4257a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy 4267a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy return resultCursor; 427a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki } 428a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki 429a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki /** 430a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki * @return a new cursor based on the given cursor with all duplicate destinations removed. 431a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki * 432a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki * It's only intended to use for the alternate list, so... 433a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki * - This method ignores all other fields and dedupe solely on the destination. Normally, 434a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki * if a cursor contains multiple contacts and they have the same destination, we'd still want 435a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki * to show both. 436a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki * - This method creates a MatrixCursor, so all data will be kept in memory. We wouldn't want 437a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki * to do this if the original cursor is large, but it's okay here because the alternate list 438a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki * won't be that big. 4397a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy * 4407a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy * @param desiredMimeType If this is non-<code>null</code>, only entries with this mime type 4417a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy * will be added to the cursor 4427a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy * @param lookupKey The lookup key used for this contact if there isn't one in the cursor. This 4437a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy * should be the same one used in the query that returned the cursor 444a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki */ 445a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki // Visible for testing 4467a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy static Cursor removeUndesiredDestinations(final Cursor original, final String desiredMimeType, 4477a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy final String lookupKey) { 448a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki final MatrixCursor result = new MatrixCursor( 449a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki original.getColumnNames(), original.getCount()); 450a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki final HashSet<String> destinationsSeen = new HashSet<String>(); 451a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki 4527a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy String defaultDisplayName = null; 4537a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy String defaultPhotoThumbnailUri = null; 4547a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy int defaultDisplayNameSource = 0; 4557a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy 4567a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy // Find some nice defaults in case we need them 4577a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy original.moveToPosition(-1); 4587a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy while (original.moveToNext()) { 4597a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy final String mimeType = original.getString(Query.MIME_TYPE); 4607a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy 4617a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy if (ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE.equals( 4627a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy mimeType)) { 4637a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy // Store this data 4647a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy defaultDisplayName = original.getString(Query.NAME); 4657a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy defaultPhotoThumbnailUri = original.getString(Query.PHOTO_THUMBNAIL_URI); 4667a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy defaultDisplayNameSource = original.getInt(Query.DISPLAY_NAME_SOURCE); 4677a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy break; 4687a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } 4697a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } 4707a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy 471a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki original.moveToPosition(-1); 472a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki while (original.moveToNext()) { 4737a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy if (desiredMimeType != null) { 4747a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy final String mimeType = original.getString(Query.MIME_TYPE); 4757a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy if (!desiredMimeType.equals(mimeType)) { 4767a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy continue; 4777a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } 4787a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } 479a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki final String destination = original.getString(Query.DESTINATION); 480a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki if (destinationsSeen.contains(destination)) { 481a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki continue; 482a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki } 483a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki destinationsSeen.add(destination); 484a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki 4857a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy final Object[] row = new Object[] { 486a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki original.getString(Query.NAME), 487a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki original.getString(Query.DESTINATION), 488a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki original.getInt(Query.DESTINATION_TYPE), 489a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki original.getString(Query.DESTINATION_LABEL), 490a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki original.getLong(Query.CONTACT_ID), 491a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki original.getLong(Query.DATA_ID), 492a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki original.getString(Query.PHOTO_THUMBNAIL_URI), 4937a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy original.getInt(Query.DISPLAY_NAME_SOURCE), 4947a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy original.getString(Query.LOOKUP_KEY), 4957a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy original.getString(Query.MIME_TYPE) 4967a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy }; 4977a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy 4987a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy if (row[Query.NAME] == null) { 4997a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy row[Query.NAME] = defaultDisplayName; 5007a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } 5017a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy if (row[Query.PHOTO_THUMBNAIL_URI] == null) { 5027a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy row[Query.PHOTO_THUMBNAIL_URI] = defaultPhotoThumbnailUri; 5037a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } 5047a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy if ((Integer) row[Query.DISPLAY_NAME_SOURCE] == 0) { 5057a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy row[Query.DISPLAY_NAME_SOURCE] = defaultDisplayNameSource; 5067a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } 5077a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy if (row[Query.LOOKUP_KEY] == null) { 5087a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy row[Query.LOOKUP_KEY] = lookupKey; 5097a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } 5107a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy 5117a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy // Ensure we don't have two '?' like content://.../...?account_name=...?sz=... 5127a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy final String photoThumbnailUri = (String) row[Query.PHOTO_THUMBNAIL_URI]; 5137a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy if (photoThumbnailUri != null) { 5147a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy if (sCorrectedPhotoUris.containsKey(photoThumbnailUri)) { 5157a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy row[Query.PHOTO_THUMBNAIL_URI] = sCorrectedPhotoUris.get(photoThumbnailUri); 5167a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } else if (photoThumbnailUri.indexOf('?') != photoThumbnailUri.lastIndexOf('?')) { 5177a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy final String[] parts = photoThumbnailUri.split("\\?"); 5187a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy final StringBuilder correctedUriBuilder = new StringBuilder(); 5197a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy for (int i = 0; i < parts.length; i++) { 5207a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy if (i == 1) { 5217a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy correctedUriBuilder.append("?"); // We only want one of these 5227a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } else if (i > 1) { 5237a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy correctedUriBuilder.append("&"); // And we want these elsewhere 5247a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } 5257a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy correctedUriBuilder.append(parts[i]); 5267a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } 5277a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy 5287a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy final String correctedUri = correctedUriBuilder.toString(); 5297a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy sCorrectedPhotoUris.put(photoThumbnailUri, correctedUri); 5307a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy row[Query.PHOTO_THUMBNAIL_URI] = correctedUri; 5317a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } 5327a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } 5337a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy 5347a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy result.addRow(row); 535a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki } 536a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki 537a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki return result; 53897d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira } 53997d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira 54097d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira @Override 54197d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira public long getItemId(int position) { 54297d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira Cursor c = getCursor(); 5433bb52162b7e842243d4a14e73c15b20dbd1804d7Mindy Pereira if (c.moveToPosition(position)) { 54480f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor c.getLong(Queries.Query.DATA_ID); 5453bb52162b7e842243d4a14e73c15b20dbd1804d7Mindy Pereira } 5463bb52162b7e842243d4a14e73c15b20dbd1804d7Mindy Pereira return -1; 54797d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira } 54897d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira 54997d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira public RecipientEntry getRecipientEntry(int position) { 55097d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira Cursor c = getCursor(); 55197d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira c.moveToPosition(position); 55280f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor return RecipientEntry.constructTopLevelEntry( 55380f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor c.getString(Queries.Query.NAME), 55400adb32f3cea49ec82467c0e1a9e42659b556836Makoto Onuki c.getInt(Queries.Query.DISPLAY_NAME_SOURCE), 55580f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor c.getString(Queries.Query.DESTINATION), 55680f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor c.getInt(Queries.Query.DESTINATION_TYPE), 55780f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor c.getString(Queries.Query.DESTINATION_LABEL), 55880f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor c.getLong(Queries.Query.CONTACT_ID), 5597a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy mDirectoryId, 56080f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor c.getLong(Queries.Query.DATA_ID), 561ccb8e237ec80934d1c983bb61f66b75541786ddcmindyp c.getString(Queries.Query.PHOTO_THUMBNAIL_URI), 562514f8a75f72fa2e735418ffb5d6e30aa914fbe7bScott Kennedy true, 5637a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy c.getString(Queries.Query.LOOKUP_KEY)); 56497d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira } 56597d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira 56697d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira @Override 56797d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira public View getView(int position, View convertView, ViewGroup parent) { 56867ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira Cursor cursor = getCursor(); 56967ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira cursor.moveToPosition(position); 57097d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira if (convertView == null) { 571b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin convertView = mDropdownChipLayouter.newView(); 572007a76baab414c9d432d31c661668b1bd07e3f80Mindy Pereira } 57380f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor if (cursor.getLong(Queries.Query.DATA_ID) == mCurrentId) { 574007a76baab414c9d432d31c661668b1bd07e3f80Mindy Pereira mCheckedItemPosition = position; 5755086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira if (mCheckedItemChangedListener != null) { 5765086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira mCheckedItemChangedListener.onCheckedItemChanged(mCheckedItemPosition); 5775086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira } 57897d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira } 57967ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira bindView(convertView, convertView.getContext(), cursor); 58097d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira return convertView; 58197d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira } 58297d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira 58397d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira @Override 58497d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira public void bindView(View view, Context context, Cursor cursor) { 58567ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira int position = cursor.getPosition(); 58667ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira RecipientEntry entry = getRecipientEntry(position); 587b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 588b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin mDropdownChipLayouter.bindView(view, null, entry, position, 589b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin AdapterType.RECIPIENT_ALTERNATES, null); 59097d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira } 59197d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira 59297d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira @Override 59397d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira public View newView(Context context, Cursor cursor, ViewGroup parent) { 594b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin return mDropdownChipLayouter.newView(); 59597d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira } 59697d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira 5975086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira /*package*/ static interface OnCheckedItemChangedListener { 5985086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira public void onCheckedItemChanged(int position); 59997d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira } 60097d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira} 601