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