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