15cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov/*
25cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * Copyright (C) 2010 The Android Open Source Project
35cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov *
45cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * Licensed under the Apache License, Version 2.0 (the "License");
55cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * you may not use this file except in compliance with the License.
65cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * You may obtain a copy of the License at
75cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov *
85cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov *      http://www.apache.org/licenses/LICENSE-2.0
95cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov *
105cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * Unless required by applicable law or agreed to in writing, software
115cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * distributed under the License is distributed on an "AS IS" BASIS,
125cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * See the License for the specific language governing permissions and
145cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * limitations under the License.
155cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov */
165cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
175cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovpackage com.android.common.contacts;
185cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
195cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovimport com.android.common.widget.CompositeCursorAdapter;
205cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
215cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovimport android.accounts.Account;
225cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovimport android.content.ContentResolver;
235cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovimport android.content.Context;
245cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovimport android.content.pm.PackageManager;
255cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovimport android.content.pm.PackageManager.NameNotFoundException;
265cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovimport android.content.res.Resources;
275cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovimport android.database.Cursor;
285cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovimport android.database.MatrixCursor;
295cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovimport android.net.Uri;
301fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikovimport android.os.Handler;
311fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikovimport android.os.Message;
325cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovimport android.provider.ContactsContract;
335cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Email;
345cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovimport android.provider.ContactsContract.Contacts;
355cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovimport android.text.TextUtils;
365cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovimport android.text.util.Rfc822Token;
375cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovimport android.util.Log;
385cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovimport android.view.View;
395cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovimport android.view.ViewGroup;
405cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovimport android.widget.Filter;
415cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovimport android.widget.Filterable;
425cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
435cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovimport java.util.ArrayList;
445cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovimport java.util.List;
455cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
465cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov/**
475cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * A base class for email address autocomplete adapters. It uses
485cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * {@link Email#CONTENT_FILTER_URI} to search for data rows by email address
495cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * and/or contact name. It also searches registered {@link Directory}'s.
505cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov */
515cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovpublic abstract class BaseEmailAddressAdapter extends CompositeCursorAdapter implements Filterable {
525cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
535cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    private static final String TAG = "BaseEmailAddressAdapter";
545cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
5522cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov    // TODO: revert to references to the Directory class as soon as the
5622cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov    // issue with the dependency on SDK 8 is resolved
5722cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov
5822cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov    // This is Directory.LOCAL_INVISIBLE
5922cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov    private static final long DIRECTORY_LOCAL_INVISIBLE = 1;
6022cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov
6122cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov    // This is ContactsContract.DIRECTORY_PARAM_KEY
6222cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov    private static final String DIRECTORY_PARAM_KEY = "directory";
6322cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov
641e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov    // This is ContactsContract.LIMIT_PARAM_KEY
651e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov    private static final String LIMIT_PARAM_KEY = "limit";
661e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov
67a15ab452e6a7603fb289666177aa13e5e4803d18Daisuke Miyakawa    // This is ContactsContract.PRIMARY_ACCOUNT_NAME
68a15ab452e6a7603fb289666177aa13e5e4803d18Daisuke Miyakawa    private static final String PRIMARY_ACCOUNT_NAME = "name_for_primary_account";
69a15ab452e6a7603fb289666177aa13e5e4803d18Daisuke Miyakawa    // This is ContactsContract.PRIMARY_ACCOUNT_TYPE
70a15ab452e6a7603fb289666177aa13e5e4803d18Daisuke Miyakawa    private static final String PRIMARY_ACCOUNT_TYPE = "type_for_primary_account";
71a15ab452e6a7603fb289666177aa13e5e4803d18Daisuke Miyakawa
721e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov    /**
7317d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov     * The preferred number of results to be retrieved. This number may be
7417d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov     * exceeded if there are several directories configured, because we will use
7517d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov     * the same limit for all directories.
761e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov     */
771e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov    private static final int DEFAULT_PREFERRED_MAX_RESULT_COUNT = 10;
781e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov
795cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    /**
8017d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov     * The number of extra entries requested to allow for duplicates. Duplicates
8117d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov     * are removed from the overall result.
8217d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov     */
8317d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov    private static final int ALLOWANCE_FOR_DUPLICATES = 5;
8417d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov
8517d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov    /**
861fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov     * The "Searching..." message will be displayed if search is not complete
871fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov     * within this many milliseconds.
881fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov     */
891fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov    private static final int MESSAGE_SEARCH_PENDING_DELAY = 1000;
901fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov
911fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov    private static final int MESSAGE_SEARCH_PENDING = 1;
921fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov
931fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov    /**
945cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov     * Model object for a {@link Directory} row. There is a partition in the
955cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov     * {@link CompositeCursorAdapter} for every directory (except
965cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov     * {@link Directory#LOCAL_INVISIBLE}.
975cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov     */
985cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    public final static class DirectoryPartition extends CompositeCursorAdapter.Partition {
995cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        public long directoryId;
1005cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        public String directoryType;
1015cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        public String displayName;
1025cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        public String accountName;
1035cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        public String accountType;
1045cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        public boolean loading;
1055cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        public CharSequence constraint;
1065cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        public DirectoryPartitionFilter filter;
1075cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
1085cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        public DirectoryPartition() {
1095cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            super(false, false);
1105cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        }
1115cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    }
1125cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
1135cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    private static class EmailQuery {
1145cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        public static final String[] PROJECTION = {
1155cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            Contacts.DISPLAY_NAME,  // 0
11622cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov            Email.DATA              // 1
1175cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        };
1185cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
1195cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        public static final int NAME = 0;
1205cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        public static final int ADDRESS = 1;
1215cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    }
1225cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
1235cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    private static class DirectoryListQuery {
12422cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov
12522cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov        // TODO: revert to references to the Directory class as soon as the
12622cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov        // issue with the dependency on SDK 8 is resolved
12722cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov        public static final Uri URI =
12822cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov                Uri.withAppendedPath(ContactsContract.AUTHORITY_URI, "directories");
12922cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov        private static final String DIRECTORY_ID = "_id";
13022cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov        private static final String DIRECTORY_ACCOUNT_NAME = "accountName";
13122cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov        private static final String DIRECTORY_ACCOUNT_TYPE = "accountType";
13222cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov        private static final String DIRECTORY_DISPLAY_NAME = "displayName";
13322cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov        private static final String DIRECTORY_PACKAGE_NAME = "packageName";
13422cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov        private static final String DIRECTORY_TYPE_RESOURCE_ID = "typeResourceId";
13522cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov
1365cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        public static final String[] PROJECTION = {
13722cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov            DIRECTORY_ID,               // 0
13822cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov            DIRECTORY_ACCOUNT_NAME,     // 1
13922cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov            DIRECTORY_ACCOUNT_TYPE,     // 2
14022cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov            DIRECTORY_DISPLAY_NAME,     // 3
14122cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov            DIRECTORY_PACKAGE_NAME,     // 4
14222cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov            DIRECTORY_TYPE_RESOURCE_ID, // 5
1435cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        };
1445cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
1455cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        public static final int ID = 0;
1465cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        public static final int ACCOUNT_NAME = 1;
1475cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        public static final int ACCOUNT_TYPE = 2;
1485cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        public static final int DISPLAY_NAME = 3;
1495cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        public static final int PACKAGE_NAME = 4;
1505cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        public static final int TYPE_RESOURCE_ID = 5;
1515cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    }
1525cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
1535cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    /**
1545cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov     * A fake column name that indicates a "Searching..." item in the list.
1555cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov     */
1565cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    private static final String SEARCHING_CURSOR_MARKER = "searching";
1575cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
1585cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    /**
1595cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov     * An asynchronous filter used for loading two data sets: email rows from the local
1605cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov     * contact provider and the list of {@link Directory}'s.
1615cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov     */
1625cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    private final class DefaultPartitionFilter extends Filter {
1631e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov
1645cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        @Override
1655cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        protected FilterResults performFiltering(CharSequence constraint) {
1665cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            Cursor directoryCursor = null;
1675cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            if (!mDirectoriesLoaded) {
1685cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                directoryCursor = mContentResolver.query(
16922cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov                        DirectoryListQuery.URI, DirectoryListQuery.PROJECTION, null, null, null);
1705cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                mDirectoriesLoaded = true;
1715cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            }
1725cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
1735cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            FilterResults results = new FilterResults();
1745cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            Cursor cursor = null;
1755cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            if (!TextUtils.isEmpty(constraint)) {
176a15ab452e6a7603fb289666177aa13e5e4803d18Daisuke Miyakawa                Uri.Builder builder = Email.CONTENT_FILTER_URI.buildUpon()
1771e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov                        .appendPath(constraint.toString())
1781e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov                        .appendQueryParameter(LIMIT_PARAM_KEY,
179a15ab452e6a7603fb289666177aa13e5e4803d18Daisuke Miyakawa                                String.valueOf(mPreferredMaxResultCount));
180a15ab452e6a7603fb289666177aa13e5e4803d18Daisuke Miyakawa                if (mAccount != null) {
181a15ab452e6a7603fb289666177aa13e5e4803d18Daisuke Miyakawa                    builder.appendQueryParameter(PRIMARY_ACCOUNT_NAME, mAccount.name);
182a15ab452e6a7603fb289666177aa13e5e4803d18Daisuke Miyakawa                    builder.appendQueryParameter(PRIMARY_ACCOUNT_TYPE, mAccount.type);
183a15ab452e6a7603fb289666177aa13e5e4803d18Daisuke Miyakawa                }
184a15ab452e6a7603fb289666177aa13e5e4803d18Daisuke Miyakawa                Uri uri = builder.build();
1855cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                cursor = mContentResolver.query(uri, EmailQuery.PROJECTION, null, null, null);
1865cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                results.count = cursor.getCount();
1875cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            }
1885cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            results.values = new Cursor[] { directoryCursor, cursor };
1895cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            return results;
1905cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        }
1915cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
1925cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        @Override
1935cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        protected void publishResults(CharSequence constraint, FilterResults results) {
1945cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            if (results.values != null) {
1955cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                Cursor[] cursors = (Cursor[]) results.values;
1965cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                onDirectoryLoadFinished(constraint, cursors[0], cursors[1]);
1975cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            }
1985cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            results.count = getCount();
1995cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        }
2005cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
2015cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        @Override
2025cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        public CharSequence convertResultToString(Object resultValue) {
2035cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            return makeDisplayString((Cursor) resultValue);
2045cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        }
2055cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    }
2065cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
2075cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    /**
2085cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov     * An asynchronous filter that performs search in a particular directory.
2095cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov     */
2105cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    private final class DirectoryPartitionFilter extends Filter {
2115cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        private final int mPartitionIndex;
2125cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        private final long mDirectoryId;
2131e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov        private int mLimit;
2145cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
2155cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        public DirectoryPartitionFilter(int partitionIndex, long directoryId) {
2165cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            this.mPartitionIndex = partitionIndex;
2175cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            this.mDirectoryId = directoryId;
2185cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        }
2195cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
2201e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov        public synchronized void setLimit(int limit) {
2211e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov            this.mLimit = limit;
2221e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov        }
2231e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov
2241e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov        public synchronized int getLimit() {
2251e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov            return this.mLimit;
2261e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov        }
2271e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov
2285cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        @Override
2295cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        protected FilterResults performFiltering(CharSequence constraint) {
2305cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            FilterResults results = new FilterResults();
2315cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            if (!TextUtils.isEmpty(constraint)) {
2325cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                Uri uri = Email.CONTENT_FILTER_URI.buildUpon()
2335cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                        .appendPath(constraint.toString())
23422cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov                        .appendQueryParameter(DIRECTORY_PARAM_KEY, String.valueOf(mDirectoryId))
23517d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov                        .appendQueryParameter(LIMIT_PARAM_KEY,
23617d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov                                String.valueOf(getLimit() + ALLOWANCE_FOR_DUPLICATES))
2375cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                        .build();
2385cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                Cursor cursor = mContentResolver.query(
2395cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                        uri, EmailQuery.PROJECTION, null, null, null);
2405cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                results.values = cursor;
2415cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            }
2425cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            return results;
2435cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        }
2445cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
2455cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        @Override
2465cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        protected void publishResults(CharSequence constraint, FilterResults results) {
2475cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            Cursor cursor = (Cursor) results.values;
2485cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            onPartitionLoadFinished(constraint, mPartitionIndex, cursor);
2495cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            results.count = getCount();
2505cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        }
2515cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    }
2525cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
2535cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    protected final ContentResolver mContentResolver;
2545cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    private boolean mDirectoriesLoaded;
2555cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    private Account mAccount;
2561e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov    private int mPreferredMaxResultCount;
2571fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov    private Handler mHandler;
2585cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
2595cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    public BaseEmailAddressAdapter(Context context) {
2601e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov        this(context, DEFAULT_PREFERRED_MAX_RESULT_COUNT);
2611e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov    }
2621e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov
2631e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov    public BaseEmailAddressAdapter(Context context, int preferredMaxResultCount) {
2645cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        super(context);
2655cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        mContentResolver = context.getContentResolver();
2661e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov        mPreferredMaxResultCount = preferredMaxResultCount;
2671fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov
2681fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov        mHandler = new Handler() {
2691fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov
2701fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov            @Override
2711fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov            public void handleMessage(Message msg) {
2721fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov                showSearchPendingIfNotComplete(msg.arg1);
2731fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov            }
2741fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov        };
2755cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    }
2765cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
2775cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    /**
2785cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov     * Set the account when known. Causes the search to prioritize contacts from
2795cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov     * that account.
2805cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov     */
2815cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    public void setAccount(Account account) {
2825cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        mAccount = account;
2835cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    }
2845cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
2855cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    /**
2865cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov     * Override to create a view for line item in the autocomplete suggestion list UI.
2875cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov     */
2885cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    protected abstract View inflateItemView(ViewGroup parent);
2895cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
2905cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    /**
2915cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov     * Override to populate the autocomplete suggestion line item UI with data.
2925cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov     */
2935cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    protected abstract void bindView(View view, String directoryType, String directoryName,
2945cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            String displayName, String emailAddress);
2955cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
2965cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    /**
2975cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov     * Override to create a view for a "Searching directory" line item, which is
2985cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov     * displayed temporarily while the corresponding filter is running.
2995cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov     */
3005cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    protected abstract View inflateItemViewLoading(ViewGroup parent);
3015cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
3025cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    /**
3035cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov     * Override to populate the "Searching directory" line item UI with data.
3045cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov     */
3055cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    protected abstract void bindViewLoading(View view, String directoryType, String directoryName);
3065cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
3075cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    @Override
3085cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    protected int getItemViewType(int partitionIndex, int position) {
3095cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        DirectoryPartition partition = (DirectoryPartition)getPartition(partitionIndex);
3105cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        return partition.loading ? 1 : 0;
3115cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    }
3125cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
3135cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    @Override
3145cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    protected View newView(Context context, int partitionIndex, Cursor cursor,
3155cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            int position, ViewGroup parent) {
3165cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        DirectoryPartition partition = (DirectoryPartition)getPartition(partitionIndex);
3175cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        if (partition.loading) {
3185cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            return inflateItemViewLoading(parent);
3195cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        } else {
3205cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            return inflateItemView(parent);
3215cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        }
3225cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    }
3235cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
3245cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    @Override
3255cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    protected void bindView(View v, int partition, Cursor cursor, int position) {
3265cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        DirectoryPartition directoryPartition = (DirectoryPartition)getPartition(partition);
3275cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        String directoryType = directoryPartition.directoryType;
3285cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        String directoryName = directoryPartition.displayName;
3295cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        if (directoryPartition.loading) {
3305cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            bindViewLoading(v, directoryType, directoryName);
3315cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        } else {
3325cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            String displayName = cursor.getString(EmailQuery.NAME);
3335cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            String emailAddress = cursor.getString(EmailQuery.ADDRESS);
33455f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov            if (TextUtils.isEmpty(displayName) || TextUtils.equals(displayName, emailAddress)) {
33555f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov                displayName = emailAddress;
33655f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov                emailAddress = null;
33755f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov            }
3385cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            bindView(v, directoryType, directoryName, displayName, emailAddress);
3395cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        }
3405cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    }
3415cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
3425cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    @Override
3435cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    public boolean areAllItemsEnabled() {
3445cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        return false;
3455cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    }
3465cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
3475cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    @Override
3485cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    protected boolean isEnabled(int partitionIndex, int position) {
3495cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        // The "Searching..." item should not be selectable
35017d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov        return !isLoading(partitionIndex);
35117d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov    }
35217d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov
35317d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov    private boolean isLoading(int partitionIndex) {
35417d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov        return ((DirectoryPartition)getPartition(partitionIndex)).loading;
3555cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    }
3565cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
3575cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    @Override
3585cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    public Filter getFilter() {
3595cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        return new DefaultPartitionFilter();
3605cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    }
3615cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
3625cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    /**
3635cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov     * Handles the result of the initial call, which brings back the list of
3645cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov     * directories as well as the search results for the local directories.
3655cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov     */
3665cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    protected void onDirectoryLoadFinished(
3675cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            CharSequence constraint, Cursor directoryCursor, Cursor defaultPartitionCursor) {
3685cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        if (directoryCursor != null) {
3695cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            PackageManager packageManager = getContext().getPackageManager();
3705cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            DirectoryPartition preferredDirectory = null;
3715cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            List<DirectoryPartition> directories = new ArrayList<DirectoryPartition>();
3725cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            while (directoryCursor.moveToNext()) {
3735cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                long id = directoryCursor.getLong(DirectoryListQuery.ID);
3745cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
3755cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                // Skip the local invisible directory, because the default directory
3765cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                // already includes all local results.
37722cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov                if (id == DIRECTORY_LOCAL_INVISIBLE) {
3785cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                    continue;
3795cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                }
3805cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
3815cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                DirectoryPartition partition = new DirectoryPartition();
3825cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                partition.directoryId = id;
3835cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                partition.displayName = directoryCursor.getString(DirectoryListQuery.DISPLAY_NAME);
3845cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                partition.accountName = directoryCursor.getString(DirectoryListQuery.ACCOUNT_NAME);
3855cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                partition.accountType = directoryCursor.getString(DirectoryListQuery.ACCOUNT_TYPE);
3865cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                String packageName = directoryCursor.getString(DirectoryListQuery.PACKAGE_NAME);
3875cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                int resourceId = directoryCursor.getInt(DirectoryListQuery.TYPE_RESOURCE_ID);
3885cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                if (packageName != null && resourceId != 0) {
3895cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                    try {
3905cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                        Resources resources =
3915cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                                packageManager.getResourcesForApplication(packageName);
3925cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                        partition.directoryType = resources.getString(resourceId);
3935cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                        if (partition.directoryType == null) {
3945cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                            Log.e(TAG, "Cannot resolve directory name: "
3955cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                                    + resourceId + "@" + packageName);
3965cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                        }
3975cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                    } catch (NameNotFoundException e) {
3985cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                        Log.e(TAG, "Cannot resolve directory name: "
3995cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                                + resourceId + "@" + packageName, e);
4005cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                    }
4015cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                }
4025cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
4035cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                // If an account has been provided and we found a directory that
4045cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                // corresponds to that account, place that directory second, directly
4055cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                // underneath the local contacts.
4065cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                if (mAccount != null && mAccount.name.equals(partition.accountName) &&
4075cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                        mAccount.type.equals(partition.accountType)) {
4085cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                    preferredDirectory = partition;
4095cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                } else {
4105cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                    directories.add(partition);
4115cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                }
4125cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            }
4135cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
4145cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            if (preferredDirectory != null) {
4155cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                directories.add(1, preferredDirectory);
4165cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            }
4175cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
4185cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            for (DirectoryPartition partition : directories) {
4195cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                addPartition(partition);
4205cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            }
4215cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        }
4225cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
42355f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov        int count = getPartitionCount();
4241e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov        int limit = 0;
42555f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov
42655f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov        // Since we will be changing several partitions at once, hold the data change
42755f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov        // notifications
42855f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov        setNotificationsEnabled(false);
42955f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov        try {
43055f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov            // The filter has loaded results for the default partition too.
43155f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov            if (defaultPartitionCursor != null && getPartitionCount() > 0) {
43255f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov                changeCursor(0, defaultPartitionCursor);
43355f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov            }
43455f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov
4351e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov            int defaultPartitionCount = (defaultPartitionCursor == null ? 0
4361e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov                    : defaultPartitionCursor.getCount());
4371e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov
4381e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov            limit = mPreferredMaxResultCount - defaultPartitionCount;
4391e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov
44055f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov            // Show non-default directories as "loading"
44155f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov            // Note: skipping the default partition (index 0), which has already been loaded
44255f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov            for (int i = 1; i < count; i++) {
44355f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov                DirectoryPartition partition = (DirectoryPartition) getPartition(i);
44455f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov                partition.constraint = constraint;
44555f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov
4461e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov                if (limit > 0) {
4471e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov                    if (!partition.loading) {
4481e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov                        partition.loading = true;
4491fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov                        changeCursor(i, null);
4501e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov                    }
4511e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov                } else {
4521e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov                    partition.loading = false;
4531e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov                    changeCursor(i, null);
45455f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov                }
45555f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov            }
45655f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov        } finally {
45755f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov            setNotificationsEnabled(true);
4585cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        }
4595cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
4605cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        // Start search in other directories
4615cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        // Note: skipping the default partition (index 0), which has already been loaded
4625cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        for (int i = 1; i < count; i++) {
4635cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            DirectoryPartition partition = (DirectoryPartition) getPartition(i);
4641e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov            if (partition.loading) {
4651fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov                mHandler.removeMessages(MESSAGE_SEARCH_PENDING, partition);
4661fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov                Message msg = mHandler.obtainMessage(MESSAGE_SEARCH_PENDING, i, 0, partition);
4671fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov                mHandler.sendMessageDelayed(msg, MESSAGE_SEARCH_PENDING_DELAY);
4681e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov                if (partition.filter == null) {
4691e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov                    partition.filter = new DirectoryPartitionFilter(i, partition.directoryId);
4701e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov                }
4711e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov                partition.filter.setLimit(limit);
4721e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov                partition.filter.filter(constraint);
4731e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov            } else {
4741e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov                if (partition.filter != null) {
4751e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov                    // Cancel any previous loading request
4761e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov                    partition.filter.filter(null);
4771e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov                }
4785cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            }
4795cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        }
4805cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    }
4815cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
4821fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov    void showSearchPendingIfNotComplete(int partitionIndex) {
4831fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov        if (partitionIndex < getPartitionCount()) {
4841fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov            DirectoryPartition partition = (DirectoryPartition) getPartition(partitionIndex);
4851fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov            if (partition.loading) {
4861fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov                changeCursor(partitionIndex, createLoadingCursor());
4871fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov            }
4881fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov        }
4891fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov    }
4901fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov
4915cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    /**
4925cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov     * Creates a dummy cursor to represent the "Searching directory..." item.
4935cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov     */
4945cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    private Cursor createLoadingCursor() {
4955cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        MatrixCursor cursor = new MatrixCursor(new String[]{SEARCHING_CURSOR_MARKER});
4965cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        cursor.addRow(new Object[]{""});
4975cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        return cursor;
4985cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    }
4995cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
5005cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    public void onPartitionLoadFinished(
5015cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            CharSequence constraint, int partitionIndex, Cursor cursor) {
5025cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        if (partitionIndex < getPartitionCount()) {
5035cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            DirectoryPartition partition = (DirectoryPartition) getPartition(partitionIndex);
5041fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov
5055cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            // Check if the received result matches the current constraint
5065cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            // If not - the user must have continued typing after the request
5075cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            // was issued
5081e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov            if (partition.loading && TextUtils.equals(constraint, partition.constraint)) {
5095cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                partition.loading = false;
5101fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov                mHandler.removeMessages(MESSAGE_SEARCH_PENDING, partition);
51117d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov                changeCursor(partitionIndex, removeDuplicatesAndTruncate(partitionIndex, cursor));
5125cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            } else {
5135cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                // We got the result for an unexpected query (the user is still typing)
5145cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                // Just ignore this result
5155cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                if (cursor != null) {
5165cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                    cursor.close();
5175cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov                }
5185cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            }
5195cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        } else if (cursor != null) {
5205cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            cursor.close();
5215cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        }
5225cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    }
5235cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
52417d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov    /**
52517d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov     * Post-process the cursor to eliminate duplicates.  Closes the original cursor
52617d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov     * and returns a new one.
52717d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov     */
52817d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov    private Cursor removeDuplicatesAndTruncate(int partition, Cursor cursor) {
52917d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov        if (cursor == null) {
53017d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov            return null;
53117d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov        }
53217d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov
53317d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov        if (cursor.getCount() <= DEFAULT_PREFERRED_MAX_RESULT_COUNT
53417d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov                && !hasDuplicates(cursor, partition)) {
53517d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov            return cursor;
53617d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov        }
53717d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov
53817d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov        int count = 0;
53917d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov        MatrixCursor newCursor = new MatrixCursor(EmailQuery.PROJECTION);
54017d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov        cursor.moveToPosition(-1);
54117d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov        while (cursor.moveToNext() && count < DEFAULT_PREFERRED_MAX_RESULT_COUNT) {
54217d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov            String displayName = cursor.getString(EmailQuery.NAME);
54317d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov            String emailAddress = cursor.getString(EmailQuery.ADDRESS);
54417d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov            if (!isDuplicate(emailAddress, partition)) {
54517d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov                newCursor.addRow(new Object[]{displayName, emailAddress});
54617d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov                count++;
54717d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov            }
54817d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov        }
54917d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov        cursor.close();
55017d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov
55117d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov        return newCursor;
55217d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov    }
55317d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov
55417d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov    private boolean hasDuplicates(Cursor cursor, int partition) {
55517d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov        cursor.moveToPosition(-1);
55617d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov        while (cursor.moveToNext()) {
55717d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov            String emailAddress = cursor.getString(EmailQuery.ADDRESS);
55817d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov            if (isDuplicate(emailAddress, partition)) {
55917d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov                return true;
56017d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov            }
56117d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov        }
56217d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov        return false;
56317d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov    }
56417d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov
56517d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov    /**
56617d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov     * Checks if the supplied email address is already present in partitions other
56717d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov     * than the supplied one.
56817d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov     */
56917d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov    private boolean isDuplicate(String emailAddress, int excludePartition) {
57017d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov        int partitionCount = getPartitionCount();
57117d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov        for (int partition = 0; partition < partitionCount; partition++) {
57217d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov            if (partition != excludePartition && !isLoading(partition)) {
57317d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov                Cursor cursor = getCursor(partition);
57417d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov                if (cursor != null) {
57517d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov                    cursor.moveToPosition(-1);
57617d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov                    while (cursor.moveToNext()) {
57717d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov                        String address = cursor.getString(EmailQuery.ADDRESS);
57817d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov                        if (TextUtils.equals(emailAddress, address)) {
57917d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov                            return true;
58017d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov                        }
58117d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov                    }
58217d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov                }
58317d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov            }
58417d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov        }
58517d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov
58617d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov        return false;
58717d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov    }
58817d4817661d16464ffa0fd02cb6d1b362e96b8a1Dmitri Plotnikov
5895cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    private final String makeDisplayString(Cursor cursor) {
5905cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        if (cursor.getColumnName(0).equals(SEARCHING_CURSOR_MARKER)) {
5915cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov            return "";
5925cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov        }
5935cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov
59455f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov        String displayName = cursor.getString(EmailQuery.NAME);
59555f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov        String emailAddress = cursor.getString(EmailQuery.ADDRESS);
59655f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov        if (TextUtils.isEmpty(displayName) || TextUtils.equals(displayName, emailAddress)) {
59755f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov             return emailAddress;
59855f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov        } else {
59955f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov            return new Rfc822Token(displayName, emailAddress, null).toString();
60055f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov        }
6015cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov    }
6025cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov}
603