RecipientAlternatesAdapter.java revision 4db8cccf3332ad7c6fb1915f9f0f169953c3953a
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; 244db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Caoimport android.graphics.drawable.StateListDrawable; 2516923ee63a79fce4be3f62b08bcd1f80617c1205mindypimport android.net.Uri; 2616923ee63a79fce4be3f62b08bcd1f80617c1205mindypimport android.provider.ContactsContract; 277a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedyimport android.provider.ContactsContract.Contacts; 28ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedyimport android.text.TextUtils; 291852931de1e24e77cb708f4ba010eaa269426657Mindy Pereiraimport android.text.util.Rfc822Token; 301852931de1e24e77cb708f4ba010eaa269426657Mindy Pereiraimport android.text.util.Rfc822Tokenizer; 3118987c44006700a2bfe614ec1e39a29ed5b23d78Mindy Pereiraimport android.util.Log; 3297d7768576ff27d779d68f77e23925b69f3290bcMindy Pereiraimport android.view.View; 3397d7768576ff27d779d68f77e23925b69f3290bcMindy Pereiraimport android.view.ViewGroup; 3497d7768576ff27d779d68f77e23925b69f3290bcMindy Pereiraimport android.widget.CursorAdapter; 3597d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira 3616923ee63a79fce4be3f62b08bcd1f80617c1205mindypimport com.android.ex.chips.BaseRecipientAdapter.DirectoryListQuery; 3716923ee63a79fce4be3f62b08bcd1f80617c1205mindypimport com.android.ex.chips.BaseRecipientAdapter.DirectorySearchParams; 38b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Linimport com.android.ex.chips.DropdownChipLayouter.AdapterType; 3980f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylorimport com.android.ex.chips.Queries.Query; 40a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki 4103cfe3eee5635e419ab1d70d463b2b8beac72f00Mindy Pereiraimport java.util.ArrayList; 421852931de1e24e77cb708f4ba010eaa269426657Mindy Pereiraimport java.util.HashMap; 43a5d37c8a968edf94755215617b593d3f61738a92Makoto Onukiimport java.util.HashSet; 4416923ee63a79fce4be3f62b08bcd1f80617c1205mindypimport java.util.List; 4594fa301de71cc110671802eba8376c275b4055a4Scott Kennedyimport java.util.Map; 4694fa301de71cc110671802eba8376c275b4055a4Scott Kennedyimport java.util.Set; 471852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira 4880f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor/** 4980f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor * RecipientAlternatesAdapter backs the RecipientEditTextView for managing contacts 5080f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor * queried by email or by phone number. 5180f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor */ 5297d7768576ff27d779d68f77e23925b69f3290bcMindy Pereirapublic class RecipientAlternatesAdapter extends CursorAdapter { 538af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein public static final int MAX_LOOKUPS = 50; 5497d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira 5597d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira private final long mCurrentId; 5697d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira 57007a76baab414c9d432d31c661668b1bd07e3f80Mindy Pereira private int mCheckedItemPosition = -1; 58007a76baab414c9d432d31c661668b1bd07e3f80Mindy Pereira 595086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira private OnCheckedItemChangedListener mCheckedItemChangedListener; 605086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira 6118987c44006700a2bfe614ec1e39a29ed5b23d78Mindy Pereira private static final String TAG = "RecipAlternates"; 6218987c44006700a2bfe614ec1e39a29ed5b23d78Mindy Pereira 6380f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor public static final int QUERY_TYPE_EMAIL = 0; 6480f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor public static final int QUERY_TYPE_PHONE = 1; 657a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy private final Long mDirectoryId; 66b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin private DropdownChipLayouter mDropdownChipLayouter; 674db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao private final StateListDrawable mDeleteDrawable; 6880f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor 697a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy private static final Map<String, String> sCorrectedPhotoUris = new HashMap<String, String>(); 707a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy 7116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp public interface RecipientMatchCallback { 7294fa301de71cc110671802eba8376c275b4055a4Scott Kennedy public void matchesFound(Map<String, RecipientEntry> results); 7394fa301de71cc110671802eba8376c275b4055a4Scott Kennedy /** 7494fa301de71cc110671802eba8376c275b4055a4Scott Kennedy * Called with all addresses that could not be resolved to valid recipients. 7594fa301de71cc110671802eba8376c275b4055a4Scott Kennedy */ 76f7e202d8b83bfbd73ca47ba7843ebc4dd57c2fa4Scott Kennedy public void matchesNotFound(Set<String> unfoundAddresses); 7716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 7816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp 7976f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert public static void getMatchingRecipients(Context context, BaseRecipientAdapter adapter, 8076f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert ArrayList<String> inAddresses, Account account, RecipientMatchCallback callback) { 8176f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert getMatchingRecipients(context, adapter, inAddresses, QUERY_TYPE_EMAIL, account, callback); 8280f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } 8380f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor 841852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira /** 851852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira * Get a HashMap of address to RecipientEntry that contains all contact 861852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira * information for a contact with the provided address, if one exists. This 871852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira * may block the UI, so run it in an async task. 881852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira * 891852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira * @param context Context. 907211747e51623ae1305053f533c09dd335e013a2Daisuke Miyakawa * @param inAddresses Array of addresses on which to perform the lookup. 9116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp * @param callback RecipientMatchCallback called when a match or matches are found. 921852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira */ 9376f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert public static void getMatchingRecipients(Context context, BaseRecipientAdapter adapter, 9476f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert ArrayList<String> inAddresses, int addressType, Account account, 9576f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert RecipientMatchCallback callback) { 9680f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor Queries.Query query; 9780f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor if (addressType == QUERY_TYPE_EMAIL) { 9880f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor query = Queries.EMAIL; 9980f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } else { 10080f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor query = Queries.PHONE; 10180f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } 10203cfe3eee5635e419ab1d70d463b2b8beac72f00Mindy Pereira int addressesSize = Math.min(MAX_LOOKUPS, inAddresses.size()); 10316923ee63a79fce4be3f62b08bcd1f80617c1205mindyp HashSet<String> addresses = new HashSet<String>(); 1041852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira StringBuilder bindString = new StringBuilder(); 1051852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira // Create the "?" string and set up arguments. 1061852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira for (int i = 0; i < addressesSize; i++) { 10703cfe3eee5635e419ab1d70d463b2b8beac72f00Mindy Pereira Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(inAddresses.get(i).toLowerCase()); 10816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp addresses.add(tokens.length > 0 ? tokens[0].getAddress() : inAddresses.get(i)); 1091852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira bindString.append("?"); 1101852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira if (i < addressesSize - 1) { 1111852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira bindString.append(","); 1121852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira } 1131852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira } 1141852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira 11518987c44006700a2bfe614ec1e39a29ed5b23d78Mindy Pereira if (Log.isLoggable(TAG, Log.DEBUG)) { 11618987c44006700a2bfe614ec1e39a29ed5b23d78Mindy Pereira Log.d(TAG, "Doing reverse lookup for " + addresses.toString()); 11718987c44006700a2bfe614ec1e39a29ed5b23d78Mindy Pereira } 11818987c44006700a2bfe614ec1e39a29ed5b23d78Mindy Pereira 11916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp String[] addressArray = new String[addresses.size()]; 12016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp addresses.toArray(addressArray); 12116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp HashMap<String, RecipientEntry> recipientEntries = null; 12216923ee63a79fce4be3f62b08bcd1f80617c1205mindyp Cursor c = null; 12316923ee63a79fce4be3f62b08bcd1f80617c1205mindyp 12416923ee63a79fce4be3f62b08bcd1f80617c1205mindyp try { 12516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp c = context.getContentResolver().query( 12616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp query.getContentUri(), 12716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp query.getProjection(), 12816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp query.getProjection()[Queries.Query.DESTINATION] + " IN (" 12916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp + bindString.toString() + ")", addressArray, null); 1307a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy recipientEntries = processContactEntries(c, null /* directoryId */); 13116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp callback.matchesFound(recipientEntries); 13216923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } finally { 13316923ee63a79fce4be3f62b08bcd1f80617c1205mindyp if (c != null) { 13416923ee63a79fce4be3f62b08bcd1f80617c1205mindyp c.close(); 13516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 13616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 1378af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein 1388af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein final Set<String> matchesNotFound = new HashSet<String>(); 1398af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein 1408af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein getMatchingRecipientsFromDirectoryQueries(context, recipientEntries, 1418af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein addresses, account, matchesNotFound, query, callback); 1428af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein 1438af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein getMatchingRecipientsFromExtensionMatcher(adapter, matchesNotFound, callback); 1448af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein } 1458af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein 1468af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein public static void getMatchingRecipientsFromDirectoryQueries(Context context, 1478af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein Map<String, RecipientEntry> recipientEntries, Set<String> addresses, 1488af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein Account account, Set<String> matchesNotFound, 1498af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein RecipientMatchCallback callback) { 1508af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein getMatchingRecipientsFromDirectoryQueries( 1518af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein context, recipientEntries, addresses, account, 1528af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein matchesNotFound, Queries.EMAIL, callback); 1538af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein } 1548af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein 1558af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein private static void getMatchingRecipientsFromDirectoryQueries(Context context, 1568af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein Map<String, RecipientEntry> recipientEntries, Set<String> addresses, 1578af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein Account account, Set<String> matchesNotFound, Queries.Query query, 1588af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein RecipientMatchCallback callback) { 15916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp // See if any entries did not resolve; if so, we need to check other 16016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp // directories 1618af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein 16216923ee63a79fce4be3f62b08bcd1f80617c1205mindyp if (recipientEntries.size() < addresses.size()) { 16316923ee63a79fce4be3f62b08bcd1f80617c1205mindyp final List<DirectorySearchParams> paramsList; 164539c2b12cca5e9bccd9acabc4721c876058a68d4Scott Kennedy Cursor directoryCursor = null; 165539c2b12cca5e9bccd9acabc4721c876058a68d4Scott Kennedy try { 166539c2b12cca5e9bccd9acabc4721c876058a68d4Scott Kennedy directoryCursor = context.getContentResolver().query(DirectoryListQuery.URI, 167539c2b12cca5e9bccd9acabc4721c876058a68d4Scott Kennedy DirectoryListQuery.PROJECTION, null, null, null); 168771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy if (directoryCursor == null) { 169771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy paramsList = null; 170771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy } else { 171771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy paramsList = BaseRecipientAdapter.setupOtherDirectories(context, 172771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy directoryCursor, account); 173771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy } 174539c2b12cca5e9bccd9acabc4721c876058a68d4Scott Kennedy } finally { 175539c2b12cca5e9bccd9acabc4721c876058a68d4Scott Kennedy if (directoryCursor != null) { 176539c2b12cca5e9bccd9acabc4721c876058a68d4Scott Kennedy directoryCursor.close(); 177539c2b12cca5e9bccd9acabc4721c876058a68d4Scott Kennedy } 178539c2b12cca5e9bccd9acabc4721c876058a68d4Scott Kennedy } 17916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp // Run a directory query for each unmatched recipient. 18016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp HashSet<String> unresolvedAddresses = new HashSet<String>(); 18116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp for (String address : addresses) { 18216923ee63a79fce4be3f62b08bcd1f80617c1205mindyp if (!recipientEntries.containsKey(address)) { 18316923ee63a79fce4be3f62b08bcd1f80617c1205mindyp unresolvedAddresses.add(address); 18416923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 18516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 18694fa301de71cc110671802eba8376c275b4055a4Scott Kennedy 18794fa301de71cc110671802eba8376c275b4055a4Scott Kennedy matchesNotFound.addAll(unresolvedAddresses); 18894fa301de71cc110671802eba8376c275b4055a4Scott Kennedy 189771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy if (paramsList != null) { 190771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy Cursor directoryContactsCursor = null; 191771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy for (String unresolvedAddress : unresolvedAddresses) { 1927a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy Long directoryId = null; 193771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy for (int i = 0; i < paramsList.size(); i++) { 194771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy try { 195771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy directoryContactsCursor = doQuery(unresolvedAddress, 1, 196771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy paramsList.get(i).directoryId, account, 197771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy context.getContentResolver(), query); 198771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy } finally { 199771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy if (directoryContactsCursor != null 200771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy && directoryContactsCursor.getCount() == 0) { 201771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy directoryContactsCursor.close(); 202771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy directoryContactsCursor = null; 203771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy } else { 2047a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy directoryId = paramsList.get(i).directoryId; 205771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy break; 206771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy } 20718987c44006700a2bfe614ec1e39a29ed5b23d78Mindy Pereira } 20816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 209771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy if (directoryContactsCursor != null) { 210771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy try { 211771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy final Map<String, RecipientEntry> entries = 2127a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy processContactEntries(directoryContactsCursor, directoryId); 21394fa301de71cc110671802eba8376c275b4055a4Scott Kennedy 214771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy for (final String address : entries.keySet()) { 215771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy matchesNotFound.remove(address); 216771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy } 21794fa301de71cc110671802eba8376c275b4055a4Scott Kennedy 218771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy callback.matchesFound(entries); 219771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy } finally { 220771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy directoryContactsCursor.close(); 221771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy } 22216923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 2231852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira } 2241852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira } 2251852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira } 2268af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein } 22794fa301de71cc110671802eba8376c275b4055a4Scott Kennedy 2288af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein public static void getMatchingRecipientsFromExtensionMatcher(BaseRecipientAdapter adapter, 2298af0d3b6f34e03c08c8e67be2190da01c59889daAndrew Sapperstein Set<String> matchesNotFound, RecipientMatchCallback callback) { 23076f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert // If no matches found in contact provider or the directories, try the extension 23176f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert // matcher. 23276f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert // todo (aalbert): This whole method needs to be in the adapter? 23376f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert if (adapter != null) { 23476f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert final Map<String, RecipientEntry> entries = 23576f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert adapter.getMatchingRecipients(matchesNotFound); 23676f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert if (entries != null && entries.size() > 0) { 23776f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert callback.matchesFound(entries); 23876f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert for (final String address : entries.keySet()) { 23976f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert matchesNotFound.remove(address); 24076f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert } 24176f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert } 24276f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert } 24394fa301de71cc110671802eba8376c275b4055a4Scott Kennedy callback.matchesNotFound(matchesNotFound); 24416923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 24516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp 2467a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy private static HashMap<String, RecipientEntry> processContactEntries(Cursor c, 2477a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy Long directoryId) { 24816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp HashMap<String, RecipientEntry> recipientEntries = new HashMap<String, RecipientEntry>(); 24916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp if (c != null && c.moveToFirst()) { 25016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp do { 25116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp String address = c.getString(Queries.Query.DESTINATION); 252ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy 253ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy final RecipientEntry newRecipientEntry = RecipientEntry.constructTopLevelEntry( 25416923ee63a79fce4be3f62b08bcd1f80617c1205mindyp c.getString(Queries.Query.NAME), 25516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp c.getInt(Queries.Query.DISPLAY_NAME_SOURCE), 25616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp c.getString(Queries.Query.DESTINATION), 25716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp c.getInt(Queries.Query.DESTINATION_TYPE), 25816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp c.getString(Queries.Query.DESTINATION_LABEL), 25916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp c.getLong(Queries.Query.CONTACT_ID), 2607a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy directoryId, 26116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp c.getLong(Queries.Query.DATA_ID), 26216923ee63a79fce4be3f62b08bcd1f80617c1205mindyp c.getString(Queries.Query.PHOTO_THUMBNAIL_URI), 263514f8a75f72fa2e735418ffb5d6e30aa914fbe7bScott Kennedy true, 2647a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy c.getString(Queries.Query.LOOKUP_KEY)); 265ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy 266ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy /* 267ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy * In certain situations, we may have two results for one address, where one of the 268ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy * results is just the email address, and the other has a name and photo, so we want 269ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy * to use the better one. 270ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy */ 271ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy final RecipientEntry recipientEntry = 272ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy getBetterRecipient(recipientEntries.get(address), newRecipientEntry); 273ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy 274ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy recipientEntries.put(address, recipientEntry); 27516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp if (Log.isLoggable(TAG, Log.DEBUG)) { 27616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp Log.d(TAG, "Received reverse look up information for " + address 27716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp + " RESULTS: " 27816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp + " NAME : " + c.getString(Queries.Query.NAME) 27916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp + " CONTACT ID : " + c.getLong(Queries.Query.CONTACT_ID) 28016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp + " ADDRESS :" + c.getString(Queries.Query.DESTINATION)); 28116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 28216923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } while (c.moveToNext()); 28316923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 2841852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira return recipientEntries; 2851852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira } 2861852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira 287ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy /** 288ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy * Given two {@link RecipientEntry}s for the same email address, this will return the one that 289ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy * contains more complete information for display purposes. Defaults to <code>entry2</code> if 290ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy * no significant differences are found. 291ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy */ 29278f38a09c9753c0ac1838ce0bfd3a6bc1a307ff7Scott Kennedy static RecipientEntry getBetterRecipient(final RecipientEntry entry1, 293ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy final RecipientEntry entry2) { 294ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy // If only one has passed in, use it 295ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy if (entry2 == null) { 296ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy return entry1; 297ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy } 298ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy 299ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy if (entry1 == null) { 300ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy return entry2; 301ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy } 302ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy 303ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy // If only one has a display name, use it 304ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy if (!TextUtils.isEmpty(entry1.getDisplayName()) 305ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy && TextUtils.isEmpty(entry2.getDisplayName())) { 306ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy return entry1; 307ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy } 308ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy 309ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy if (!TextUtils.isEmpty(entry2.getDisplayName()) 310ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy && TextUtils.isEmpty(entry1.getDisplayName())) { 311ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy return entry2; 312ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy } 313ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy 314ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy // If only one has a display name that is not the same as the destination, use it 315ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy if (!TextUtils.equals(entry1.getDisplayName(), entry1.getDestination()) 316ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy && TextUtils.equals(entry2.getDisplayName(), entry2.getDestination())) { 317ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy return entry1; 318ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy } 319ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy 320ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy if (!TextUtils.equals(entry2.getDisplayName(), entry2.getDestination()) 321ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy && TextUtils.equals(entry1.getDisplayName(), entry1.getDestination())) { 322ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy return entry2; 323ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy } 324ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy 325ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy // If only one has a photo, use it 326ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy if ((entry1.getPhotoThumbnailUri() != null || entry1.getPhotoBytes() != null) 327ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy && (entry2.getPhotoThumbnailUri() == null && entry2.getPhotoBytes() == null)) { 328ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy return entry1; 329ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy } 330ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy 331ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy if ((entry2.getPhotoThumbnailUri() != null || entry2.getPhotoBytes() != null) 332ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy && (entry1.getPhotoThumbnailUri() == null && entry1.getPhotoBytes() == null)) { 333ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy return entry2; 334ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy } 335ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy 336ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy // Go with the second option as a default 337ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy return entry2; 338ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy } 339ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy 34016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp private static Cursor doQuery(CharSequence constraint, int limit, Long directoryId, 34116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp Account account, ContentResolver resolver, Query query) { 34216923ee63a79fce4be3f62b08bcd1f80617c1205mindyp final Uri.Builder builder = query 34316923ee63a79fce4be3f62b08bcd1f80617c1205mindyp .getContentFilterUri() 34416923ee63a79fce4be3f62b08bcd1f80617c1205mindyp .buildUpon() 34516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp .appendPath(constraint.toString()) 34616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp .appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY, 34716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp String.valueOf(limit + BaseRecipientAdapter.ALLOWANCE_FOR_DUPLICATES)); 34816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp if (directoryId != null) { 34916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, 35016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp String.valueOf(directoryId)); 35116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 35216923ee63a79fce4be3f62b08bcd1f80617c1205mindyp if (account != null) { 35316923ee63a79fce4be3f62b08bcd1f80617c1205mindyp builder.appendQueryParameter(BaseRecipientAdapter.PRIMARY_ACCOUNT_NAME, account.name); 35416923ee63a79fce4be3f62b08bcd1f80617c1205mindyp builder.appendQueryParameter(BaseRecipientAdapter.PRIMARY_ACCOUNT_TYPE, account.type); 35516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 35616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp final Cursor cursor = resolver.query(builder.build(), query.getProjection(), null, null, 35716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp null); 35816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp return cursor; 35916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp } 36016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp 3617a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy public RecipientAlternatesAdapter(Context context, long contactId, Long directoryId, 3627a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy String lookupKey, long currentId, int queryMode, OnCheckedItemChangedListener listener, 3637a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy DropdownChipLayouter dropdownChipLayouter) { 3644db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao this(context, contactId, directoryId, lookupKey, currentId, queryMode, listener, 3654db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao dropdownChipLayouter, null); 3664db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao } 3674db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao 3684db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao public RecipientAlternatesAdapter(Context context, long contactId, Long directoryId, 3694db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao String lookupKey, long currentId, int queryMode, OnCheckedItemChangedListener listener, 3704db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao DropdownChipLayouter dropdownChipLayouter, StateListDrawable deleteDrawable) { 3717a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy super(context, 3727a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy getCursorForConstruction(context, contactId, directoryId, lookupKey, queryMode), 0); 37397d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira mCurrentId = currentId; 3747a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy mDirectoryId = directoryId; 3755086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira mCheckedItemChangedListener = listener; 37680f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor 377b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin mDropdownChipLayouter = dropdownChipLayouter; 3784db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao mDeleteDrawable = deleteDrawable; 37980f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } 38080f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor 3817a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy private static Cursor getCursorForConstruction(Context context, long contactId, 3827a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy Long directoryId, String lookupKey, int queryType) { 383a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki final Cursor cursor; 3847a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy final String desiredMimeType; 38580f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor if (queryType == QUERY_TYPE_EMAIL) { 3867a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy final Uri uri; 3877a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy final StringBuilder selection = new StringBuilder(); 3887a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy selection.append(Queries.EMAIL.getProjection()[Queries.Query.CONTACT_ID]); 3897a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy selection.append(" = ?"); 3907a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy 3917a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy if (directoryId == null || lookupKey == null) { 3927a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy uri = Queries.EMAIL.getContentUri(); 3937a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy desiredMimeType = null; 3947a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } else { 3957a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy final Uri.Builder builder = Contacts.getLookupUri(contactId, lookupKey).buildUpon(); 3967a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy builder.appendPath(Contacts.Entity.CONTENT_DIRECTORY) 3977a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, 3987a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy String.valueOf(directoryId)); 3997a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy uri = builder.build(); 4007a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy desiredMimeType = ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE; 4017a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } 402a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki cursor = context.getContentResolver().query( 4037a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy uri, 40480f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor Queries.EMAIL.getProjection(), 4057a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy selection.toString(), new String[] { 40680f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor String.valueOf(contactId) 40780f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor }, null); 40880f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } else { 4097a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy final Uri uri; 4107a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy final StringBuilder selection = new StringBuilder(); 4117a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy selection.append(Queries.PHONE.getProjection()[Queries.Query.CONTACT_ID]); 4127a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy selection.append(" = ?"); 4137a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy 4147a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy if (lookupKey == null) { 4157a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy uri = Queries.PHONE.getContentUri(); 4167a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy desiredMimeType = null; 4177a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } else { 4187a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy final Uri.Builder builder = Contacts.getLookupUri(contactId, lookupKey).buildUpon(); 4197a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy builder.appendPath(Contacts.Entity.CONTENT_DIRECTORY) 4207a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, 4217a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy String.valueOf(directoryId)); 4227a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy uri = builder.build(); 4237a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy desiredMimeType = ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE; 4247a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } 425a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki cursor = context.getContentResolver().query( 4267a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy uri, 42780f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor Queries.PHONE.getProjection(), 4287a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy selection.toString(), new String[] { 42980f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor String.valueOf(contactId) 43080f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor }, null); 43180f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor } 4327a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy 4337a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy final Cursor resultCursor = removeUndesiredDestinations(cursor, desiredMimeType, lookupKey); 4347a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy cursor.close(); 4357a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy 4367a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy return resultCursor; 437a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki } 438a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki 439a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki /** 440a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki * @return a new cursor based on the given cursor with all duplicate destinations removed. 441a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki * 442a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki * It's only intended to use for the alternate list, so... 443a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki * - This method ignores all other fields and dedupe solely on the destination. Normally, 444a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki * if a cursor contains multiple contacts and they have the same destination, we'd still want 445a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki * to show both. 446a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki * - This method creates a MatrixCursor, so all data will be kept in memory. We wouldn't want 447a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki * to do this if the original cursor is large, but it's okay here because the alternate list 448a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki * won't be that big. 4497a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy * 4507a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy * @param desiredMimeType If this is non-<code>null</code>, only entries with this mime type 4517a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy * will be added to the cursor 4527a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy * @param lookupKey The lookup key used for this contact if there isn't one in the cursor. This 4537a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy * should be the same one used in the query that returned the cursor 454a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki */ 455a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki // Visible for testing 4567a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy static Cursor removeUndesiredDestinations(final Cursor original, final String desiredMimeType, 4577a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy final String lookupKey) { 458a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki final MatrixCursor result = new MatrixCursor( 459a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki original.getColumnNames(), original.getCount()); 460a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki final HashSet<String> destinationsSeen = new HashSet<String>(); 461a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki 4627a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy String defaultDisplayName = null; 4637a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy String defaultPhotoThumbnailUri = null; 4647a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy int defaultDisplayNameSource = 0; 4657a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy 4667a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy // Find some nice defaults in case we need them 4677a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy original.moveToPosition(-1); 4687a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy while (original.moveToNext()) { 4697a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy final String mimeType = original.getString(Query.MIME_TYPE); 4707a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy 4717a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy if (ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE.equals( 4727a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy mimeType)) { 4737a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy // Store this data 4747a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy defaultDisplayName = original.getString(Query.NAME); 4757a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy defaultPhotoThumbnailUri = original.getString(Query.PHOTO_THUMBNAIL_URI); 4767a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy defaultDisplayNameSource = original.getInt(Query.DISPLAY_NAME_SOURCE); 4777a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy break; 4787a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } 4797a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } 4807a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy 481a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki original.moveToPosition(-1); 482a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki while (original.moveToNext()) { 4837a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy if (desiredMimeType != null) { 4847a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy final String mimeType = original.getString(Query.MIME_TYPE); 4857a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy if (!desiredMimeType.equals(mimeType)) { 4867a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy continue; 4877a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } 4887a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } 489a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki final String destination = original.getString(Query.DESTINATION); 490a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki if (destinationsSeen.contains(destination)) { 491a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki continue; 492a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki } 493a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki destinationsSeen.add(destination); 494a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki 4957a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy final Object[] row = new Object[] { 496a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki original.getString(Query.NAME), 497a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki original.getString(Query.DESTINATION), 498a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki original.getInt(Query.DESTINATION_TYPE), 499a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki original.getString(Query.DESTINATION_LABEL), 500a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki original.getLong(Query.CONTACT_ID), 501a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki original.getLong(Query.DATA_ID), 502a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki original.getString(Query.PHOTO_THUMBNAIL_URI), 5037a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy original.getInt(Query.DISPLAY_NAME_SOURCE), 5047a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy original.getString(Query.LOOKUP_KEY), 5057a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy original.getString(Query.MIME_TYPE) 5067a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy }; 5077a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy 5087a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy if (row[Query.NAME] == null) { 5097a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy row[Query.NAME] = defaultDisplayName; 5107a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } 5117a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy if (row[Query.PHOTO_THUMBNAIL_URI] == null) { 5127a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy row[Query.PHOTO_THUMBNAIL_URI] = defaultPhotoThumbnailUri; 5137a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } 5147a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy if ((Integer) row[Query.DISPLAY_NAME_SOURCE] == 0) { 5157a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy row[Query.DISPLAY_NAME_SOURCE] = defaultDisplayNameSource; 5167a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } 5177a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy if (row[Query.LOOKUP_KEY] == null) { 5187a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy row[Query.LOOKUP_KEY] = lookupKey; 5197a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } 5207a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy 5217a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy // Ensure we don't have two '?' like content://.../...?account_name=...?sz=... 5227a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy final String photoThumbnailUri = (String) row[Query.PHOTO_THUMBNAIL_URI]; 5237a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy if (photoThumbnailUri != null) { 5247a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy if (sCorrectedPhotoUris.containsKey(photoThumbnailUri)) { 5257a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy row[Query.PHOTO_THUMBNAIL_URI] = sCorrectedPhotoUris.get(photoThumbnailUri); 5267a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } else if (photoThumbnailUri.indexOf('?') != photoThumbnailUri.lastIndexOf('?')) { 5277a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy final String[] parts = photoThumbnailUri.split("\\?"); 5287a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy final StringBuilder correctedUriBuilder = new StringBuilder(); 5297a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy for (int i = 0; i < parts.length; i++) { 5307a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy if (i == 1) { 5317a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy correctedUriBuilder.append("?"); // We only want one of these 5327a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } else if (i > 1) { 5337a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy correctedUriBuilder.append("&"); // And we want these elsewhere 5347a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } 5357a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy correctedUriBuilder.append(parts[i]); 5367a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } 5377a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy 5387a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy final String correctedUri = correctedUriBuilder.toString(); 5397a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy sCorrectedPhotoUris.put(photoThumbnailUri, correctedUri); 5407a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy row[Query.PHOTO_THUMBNAIL_URI] = correctedUri; 5417a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } 5427a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy } 5437a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy 5447a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy result.addRow(row); 545a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki } 546a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki 547a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki return result; 54897d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira } 54997d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira 55097d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira @Override 55197d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira public long getItemId(int position) { 55297d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira Cursor c = getCursor(); 5533bb52162b7e842243d4a14e73c15b20dbd1804d7Mindy Pereira if (c.moveToPosition(position)) { 55480f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor c.getLong(Queries.Query.DATA_ID); 5553bb52162b7e842243d4a14e73c15b20dbd1804d7Mindy Pereira } 5563bb52162b7e842243d4a14e73c15b20dbd1804d7Mindy Pereira return -1; 55797d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira } 55897d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira 55997d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira public RecipientEntry getRecipientEntry(int position) { 56097d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira Cursor c = getCursor(); 56197d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira c.moveToPosition(position); 56280f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor return RecipientEntry.constructTopLevelEntry( 56380f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor c.getString(Queries.Query.NAME), 56400adb32f3cea49ec82467c0e1a9e42659b556836Makoto Onuki c.getInt(Queries.Query.DISPLAY_NAME_SOURCE), 56580f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor c.getString(Queries.Query.DESTINATION), 56680f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor c.getInt(Queries.Query.DESTINATION_TYPE), 56780f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor c.getString(Queries.Query.DESTINATION_LABEL), 56880f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor c.getLong(Queries.Query.CONTACT_ID), 5697a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy mDirectoryId, 57080f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor c.getLong(Queries.Query.DATA_ID), 571ccb8e237ec80934d1c983bb61f66b75541786ddcmindyp c.getString(Queries.Query.PHOTO_THUMBNAIL_URI), 572514f8a75f72fa2e735418ffb5d6e30aa914fbe7bScott Kennedy true, 5737a4e67708498ec46c2e9b3bad69d3807d88c064eScott Kennedy c.getString(Queries.Query.LOOKUP_KEY)); 57497d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira } 57597d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira 57697d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira @Override 57797d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira public View getView(int position, View convertView, ViewGroup parent) { 57867ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira Cursor cursor = getCursor(); 57967ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira cursor.moveToPosition(position); 58097d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira if (convertView == null) { 5814ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao convertView = mDropdownChipLayouter.newView(AdapterType.RECIPIENT_ALTERNATES); 582007a76baab414c9d432d31c661668b1bd07e3f80Mindy Pereira } 58380f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor if (cursor.getLong(Queries.Query.DATA_ID) == mCurrentId) { 584007a76baab414c9d432d31c661668b1bd07e3f80Mindy Pereira mCheckedItemPosition = position; 5855086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira if (mCheckedItemChangedListener != null) { 5865086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira mCheckedItemChangedListener.onCheckedItemChanged(mCheckedItemPosition); 5875086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira } 58897d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira } 58967ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira bindView(convertView, convertView.getContext(), cursor); 59097d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira return convertView; 59197d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira } 59297d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira 59397d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira @Override 59497d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira public void bindView(View view, Context context, Cursor cursor) { 59567ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira int position = cursor.getPosition(); 59667ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira RecipientEntry entry = getRecipientEntry(position); 597b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin 598b10d1c652d0416c284d9792fc9a0a92b3acd51caKevin Lin mDropdownChipLayouter.bindView(view, null, entry, position, 5994db8cccf3332ad7c6fb1915f9f0f169953c3953aJin Cao AdapterType.RECIPIENT_ALTERNATES, null, mDeleteDrawable); 60097d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira } 60197d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira 60297d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira @Override 60397d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira public View newView(Context context, Cursor cursor, ViewGroup parent) { 6044ddcdaed9ef5ea83910a0513e87538130270e2e4Jin Cao return mDropdownChipLayouter.newView(AdapterType.RECIPIENT_ALTERNATES); 60597d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira } 60697d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira 6075086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira /*package*/ static interface OnCheckedItemChangedListener { 6085086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira public void onCheckedItemChanged(int position); 60997d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira } 61097d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira} 611