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