RecipientAlternatesAdapter.java revision 76f1f2d4eb66956814254b0e4f86da7aa8261bcb
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;
26ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedyimport android.text.TextUtils;
271852931de1e24e77cb708f4ba010eaa269426657Mindy Pereiraimport android.text.util.Rfc822Token;
281852931de1e24e77cb708f4ba010eaa269426657Mindy Pereiraimport android.text.util.Rfc822Tokenizer;
2918987c44006700a2bfe614ec1e39a29ed5b23d78Mindy Pereiraimport android.util.Log;
3097d7768576ff27d779d68f77e23925b69f3290bcMindy Pereiraimport android.view.LayoutInflater;
3197d7768576ff27d779d68f77e23925b69f3290bcMindy Pereiraimport android.view.View;
3297d7768576ff27d779d68f77e23925b69f3290bcMindy Pereiraimport android.view.ViewGroup;
3397d7768576ff27d779d68f77e23925b69f3290bcMindy Pereiraimport android.widget.CursorAdapter;
3467ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereiraimport android.widget.ImageView;
3597d7768576ff27d779d68f77e23925b69f3290bcMindy Pereiraimport android.widget.TextView;
3697d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira
3716923ee63a79fce4be3f62b08bcd1f80617c1205mindypimport com.android.ex.chips.BaseRecipientAdapter.DirectoryListQuery;
3816923ee63a79fce4be3f62b08bcd1f80617c1205mindypimport com.android.ex.chips.BaseRecipientAdapter.DirectorySearchParams;
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 {
531852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira    static final int MAX_LOOKUPS = 50;
5497d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira    private final LayoutInflater mLayoutInflater;
5597d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira
5697d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira    private final long mCurrentId;
5797d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira
58007a76baab414c9d432d31c661668b1bd07e3f80Mindy Pereira    private int mCheckedItemPosition = -1;
59007a76baab414c9d432d31c661668b1bd07e3f80Mindy Pereira
605086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira    private OnCheckedItemChangedListener mCheckedItemChangedListener;
615086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira
6218987c44006700a2bfe614ec1e39a29ed5b23d78Mindy Pereira    private static final String TAG = "RecipAlternates";
6318987c44006700a2bfe614ec1e39a29ed5b23d78Mindy Pereira
6480f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor    public static final int QUERY_TYPE_EMAIL = 0;
6580f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor    public static final int QUERY_TYPE_PHONE = 1;
6680f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor    private Query mQuery;
6780f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor
6816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp    public interface RecipientMatchCallback {
6994fa301de71cc110671802eba8376c275b4055a4Scott Kennedy        public void matchesFound(Map<String, RecipientEntry> results);
7094fa301de71cc110671802eba8376c275b4055a4Scott Kennedy        /**
7194fa301de71cc110671802eba8376c275b4055a4Scott Kennedy         * Called with all addresses that could not be resolved to valid recipients.
7294fa301de71cc110671802eba8376c275b4055a4Scott Kennedy         */
73f7e202d8b83bfbd73ca47ba7843ebc4dd57c2fa4Scott Kennedy        public void matchesNotFound(Set<String> unfoundAddresses);
7416923ee63a79fce4be3f62b08bcd1f80617c1205mindyp    }
7516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp
7676f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert    public static void getMatchingRecipients(Context context, BaseRecipientAdapter adapter,
7776f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert            ArrayList<String> inAddresses, Account account, RecipientMatchCallback callback) {
7876f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert        getMatchingRecipients(context, adapter, inAddresses, QUERY_TYPE_EMAIL, account, callback);
7980f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor    }
8080f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor
811852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira    /**
821852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira     * Get a HashMap of address to RecipientEntry that contains all contact
831852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira     * information for a contact with the provided address, if one exists. This
841852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira     * may block the UI, so run it in an async task.
851852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira     *
861852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira     * @param context Context.
877211747e51623ae1305053f533c09dd335e013a2Daisuke Miyakawa     * @param inAddresses Array of addresses on which to perform the lookup.
8816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp     * @param callback RecipientMatchCallback called when a match or matches are found.
891852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira     * @return HashMap<String,RecipientEntry>
901852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira     */
9176f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert    public static void getMatchingRecipients(Context context, BaseRecipientAdapter adapter,
9276f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert            ArrayList<String> inAddresses, int addressType, Account account,
9376f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert            RecipientMatchCallback callback) {
9480f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor        Queries.Query query;
9580f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor        if (addressType == QUERY_TYPE_EMAIL) {
9680f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor            query = Queries.EMAIL;
9780f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor        } else {
9880f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor            query = Queries.PHONE;
9980f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor        }
10003cfe3eee5635e419ab1d70d463b2b8beac72f00Mindy Pereira        int addressesSize = Math.min(MAX_LOOKUPS, inAddresses.size());
10116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp        HashSet<String> addresses = new HashSet<String>();
1021852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira        StringBuilder bindString = new StringBuilder();
1031852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira        // Create the "?" string and set up arguments.
1041852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira        for (int i = 0; i < addressesSize; i++) {
10503cfe3eee5635e419ab1d70d463b2b8beac72f00Mindy Pereira            Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(inAddresses.get(i).toLowerCase());
10616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp            addresses.add(tokens.length > 0 ? tokens[0].getAddress() : inAddresses.get(i));
1071852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira            bindString.append("?");
1081852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira            if (i < addressesSize - 1) {
1091852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira                bindString.append(",");
1101852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira            }
1111852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira        }
1121852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira
11318987c44006700a2bfe614ec1e39a29ed5b23d78Mindy Pereira        if (Log.isLoggable(TAG, Log.DEBUG)) {
11418987c44006700a2bfe614ec1e39a29ed5b23d78Mindy Pereira            Log.d(TAG, "Doing reverse lookup for " + addresses.toString());
11518987c44006700a2bfe614ec1e39a29ed5b23d78Mindy Pereira        }
11618987c44006700a2bfe614ec1e39a29ed5b23d78Mindy Pereira
11716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp        String[] addressArray = new String[addresses.size()];
11816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp        addresses.toArray(addressArray);
11916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp        HashMap<String, RecipientEntry> recipientEntries = null;
12016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp        Cursor c = null;
12116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp
12216923ee63a79fce4be3f62b08bcd1f80617c1205mindyp        try {
12316923ee63a79fce4be3f62b08bcd1f80617c1205mindyp            c = context.getContentResolver().query(
12416923ee63a79fce4be3f62b08bcd1f80617c1205mindyp                    query.getContentUri(),
12516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp                    query.getProjection(),
12616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp                    query.getProjection()[Queries.Query.DESTINATION] + " IN ("
12716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp                            + bindString.toString() + ")", addressArray, null);
12816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp            recipientEntries = processContactEntries(c);
12916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp            callback.matchesFound(recipientEntries);
13016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp        } finally {
13116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp            if (c != null) {
13216923ee63a79fce4be3f62b08bcd1f80617c1205mindyp                c.close();
13316923ee63a79fce4be3f62b08bcd1f80617c1205mindyp            }
13416923ee63a79fce4be3f62b08bcd1f80617c1205mindyp        }
13516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp        // See if any entries did not resolve; if so, we need to check other
13616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp        // directories
13794fa301de71cc110671802eba8376c275b4055a4Scott Kennedy        final Set<String> matchesNotFound = new HashSet<String>();
13816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp        if (recipientEntries.size() < addresses.size()) {
13916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp            final List<DirectorySearchParams> paramsList;
140539c2b12cca5e9bccd9acabc4721c876058a68d4Scott Kennedy            Cursor directoryCursor = null;
141539c2b12cca5e9bccd9acabc4721c876058a68d4Scott Kennedy            try {
142539c2b12cca5e9bccd9acabc4721c876058a68d4Scott Kennedy                directoryCursor = context.getContentResolver().query(DirectoryListQuery.URI,
143539c2b12cca5e9bccd9acabc4721c876058a68d4Scott Kennedy                        DirectoryListQuery.PROJECTION, null, null, null);
144771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy                if (directoryCursor == null) {
145771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy                    paramsList = null;
146771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy                } else {
147771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy                    paramsList = BaseRecipientAdapter.setupOtherDirectories(context,
148771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy                            directoryCursor, account);
149771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy                }
150539c2b12cca5e9bccd9acabc4721c876058a68d4Scott Kennedy            } finally {
151539c2b12cca5e9bccd9acabc4721c876058a68d4Scott Kennedy                if (directoryCursor != null) {
152539c2b12cca5e9bccd9acabc4721c876058a68d4Scott Kennedy                    directoryCursor.close();
153539c2b12cca5e9bccd9acabc4721c876058a68d4Scott Kennedy                }
154539c2b12cca5e9bccd9acabc4721c876058a68d4Scott Kennedy            }
15516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp            // Run a directory query for each unmatched recipient.
15616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp            HashSet<String> unresolvedAddresses = new HashSet<String>();
15716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp            for (String address : addresses) {
15816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp                if (!recipientEntries.containsKey(address)) {
15916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp                    unresolvedAddresses.add(address);
16016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp                }
16116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp            }
16294fa301de71cc110671802eba8376c275b4055a4Scott Kennedy
16394fa301de71cc110671802eba8376c275b4055a4Scott Kennedy            matchesNotFound.addAll(unresolvedAddresses);
16494fa301de71cc110671802eba8376c275b4055a4Scott Kennedy
165771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy            if (paramsList != null) {
166771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy                Cursor directoryContactsCursor = null;
167771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy                for (String unresolvedAddress : unresolvedAddresses) {
168771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy                    for (int i = 0; i < paramsList.size(); i++) {
169771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy                        try {
170771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy                            directoryContactsCursor = doQuery(unresolvedAddress, 1,
171771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy                                    paramsList.get(i).directoryId, account,
172771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy                                    context.getContentResolver(), query);
173771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy                        } finally {
174771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy                            if (directoryContactsCursor != null
175771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy                                    && directoryContactsCursor.getCount() == 0) {
176771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy                                directoryContactsCursor.close();
177771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy                                directoryContactsCursor = null;
178771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy                            } else {
179771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy                                break;
180771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy                            }
18118987c44006700a2bfe614ec1e39a29ed5b23d78Mindy Pereira                        }
18216923ee63a79fce4be3f62b08bcd1f80617c1205mindyp                    }
183771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy                    if (directoryContactsCursor != null) {
184771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy                        try {
185771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy                            final Map<String, RecipientEntry> entries =
186771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy                                    processContactEntries(directoryContactsCursor);
18794fa301de71cc110671802eba8376c275b4055a4Scott Kennedy
188771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy                            for (final String address : entries.keySet()) {
189771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy                                matchesNotFound.remove(address);
190771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy                            }
19194fa301de71cc110671802eba8376c275b4055a4Scott Kennedy
192771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy                            callback.matchesFound(entries);
193771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy                        } finally {
194771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy                            directoryContactsCursor.close();
195771e417fe305e0aa65f0a864f2b4f4da7606b6b1Scott Kennedy                        }
19616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp                    }
1971852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira                }
1981852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira            }
1991852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira        }
20094fa301de71cc110671802eba8376c275b4055a4Scott Kennedy
20176f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert        // If no matches found in contact provider or the directories, try the extension
20276f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert        // matcher.
20376f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert        // todo (aalbert): This whole method needs to be in the adapter?
20476f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert        if (adapter != null) {
20576f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert            final Map<String, RecipientEntry> entries =
20676f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert                    adapter.getMatchingRecipients(matchesNotFound);
20776f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert            if (entries != null && entries.size() > 0) {
20876f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert                callback.matchesFound(entries);
20976f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert                for (final String address : entries.keySet()) {
21076f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert                    matchesNotFound.remove(address);
21176f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert                }
21276f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert            }
21376f1f2d4eb66956814254b0e4f86da7aa8261bcbAlon Albert        }
21494fa301de71cc110671802eba8376c275b4055a4Scott Kennedy        callback.matchesNotFound(matchesNotFound);
21516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp    }
21616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp
21716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp    private static HashMap<String, RecipientEntry> processContactEntries(Cursor c) {
21816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp        HashMap<String, RecipientEntry> recipientEntries = new HashMap<String, RecipientEntry>();
21916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp        if (c != null && c.moveToFirst()) {
22016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp            do {
22116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp                String address = c.getString(Queries.Query.DESTINATION);
222ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy
223ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy                final RecipientEntry newRecipientEntry = RecipientEntry.constructTopLevelEntry(
22416923ee63a79fce4be3f62b08bcd1f80617c1205mindyp                        c.getString(Queries.Query.NAME),
22516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp                        c.getInt(Queries.Query.DISPLAY_NAME_SOURCE),
22616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp                        c.getString(Queries.Query.DESTINATION),
22716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp                        c.getInt(Queries.Query.DESTINATION_TYPE),
22816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp                        c.getString(Queries.Query.DESTINATION_LABEL),
22916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp                        c.getLong(Queries.Query.CONTACT_ID),
23016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp                        c.getLong(Queries.Query.DATA_ID),
23116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp                        c.getString(Queries.Query.PHOTO_THUMBNAIL_URI),
232ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy                        true);
233ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy
234ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy                /*
235ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy                 * In certain situations, we may have two results for one address, where one of the
236ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy                 * results is just the email address, and the other has a name and photo, so we want
237ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy                 * to use the better one.
238ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy                 */
239ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy                final RecipientEntry recipientEntry =
240ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy                        getBetterRecipient(recipientEntries.get(address), newRecipientEntry);
241ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy
242ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy                recipientEntries.put(address, recipientEntry);
24316923ee63a79fce4be3f62b08bcd1f80617c1205mindyp                if (Log.isLoggable(TAG, Log.DEBUG)) {
24416923ee63a79fce4be3f62b08bcd1f80617c1205mindyp                    Log.d(TAG, "Received reverse look up information for " + address
24516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp                            + " RESULTS: "
24616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp                            + " NAME : " + c.getString(Queries.Query.NAME)
24716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp                            + " CONTACT ID : " + c.getLong(Queries.Query.CONTACT_ID)
24816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp                            + " ADDRESS :" + c.getString(Queries.Query.DESTINATION));
24916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp                }
25016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp            } while (c.moveToNext());
25116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp        }
2521852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira        return recipientEntries;
2531852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira    }
2541852931de1e24e77cb708f4ba010eaa269426657Mindy Pereira
255ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy    /**
256ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy     * Given two {@link RecipientEntry}s for the same email address, this will return the one that
257ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy     * contains more complete information for display purposes. Defaults to <code>entry2</code> if
258ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy     * no significant differences are found.
259ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy     */
26078f38a09c9753c0ac1838ce0bfd3a6bc1a307ff7Scott Kennedy    static RecipientEntry getBetterRecipient(final RecipientEntry entry1,
261ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy            final RecipientEntry entry2) {
262ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy        // If only one has passed in, use it
263ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy        if (entry2 == null) {
264ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy            return entry1;
265ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy        }
266ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy
267ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy        if (entry1 == null) {
268ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy            return entry2;
269ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy        }
270ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy
271ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy        // If only one has a display name, use it
272ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy        if (!TextUtils.isEmpty(entry1.getDisplayName())
273ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy                && TextUtils.isEmpty(entry2.getDisplayName())) {
274ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy            return entry1;
275ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy        }
276ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy
277ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy        if (!TextUtils.isEmpty(entry2.getDisplayName())
278ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy                && TextUtils.isEmpty(entry1.getDisplayName())) {
279ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy            return entry2;
280ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy        }
281ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy
282ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy        // If only one has a display name that is not the same as the destination, use it
283ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy        if (!TextUtils.equals(entry1.getDisplayName(), entry1.getDestination())
284ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy                && TextUtils.equals(entry2.getDisplayName(), entry2.getDestination())) {
285ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy            return entry1;
286ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy        }
287ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy
288ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy        if (!TextUtils.equals(entry2.getDisplayName(), entry2.getDestination())
289ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy                && TextUtils.equals(entry1.getDisplayName(), entry1.getDestination())) {
290ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy            return entry2;
291ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy        }
292ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy
293ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy        // If only one has a photo, use it
294ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy        if ((entry1.getPhotoThumbnailUri() != null || entry1.getPhotoBytes() != null)
295ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy                && (entry2.getPhotoThumbnailUri() == null && entry2.getPhotoBytes() == null)) {
296ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy            return entry1;
297ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy        }
298ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy
299ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy        if ((entry2.getPhotoThumbnailUri() != null || entry2.getPhotoBytes() != null)
300ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy                && (entry1.getPhotoThumbnailUri() == null && entry1.getPhotoBytes() == null)) {
301ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy            return entry2;
302ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy        }
303ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy
304ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy        // Go with the second option as a default
305ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy        return entry2;
306ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy    }
307ef3f76c8c0e4fc83a0ab7fbe8db9a98cc1e2a357Scott Kennedy
30816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp    private static Cursor doQuery(CharSequence constraint, int limit, Long directoryId,
30916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp            Account account, ContentResolver resolver, Query query) {
31016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp        final Uri.Builder builder = query
31116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp                .getContentFilterUri()
31216923ee63a79fce4be3f62b08bcd1f80617c1205mindyp                .buildUpon()
31316923ee63a79fce4be3f62b08bcd1f80617c1205mindyp                .appendPath(constraint.toString())
31416923ee63a79fce4be3f62b08bcd1f80617c1205mindyp                .appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY,
31516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp                        String.valueOf(limit + BaseRecipientAdapter.ALLOWANCE_FOR_DUPLICATES));
31616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp        if (directoryId != null) {
31716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp            builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
31816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp                    String.valueOf(directoryId));
31916923ee63a79fce4be3f62b08bcd1f80617c1205mindyp        }
32016923ee63a79fce4be3f62b08bcd1f80617c1205mindyp        if (account != null) {
32116923ee63a79fce4be3f62b08bcd1f80617c1205mindyp            builder.appendQueryParameter(BaseRecipientAdapter.PRIMARY_ACCOUNT_NAME, account.name);
32216923ee63a79fce4be3f62b08bcd1f80617c1205mindyp            builder.appendQueryParameter(BaseRecipientAdapter.PRIMARY_ACCOUNT_TYPE, account.type);
32316923ee63a79fce4be3f62b08bcd1f80617c1205mindyp        }
32416923ee63a79fce4be3f62b08bcd1f80617c1205mindyp        final Cursor cursor = resolver.query(builder.build(), query.getProjection(), null, null,
32516923ee63a79fce4be3f62b08bcd1f80617c1205mindyp                null);
32616923ee63a79fce4be3f62b08bcd1f80617c1205mindyp        return cursor;
32716923ee63a79fce4be3f62b08bcd1f80617c1205mindyp    }
32816923ee63a79fce4be3f62b08bcd1f80617c1205mindyp
329f7e202d8b83bfbd73ca47ba7843ebc4dd57c2fa4Scott Kennedy    public RecipientAlternatesAdapter(Context context, long contactId, long currentId,
3305086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira            OnCheckedItemChangedListener listener) {
331f7e202d8b83bfbd73ca47ba7843ebc4dd57c2fa4Scott Kennedy        this(context, contactId, currentId, QUERY_TYPE_EMAIL, listener);
33280f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor    }
33380f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor
334f7e202d8b83bfbd73ca47ba7843ebc4dd57c2fa4Scott Kennedy    public RecipientAlternatesAdapter(Context context, long contactId, long currentId,
33580f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor            int queryMode, OnCheckedItemChangedListener listener) {
33680f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor        super(context, getCursorForConstruction(context, contactId, queryMode), 0);
33797d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira        mLayoutInflater = LayoutInflater.from(context);
33897d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira        mCurrentId = currentId;
3395086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira        mCheckedItemChangedListener = listener;
34080f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor
34180f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor        if (queryMode == QUERY_TYPE_EMAIL) {
34280f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor            mQuery = Queries.EMAIL;
34380f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor        } else if (queryMode == QUERY_TYPE_PHONE) {
34480f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor            mQuery = Queries.PHONE;
34580f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor        } else {
34680f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor            mQuery = Queries.EMAIL;
34780f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor            Log.e(TAG, "Unsupported query type: " + queryMode);
34880f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor        }
34980f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor    }
35080f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor
35180f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor    private static Cursor getCursorForConstruction(Context context, long contactId, int queryType) {
352a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki        final Cursor cursor;
35380f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor        if (queryType == QUERY_TYPE_EMAIL) {
354a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki            cursor = context.getContentResolver().query(
35580f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor                    Queries.EMAIL.getContentUri(),
35680f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor                    Queries.EMAIL.getProjection(),
357a62ba492f901e024b249e0138e96374b09766a36Mindy Pereira                    Queries.EMAIL.getProjection()[Queries.Query.CONTACT_ID] + " =?", new String[] {
35880f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor                        String.valueOf(contactId)
35980f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor                    }, null);
36080f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor        } else {
361a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki            cursor = context.getContentResolver().query(
36280f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor                    Queries.PHONE.getContentUri(),
36380f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor                    Queries.PHONE.getProjection(),
3649c17ab5f3bf0f88e3641faf98931c4f9e7d65366Tom Taylor                    Queries.PHONE.getProjection()[Queries.Query.CONTACT_ID] + " =?", new String[] {
36580f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor                        String.valueOf(contactId)
36680f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor                    }, null);
36780f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor        }
368a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki        return removeDuplicateDestinations(cursor);
369a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki    }
370a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki
371a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki    /**
372a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki     * @return a new cursor based on the given cursor with all duplicate destinations removed.
373a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki     *
374a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki     * It's only intended to use for the alternate list, so...
375a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki     * - This method ignores all other fields and dedupe solely on the destination.  Normally,
376a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki     * if a cursor contains multiple contacts and they have the same destination, we'd still want
377a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki     * to show both.
378a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki     * - This method creates a MatrixCursor, so all data will be kept in memory.  We wouldn't want
379a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki     * to do this if the original cursor is large, but it's okay here because the alternate list
380a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki     * won't be that big.
381a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki     */
382a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki    // Visible for testing
383a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki    /* package */ static Cursor removeDuplicateDestinations(Cursor original) {
384a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki        final MatrixCursor result = new MatrixCursor(
385a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki                original.getColumnNames(), original.getCount());
386a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki        final HashSet<String> destinationsSeen = new HashSet<String>();
387a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki
388a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki        original.moveToPosition(-1);
389a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki        while (original.moveToNext()) {
390a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki            final String destination = original.getString(Query.DESTINATION);
391a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki            if (destinationsSeen.contains(destination)) {
392a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki                continue;
393a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki            }
394a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki            destinationsSeen.add(destination);
395a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki
396a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki            result.addRow(new Object[] {
397a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki                    original.getString(Query.NAME),
398a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki                    original.getString(Query.DESTINATION),
399a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki                    original.getInt(Query.DESTINATION_TYPE),
400a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki                    original.getString(Query.DESTINATION_LABEL),
401a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki                    original.getLong(Query.CONTACT_ID),
402a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki                    original.getLong(Query.DATA_ID),
403a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki                    original.getString(Query.PHOTO_THUMBNAIL_URI),
404a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki                    original.getInt(Query.DISPLAY_NAME_SOURCE)
405a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki                    });
406a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki        }
407a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki
408a5d37c8a968edf94755215617b593d3f61738a92Makoto Onuki        return result;
40997d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira    }
41097d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira
41197d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira    @Override
41297d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira    public long getItemId(int position) {
41397d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira        Cursor c = getCursor();
4143bb52162b7e842243d4a14e73c15b20dbd1804d7Mindy Pereira        if (c.moveToPosition(position)) {
41580f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor            c.getLong(Queries.Query.DATA_ID);
4163bb52162b7e842243d4a14e73c15b20dbd1804d7Mindy Pereira        }
4173bb52162b7e842243d4a14e73c15b20dbd1804d7Mindy Pereira        return -1;
41897d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira    }
41997d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira
42097d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira    public RecipientEntry getRecipientEntry(int position) {
42197d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira        Cursor c = getCursor();
42297d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira        c.moveToPosition(position);
42380f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor        return RecipientEntry.constructTopLevelEntry(
42480f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor                c.getString(Queries.Query.NAME),
42500adb32f3cea49ec82467c0e1a9e42659b556836Makoto Onuki                c.getInt(Queries.Query.DISPLAY_NAME_SOURCE),
42680f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor                c.getString(Queries.Query.DESTINATION),
42780f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor                c.getInt(Queries.Query.DESTINATION_TYPE),
42880f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor                c.getString(Queries.Query.DESTINATION_LABEL),
42980f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor                c.getLong(Queries.Query.CONTACT_ID),
43080f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor                c.getLong(Queries.Query.DATA_ID),
431ccb8e237ec80934d1c983bb61f66b75541786ddcmindyp                c.getString(Queries.Query.PHOTO_THUMBNAIL_URI),
432ccb8e237ec80934d1c983bb61f66b75541786ddcmindyp                true);
43397d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira    }
43497d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira
43597d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira    @Override
43697d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira    public View getView(int position, View convertView, ViewGroup parent) {
43767ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira        Cursor cursor = getCursor();
43867ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira        cursor.moveToPosition(position);
43997d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira        if (convertView == null) {
440007a76baab414c9d432d31c661668b1bd07e3f80Mindy Pereira            convertView = newView();
441007a76baab414c9d432d31c661668b1bd07e3f80Mindy Pereira        }
44280f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor        if (cursor.getLong(Queries.Query.DATA_ID) == mCurrentId) {
443007a76baab414c9d432d31c661668b1bd07e3f80Mindy Pereira            mCheckedItemPosition = position;
4445086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira            if (mCheckedItemChangedListener != null) {
4455086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira                mCheckedItemChangedListener.onCheckedItemChanged(mCheckedItemPosition);
4465086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira            }
44797d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira        }
44867ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira        bindView(convertView, convertView.getContext(), cursor);
44997d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira        return convertView;
45097d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira    }
45197d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira
45267ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira    // TODO: this is VERY similar to the BaseRecipientAdapter. Can we combine
45367ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira    // somehow?
45497d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira    @Override
45597d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira    public void bindView(View view, Context context, Cursor cursor) {
45667ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira        int position = cursor.getPosition();
45767ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira
458102cf10189b2c13045b885a5479333ae3b304491Daisuke Miyakawa        TextView display = (TextView) view.findViewById(android.R.id.title);
45967ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira        ImageView imageView = (ImageView) view.findViewById(android.R.id.icon);
46067ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira        RecipientEntry entry = getRecipientEntry(position);
46167ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira        if (position == 0) {
46280f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor            display.setText(cursor.getString(Queries.Query.NAME));
46367ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira            display.setVisibility(View.VISIBLE);
46467ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira            // TODO: see if this needs to be done outside the main thread
46567ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira            // as it may be too slow to get immediately.
46667ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira            imageView.setImageURI(entry.getPhotoThumbnailUri());
46767ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira            imageView.setVisibility(View.VISIBLE);
46867ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira        } else {
46967ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira            display.setVisibility(View.GONE);
47067ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira            imageView.setVisibility(View.GONE);
47167ad489cd290f7d2b468b4d69ce679edeac9bb7aMindy Pereira        }
472102cf10189b2c13045b885a5479333ae3b304491Daisuke Miyakawa        TextView destination = (TextView) view.findViewById(android.R.id.text1);
47380f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor        destination.setText(cursor.getString(Queries.Query.DESTINATION));
474102cf10189b2c13045b885a5479333ae3b304491Daisuke Miyakawa
475102cf10189b2c13045b885a5479333ae3b304491Daisuke Miyakawa        TextView destinationType = (TextView) view.findViewById(android.R.id.text2);
476f908b64e75e0bb38ff2806232ca57c93189156eaMindy Pereira        if (destinationType != null) {
47780f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor            destinationType.setText(mQuery.getTypeLabel(context.getResources(),
47880f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor                    cursor.getInt(Queries.Query.DESTINATION_TYPE),
47980f4abfb682426384e88fb1dddc682be1c8a6c7fTom Taylor                    cursor.getString(Queries.Query.DESTINATION_LABEL)).toString().toUpperCase());
480f908b64e75e0bb38ff2806232ca57c93189156eaMindy Pereira        }
48197d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira    }
48297d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira
48397d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira    @Override
48497d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira    public View newView(Context context, Cursor cursor, ViewGroup parent) {
485007a76baab414c9d432d31c661668b1bd07e3f80Mindy Pereira        return newView();
486007a76baab414c9d432d31c661668b1bd07e3f80Mindy Pereira    }
487007a76baab414c9d432d31c661668b1bd07e3f80Mindy Pereira
488007a76baab414c9d432d31c661668b1bd07e3f80Mindy Pereira    private View newView() {
48952c441e2c03e0f48572348953b985a4bf989c057Mindy Pereira        return mLayoutInflater.inflate(R.layout.chips_recipient_dropdown_item, null);
49097d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira    }
49197d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira
4925086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira    /*package*/ static interface OnCheckedItemChangedListener {
4935086391a478c3b1badbb86074c3cef72126c7d0fMindy Pereira        public void onCheckedItemChanged(int position);
49497d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira    }
49597d7768576ff27d779d68f77e23925b69f3290bcMindy Pereira}
496