BaseEmailAddressAdapter.java revision 1fa3a8f74d46a616e27c23ed1512f4b7de2ad66d
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 671e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov /** 681e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov * The preferred number of results to be retrieved. This number may be 691e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov * exceeded if there are several directories configured, because we will 701e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov * use the same limit for all directories. 711e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov */ 721e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov private static final int DEFAULT_PREFERRED_MAX_RESULT_COUNT = 10; 731e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov 745cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov /** 751fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov * The "Searching..." message will be displayed if search is not complete 761fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov * within this many milliseconds. 771fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov */ 781fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov private static final int MESSAGE_SEARCH_PENDING_DELAY = 1000; 791fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov 801fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov private static final int MESSAGE_SEARCH_PENDING = 1; 811fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov 821fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov /** 835cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * Model object for a {@link Directory} row. There is a partition in the 845cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * {@link CompositeCursorAdapter} for every directory (except 855cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * {@link Directory#LOCAL_INVISIBLE}. 865cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov */ 875cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public final static class DirectoryPartition extends CompositeCursorAdapter.Partition { 885cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public long directoryId; 895cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public String directoryType; 905cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public String displayName; 915cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public String accountName; 925cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public String accountType; 935cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public boolean loading; 945cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public CharSequence constraint; 955cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public DirectoryPartitionFilter filter; 965cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 975cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public DirectoryPartition() { 985cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov super(false, false); 995cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 1005cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 1015cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 1025cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov private static class EmailQuery { 1035cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public static final String[] PROJECTION = { 1045cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov Contacts.DISPLAY_NAME, // 0 10522cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov Email.DATA // 1 1065cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov }; 1075cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 1085cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public static final int NAME = 0; 1095cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public static final int ADDRESS = 1; 1105cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 1115cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 1125cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov private static class DirectoryListQuery { 11322cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov 11422cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov // TODO: revert to references to the Directory class as soon as the 11522cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov // issue with the dependency on SDK 8 is resolved 11622cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov public static final Uri URI = 11722cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov Uri.withAppendedPath(ContactsContract.AUTHORITY_URI, "directories"); 11822cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov private static final String DIRECTORY_ID = "_id"; 11922cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov private static final String DIRECTORY_ACCOUNT_NAME = "accountName"; 12022cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov private static final String DIRECTORY_ACCOUNT_TYPE = "accountType"; 12122cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov private static final String DIRECTORY_DISPLAY_NAME = "displayName"; 12222cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov private static final String DIRECTORY_PACKAGE_NAME = "packageName"; 12322cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov private static final String DIRECTORY_TYPE_RESOURCE_ID = "typeResourceId"; 12422cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov 1255cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public static final String[] PROJECTION = { 12622cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov DIRECTORY_ID, // 0 12722cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov DIRECTORY_ACCOUNT_NAME, // 1 12822cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov DIRECTORY_ACCOUNT_TYPE, // 2 12922cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov DIRECTORY_DISPLAY_NAME, // 3 13022cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov DIRECTORY_PACKAGE_NAME, // 4 13122cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov DIRECTORY_TYPE_RESOURCE_ID, // 5 1325cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov }; 1335cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 1345cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public static final int ID = 0; 1355cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public static final int ACCOUNT_NAME = 1; 1365cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public static final int ACCOUNT_TYPE = 2; 1375cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public static final int DISPLAY_NAME = 3; 1385cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public static final int PACKAGE_NAME = 4; 1395cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public static final int TYPE_RESOURCE_ID = 5; 1405cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 1415cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 1425cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov /** 1435cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * A fake column name that indicates a "Searching..." item in the list. 1445cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov */ 1455cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov private static final String SEARCHING_CURSOR_MARKER = "searching"; 1465cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 1475cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov /** 1485cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * An asynchronous filter used for loading two data sets: email rows from the local 1495cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * contact provider and the list of {@link Directory}'s. 1505cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov */ 1515cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov private final class DefaultPartitionFilter extends Filter { 1521e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov 1535cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov @Override 1545cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov protected FilterResults performFiltering(CharSequence constraint) { 1555cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov Cursor directoryCursor = null; 1565cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov if (!mDirectoriesLoaded) { 1575cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov directoryCursor = mContentResolver.query( 15822cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov DirectoryListQuery.URI, DirectoryListQuery.PROJECTION, null, null, null); 1595cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov mDirectoriesLoaded = true; 1605cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 1615cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 1625cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov FilterResults results = new FilterResults(); 1635cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov Cursor cursor = null; 1645cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov if (!TextUtils.isEmpty(constraint)) { 1651e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov Uri uri = Email.CONTENT_FILTER_URI.buildUpon() 1661e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov .appendPath(constraint.toString()) 1671e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov .appendQueryParameter(LIMIT_PARAM_KEY, 1681e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov String.valueOf(mPreferredMaxResultCount)) 1691e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov .build(); 1705cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov cursor = mContentResolver.query(uri, EmailQuery.PROJECTION, null, null, null); 1715cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov results.count = cursor.getCount(); 1725cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 1735cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov results.values = new Cursor[] { directoryCursor, cursor }; 1745cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov return results; 1755cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 1765cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 1775cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov @Override 1785cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov protected void publishResults(CharSequence constraint, FilterResults results) { 1795cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov if (results.values != null) { 1805cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov Cursor[] cursors = (Cursor[]) results.values; 1815cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov onDirectoryLoadFinished(constraint, cursors[0], cursors[1]); 1825cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 1835cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov results.count = getCount(); 1845cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 1855cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 1865cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov @Override 1875cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public CharSequence convertResultToString(Object resultValue) { 1885cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov return makeDisplayString((Cursor) resultValue); 1895cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 1905cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 1915cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 1925cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov /** 1935cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * An asynchronous filter that performs search in a particular directory. 1945cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov */ 1955cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov private final class DirectoryPartitionFilter extends Filter { 1965cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov private final int mPartitionIndex; 1975cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov private final long mDirectoryId; 1981e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov private int mLimit; 1995cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 2005cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public DirectoryPartitionFilter(int partitionIndex, long directoryId) { 2015cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov this.mPartitionIndex = partitionIndex; 2025cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov this.mDirectoryId = directoryId; 2035cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 2045cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 2051e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov public synchronized void setLimit(int limit) { 2061e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov this.mLimit = limit; 2071e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov } 2081e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov 2091e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov public synchronized int getLimit() { 2101e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov return this.mLimit; 2111e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov } 2121e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov 2135cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov @Override 2145cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov protected FilterResults performFiltering(CharSequence constraint) { 2155cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov FilterResults results = new FilterResults(); 2165cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov if (!TextUtils.isEmpty(constraint)) { 2175cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov Uri uri = Email.CONTENT_FILTER_URI.buildUpon() 2185cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov .appendPath(constraint.toString()) 21922cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov .appendQueryParameter(DIRECTORY_PARAM_KEY, String.valueOf(mDirectoryId)) 2201e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov .appendQueryParameter(LIMIT_PARAM_KEY, String.valueOf(getLimit())) 2215cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov .build(); 2225cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov Cursor cursor = mContentResolver.query( 2235cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov uri, EmailQuery.PROJECTION, null, null, null); 2245cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov results.values = cursor; 2255cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 2265cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov return results; 2275cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 2285cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 2295cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov @Override 2305cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov protected void publishResults(CharSequence constraint, FilterResults results) { 2315cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov Cursor cursor = (Cursor) results.values; 2325cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov onPartitionLoadFinished(constraint, mPartitionIndex, cursor); 2335cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov results.count = getCount(); 2345cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 2355cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 2365cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 2375cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov protected final ContentResolver mContentResolver; 2385cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov private boolean mDirectoriesLoaded; 2395cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov private Account mAccount; 2401e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov private int mPreferredMaxResultCount; 2411fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov private Handler mHandler; 2425cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 2435cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public BaseEmailAddressAdapter(Context context) { 2441e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov this(context, DEFAULT_PREFERRED_MAX_RESULT_COUNT); 2451e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov } 2461e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov 2471e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov public BaseEmailAddressAdapter(Context context, int preferredMaxResultCount) { 2485cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov super(context); 2495cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov mContentResolver = context.getContentResolver(); 2501e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov mPreferredMaxResultCount = preferredMaxResultCount; 2511fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov 2521fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov mHandler = new Handler() { 2531fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov 2541fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov @Override 2551fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov public void handleMessage(Message msg) { 2561fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov showSearchPendingIfNotComplete(msg.arg1); 2571fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov } 2581fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov }; 2595cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 2605cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 2615cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov /** 2625cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * Set the account when known. Causes the search to prioritize contacts from 2635cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * that account. 2645cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov */ 2655cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public void setAccount(Account account) { 2665cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov mAccount = account; 2675cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 2685cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 2695cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov /** 2705cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * Override to create a view for line item in the autocomplete suggestion list UI. 2715cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov */ 2725cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov protected abstract View inflateItemView(ViewGroup parent); 2735cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 2745cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov /** 2755cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * Override to populate the autocomplete suggestion line item UI with data. 2765cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov */ 2775cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov protected abstract void bindView(View view, String directoryType, String directoryName, 2785cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov String displayName, String emailAddress); 2795cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 2805cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov /** 2815cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * Override to create a view for a "Searching directory" line item, which is 2825cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * displayed temporarily while the corresponding filter is running. 2835cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov */ 2845cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov protected abstract View inflateItemViewLoading(ViewGroup parent); 2855cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 2865cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov /** 2875cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * Override to populate the "Searching directory" line item UI with data. 2885cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov */ 2895cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov protected abstract void bindViewLoading(View view, String directoryType, String directoryName); 2905cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 2915cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov @Override 2925cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov protected int getItemViewType(int partitionIndex, int position) { 2935cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov DirectoryPartition partition = (DirectoryPartition)getPartition(partitionIndex); 2945cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov return partition.loading ? 1 : 0; 2955cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 2965cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 2975cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov @Override 2985cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov protected View newView(Context context, int partitionIndex, Cursor cursor, 2995cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov int position, ViewGroup parent) { 3005cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov DirectoryPartition partition = (DirectoryPartition)getPartition(partitionIndex); 3015cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov if (partition.loading) { 3025cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov return inflateItemViewLoading(parent); 3035cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } else { 3045cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov return inflateItemView(parent); 3055cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 3065cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 3075cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 3085cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov @Override 3095cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov protected void bindView(View v, int partition, Cursor cursor, int position) { 3105cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov DirectoryPartition directoryPartition = (DirectoryPartition)getPartition(partition); 3115cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov String directoryType = directoryPartition.directoryType; 3125cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov String directoryName = directoryPartition.displayName; 3135cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov if (directoryPartition.loading) { 3145cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov bindViewLoading(v, directoryType, directoryName); 3155cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } else { 3165cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov String displayName = cursor.getString(EmailQuery.NAME); 3175cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov String emailAddress = cursor.getString(EmailQuery.ADDRESS); 31855f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov if (TextUtils.isEmpty(displayName) || TextUtils.equals(displayName, emailAddress)) { 31955f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov displayName = emailAddress; 32055f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov emailAddress = null; 32155f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov } 3225cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov bindView(v, directoryType, directoryName, displayName, emailAddress); 3235cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 3245cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 3255cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 3265cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov @Override 3275cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public boolean areAllItemsEnabled() { 3285cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov return false; 3295cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 3305cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 3315cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov @Override 3325cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov protected boolean isEnabled(int partitionIndex, int position) { 3335cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov // The "Searching..." item should not be selectable 3345cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov return !((DirectoryPartition)getPartition(partitionIndex)).loading; 3355cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 3365cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 3375cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov @Override 3385cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public Filter getFilter() { 3395cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov return new DefaultPartitionFilter(); 3405cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 3415cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 3425cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov /** 3435cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * Handles the result of the initial call, which brings back the list of 3445cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * directories as well as the search results for the local directories. 3455cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov */ 3465cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov protected void onDirectoryLoadFinished( 3475cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov CharSequence constraint, Cursor directoryCursor, Cursor defaultPartitionCursor) { 3485cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov if (directoryCursor != null) { 3495cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov PackageManager packageManager = getContext().getPackageManager(); 3505cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov DirectoryPartition preferredDirectory = null; 3515cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov List<DirectoryPartition> directories = new ArrayList<DirectoryPartition>(); 3525cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov while (directoryCursor.moveToNext()) { 3535cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov long id = directoryCursor.getLong(DirectoryListQuery.ID); 3545cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 3555cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov // Skip the local invisible directory, because the default directory 3565cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov // already includes all local results. 35722cb78016de447ec1a1b270a6fc22352c3186929Dmitri Plotnikov if (id == DIRECTORY_LOCAL_INVISIBLE) { 3585cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov continue; 3595cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 3605cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 3615cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov DirectoryPartition partition = new DirectoryPartition(); 3625cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov partition.directoryId = id; 3635cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov partition.displayName = directoryCursor.getString(DirectoryListQuery.DISPLAY_NAME); 3645cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov partition.accountName = directoryCursor.getString(DirectoryListQuery.ACCOUNT_NAME); 3655cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov partition.accountType = directoryCursor.getString(DirectoryListQuery.ACCOUNT_TYPE); 3665cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov String packageName = directoryCursor.getString(DirectoryListQuery.PACKAGE_NAME); 3675cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov int resourceId = directoryCursor.getInt(DirectoryListQuery.TYPE_RESOURCE_ID); 3685cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov if (packageName != null && resourceId != 0) { 3695cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov try { 3705cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov Resources resources = 3715cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov packageManager.getResourcesForApplication(packageName); 3725cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov partition.directoryType = resources.getString(resourceId); 3735cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov if (partition.directoryType == null) { 3745cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov Log.e(TAG, "Cannot resolve directory name: " 3755cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov + resourceId + "@" + packageName); 3765cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 3775cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } catch (NameNotFoundException e) { 3785cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov Log.e(TAG, "Cannot resolve directory name: " 3795cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov + resourceId + "@" + packageName, e); 3805cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 3815cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 3825cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 3835cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov // If an account has been provided and we found a directory that 3845cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov // corresponds to that account, place that directory second, directly 3855cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov // underneath the local contacts. 3865cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov if (mAccount != null && mAccount.name.equals(partition.accountName) && 3875cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov mAccount.type.equals(partition.accountType)) { 3885cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov preferredDirectory = partition; 3895cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } else { 3905cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov directories.add(partition); 3915cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 3925cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 3935cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 3945cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov if (preferredDirectory != null) { 3955cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov directories.add(1, preferredDirectory); 3965cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 3975cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 3985cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov for (DirectoryPartition partition : directories) { 3995cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov addPartition(partition); 4005cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 4015cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 4025cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 40355f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov int count = getPartitionCount(); 4041e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov int limit = 0; 40555f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov 40655f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov // Since we will be changing several partitions at once, hold the data change 40755f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov // notifications 40855f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov setNotificationsEnabled(false); 40955f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov try { 41055f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov // The filter has loaded results for the default partition too. 41155f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov if (defaultPartitionCursor != null && getPartitionCount() > 0) { 41255f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov changeCursor(0, defaultPartitionCursor); 41355f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov } 41455f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov 4151e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov int defaultPartitionCount = (defaultPartitionCursor == null ? 0 4161e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov : defaultPartitionCursor.getCount()); 4171e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov 4181e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov limit = mPreferredMaxResultCount - defaultPartitionCount; 4191e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov 42055f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov // Show non-default directories as "loading" 42155f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov // Note: skipping the default partition (index 0), which has already been loaded 42255f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov for (int i = 1; i < count; i++) { 42355f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov DirectoryPartition partition = (DirectoryPartition) getPartition(i); 42455f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov partition.constraint = constraint; 42555f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov 4261e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov if (limit > 0) { 4271e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov if (!partition.loading) { 4281e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov partition.loading = true; 4291fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov changeCursor(i, null); 4301e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov } 4311e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov } else { 4321e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov partition.loading = false; 4331e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov changeCursor(i, null); 43455f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov } 43555f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov } 43655f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov } finally { 43755f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov setNotificationsEnabled(true); 4385cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 4395cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 4405cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov // Start search in other directories 4415cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov // Note: skipping the default partition (index 0), which has already been loaded 4425cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov for (int i = 1; i < count; i++) { 4435cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov DirectoryPartition partition = (DirectoryPartition) getPartition(i); 4441e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov if (partition.loading) { 4451fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov mHandler.removeMessages(MESSAGE_SEARCH_PENDING, partition); 4461fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov Message msg = mHandler.obtainMessage(MESSAGE_SEARCH_PENDING, i, 0, partition); 4471fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov mHandler.sendMessageDelayed(msg, MESSAGE_SEARCH_PENDING_DELAY); 4481e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov if (partition.filter == null) { 4491e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov partition.filter = new DirectoryPartitionFilter(i, partition.directoryId); 4501e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov } 4511e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov partition.filter.setLimit(limit); 4521e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov partition.filter.filter(constraint); 4531e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov } else { 4541e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov if (partition.filter != null) { 4551e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov // Cancel any previous loading request 4561e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov partition.filter.filter(null); 4571e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov } 4585cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 4595cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 4605cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 4615cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 4621fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov void showSearchPendingIfNotComplete(int partitionIndex) { 4631fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov if (partitionIndex < getPartitionCount()) { 4641fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov DirectoryPartition partition = (DirectoryPartition) getPartition(partitionIndex); 4651fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov if (partition.loading) { 4661fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov changeCursor(partitionIndex, createLoadingCursor()); 4671fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov } 4681fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov } 4691fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov } 4701fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov 4715cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov /** 4725cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * Creates a dummy cursor to represent the "Searching directory..." item. 4735cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov */ 4745cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov private Cursor createLoadingCursor() { 4755cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov MatrixCursor cursor = new MatrixCursor(new String[]{SEARCHING_CURSOR_MARKER}); 4765cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov cursor.addRow(new Object[]{""}); 4775cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov return cursor; 4785cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 4795cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 4805cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public void onPartitionLoadFinished( 4815cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov CharSequence constraint, int partitionIndex, Cursor cursor) { 4825cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov if (partitionIndex < getPartitionCount()) { 4835cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov DirectoryPartition partition = (DirectoryPartition) getPartition(partitionIndex); 4841fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov 4855cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov // Check if the received result matches the current constraint 4865cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov // If not - the user must have continued typing after the request 4875cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov // was issued 4881e35ed124efed58b9ef6e70059865cbd145bbce8Dmitri Plotnikov if (partition.loading && TextUtils.equals(constraint, partition.constraint)) { 4895cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov partition.loading = false; 4901fa3a8f74d46a616e27c23ed1512f4b7de2ad66dDmitri Plotnikov mHandler.removeMessages(MESSAGE_SEARCH_PENDING, partition); 4915cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov changeCursor(partitionIndex, cursor); 4925cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } else { 4935cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov // We got the result for an unexpected query (the user is still typing) 4945cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov // Just ignore this result 4955cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov if (cursor != null) { 4965cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov cursor.close(); 4975cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 4985cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 4995cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } else if (cursor != null) { 5005cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov cursor.close(); 5015cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 5025cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 5035cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 5045cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov private final String makeDisplayString(Cursor cursor) { 5055cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov if (cursor.getColumnName(0).equals(SEARCHING_CURSOR_MARKER)) { 5065cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov return ""; 5075cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 5085cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 50955f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov String displayName = cursor.getString(EmailQuery.NAME); 51055f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov String emailAddress = cursor.getString(EmailQuery.ADDRESS); 51155f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov if (TextUtils.isEmpty(displayName) || TextUtils.equals(displayName, emailAddress)) { 51255f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov return emailAddress; 51355f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov } else { 51455f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov return new Rfc822Token(displayName, emailAddress, null).toString(); 51555f04311fb40ccadb224f1a4dc1b8ff473dfdf03Dmitri Plotnikov } 5165cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 5175cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov} 518