BaseEmailAddressAdapter.java revision 5cc774535d73c09b6788b63ecc728e60da09cfa9
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.app.Activity; 235cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovimport android.content.ContentResolver; 245cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovimport android.content.Context; 255cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovimport android.content.pm.PackageManager; 265cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovimport android.content.pm.PackageManager.NameNotFoundException; 275cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovimport android.content.res.Resources; 285cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovimport android.database.Cursor; 295cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovimport android.database.MatrixCursor; 305cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovimport android.net.Uri; 315cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovimport android.provider.ContactsContract; 325cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Email; 335cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovimport android.provider.ContactsContract.Contacts; 345cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikovimport android.provider.ContactsContract.Directory; 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 555cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov /** 565cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * Model object for a {@link Directory} row. There is a partition in the 575cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * {@link CompositeCursorAdapter} for every directory (except 585cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * {@link Directory#LOCAL_INVISIBLE}. 595cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov */ 605cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public final static class DirectoryPartition extends CompositeCursorAdapter.Partition { 615cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public long directoryId; 625cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public String directoryType; 635cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public String displayName; 645cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public String accountName; 655cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public String accountType; 665cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public boolean loading; 675cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public CharSequence constraint; 685cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public DirectoryPartitionFilter filter; 695cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 705cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public DirectoryPartition() { 715cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov super(false, false); 725cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 735cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 745cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 755cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov private static class EmailQuery { 765cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public static final String[] PROJECTION = { 775cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov Contacts.DISPLAY_NAME, // 0 785cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov Email.ADDRESS // 1 795cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov }; 805cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 815cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public static final int NAME = 0; 825cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public static final int ADDRESS = 1; 835cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 845cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 855cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov private static class DirectoryListQuery { 865cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public static final String[] PROJECTION = { 875cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov Directory._ID, // 0 885cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov Directory.ACCOUNT_NAME, // 1 895cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov Directory.ACCOUNT_TYPE, // 2 905cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov Directory.DISPLAY_NAME, // 3 915cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov Directory.PACKAGE_NAME, // 4 925cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov Directory.TYPE_RESOURCE_ID, // 5 935cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov }; 945cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 955cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public static final int ID = 0; 965cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public static final int ACCOUNT_NAME = 1; 975cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public static final int ACCOUNT_TYPE = 2; 985cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public static final int DISPLAY_NAME = 3; 995cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public static final int PACKAGE_NAME = 4; 1005cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public static final int TYPE_RESOURCE_ID = 5; 1015cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 1025cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 1035cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov /** 1045cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * A fake column name that indicates a "Searching..." item in the list. 1055cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov */ 1065cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov private static final String SEARCHING_CURSOR_MARKER = "searching"; 1075cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 1085cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov /** 1095cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * An asynchronous filter used for loading two data sets: email rows from the local 1105cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * contact provider and the list of {@link Directory}'s. 1115cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov */ 1125cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov private final class DefaultPartitionFilter extends Filter { 1135cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov @Override 1145cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov protected FilterResults performFiltering(CharSequence constraint) { 1155cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov Cursor directoryCursor = null; 1165cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov if (!mDirectoriesLoaded) { 1175cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov directoryCursor = mContentResolver.query( 1185cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov Directory.CONTENT_URI, DirectoryListQuery.PROJECTION, null, null, null); 1195cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov mDirectoriesLoaded = true; 1205cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 1215cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 1225cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov FilterResults results = new FilterResults(); 1235cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov Cursor cursor = null; 1245cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov if (!TextUtils.isEmpty(constraint)) { 1255cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov Uri uri = Uri.withAppendedPath( 1265cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov Email.CONTENT_FILTER_URI, Uri.encode(constraint.toString())); 1275cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov cursor = mContentResolver.query(uri, EmailQuery.PROJECTION, null, null, null); 1285cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov results.count = cursor.getCount(); 1295cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 1305cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov results.values = new Cursor[] { directoryCursor, cursor }; 1315cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov return results; 1325cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 1335cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 1345cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov @Override 1355cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov protected void publishResults(CharSequence constraint, FilterResults results) { 1365cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov if (results.values != null) { 1375cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov Cursor[] cursors = (Cursor[]) results.values; 1385cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov onDirectoryLoadFinished(constraint, cursors[0], cursors[1]); 1395cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 1405cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov results.count = getCount(); 1415cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 1425cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 1435cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov @Override 1445cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public CharSequence convertResultToString(Object resultValue) { 1455cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov return makeDisplayString((Cursor) resultValue); 1465cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 1475cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 1485cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 1495cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov /** 1505cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * An asynchronous filter that performs search in a particular directory. 1515cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov */ 1525cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov private final class DirectoryPartitionFilter extends Filter { 1535cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 1545cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov private final int mPartitionIndex; 1555cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov private final long mDirectoryId; 1565cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 1575cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public DirectoryPartitionFilter(int partitionIndex, long directoryId) { 1585cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov this.mPartitionIndex = partitionIndex; 1595cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov this.mDirectoryId = directoryId; 1605cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 1615cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 1625cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov @Override 1635cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov protected FilterResults performFiltering(CharSequence constraint) { 1645cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov FilterResults results = new FilterResults(); 1655cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov if (!TextUtils.isEmpty(constraint)) { 1665cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov Uri uri = Email.CONTENT_FILTER_URI.buildUpon() 1675cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov .appendPath(constraint.toString()) 1685cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov .appendQueryParameter( 1695cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(mDirectoryId)) 1705cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov .build(); 1715cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov Cursor cursor = mContentResolver.query( 1725cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov uri, EmailQuery.PROJECTION, null, null, null); 1735cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov results.values = cursor; 1745cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 1755cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov return results; 1765cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 1775cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 1785cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov @Override 1795cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov protected void publishResults(CharSequence constraint, FilterResults results) { 1805cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov Cursor cursor = (Cursor) results.values; 1815cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov onPartitionLoadFinished(constraint, mPartitionIndex, cursor); 1825cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov results.count = getCount(); 1835cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 1845cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 1855cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 1865cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov protected final ContentResolver mContentResolver; 1875cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov private boolean mDirectoriesLoaded; 1885cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov private Account mAccount; 1895cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 1905cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public BaseEmailAddressAdapter(Context context) { 1915cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov super(context); 1925cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov mContentResolver = context.getContentResolver(); 1935cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 1945cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 1955cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov /** 1965cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * Set the account when known. Causes the search to prioritize contacts from 1975cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * that account. 1985cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov */ 1995cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public void setAccount(Account account) { 2005cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov mAccount = account; 2015cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 2025cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 2035cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov /** 2045cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * Override to create a view for line item in the autocomplete suggestion list UI. 2055cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov */ 2065cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov protected abstract View inflateItemView(ViewGroup parent); 2075cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 2085cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov /** 2095cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * Override to populate the autocomplete suggestion line item UI with data. 2105cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov */ 2115cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov protected abstract void bindView(View view, String directoryType, String directoryName, 2125cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov String displayName, String emailAddress); 2135cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 2145cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov /** 2155cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * Override to create a view for a "Searching directory" line item, which is 2165cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * displayed temporarily while the corresponding filter is running. 2175cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov */ 2185cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov protected abstract View inflateItemViewLoading(ViewGroup parent); 2195cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 2205cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov /** 2215cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * Override to populate the "Searching directory" line item UI with data. 2225cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov */ 2235cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov protected abstract void bindViewLoading(View view, String directoryType, String directoryName); 2245cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 2255cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov @Override 2265cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov protected int getItemViewType(int partitionIndex, int position) { 2275cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov DirectoryPartition partition = (DirectoryPartition)getPartition(partitionIndex); 2285cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov return partition.loading ? 1 : 0; 2295cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 2305cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 2315cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov @Override 2325cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov protected View newView(Context context, int partitionIndex, Cursor cursor, 2335cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov int position, ViewGroup parent) { 2345cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov DirectoryPartition partition = (DirectoryPartition)getPartition(partitionIndex); 2355cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov if (partition.loading) { 2365cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov return inflateItemViewLoading(parent); 2375cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } else { 2385cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov return inflateItemView(parent); 2395cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 2405cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 2415cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 2425cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov @Override 2435cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov protected void bindView(View v, int partition, Cursor cursor, int position) { 2445cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov DirectoryPartition directoryPartition = (DirectoryPartition)getPartition(partition); 2455cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov String directoryType = directoryPartition.directoryType; 2465cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov String directoryName = directoryPartition.displayName; 2475cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov if (directoryPartition.loading) { 2485cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov bindViewLoading(v, directoryType, directoryName); 2495cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } else { 2505cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov String displayName = cursor.getString(EmailQuery.NAME); 2515cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov String emailAddress = cursor.getString(EmailQuery.ADDRESS); 2525cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov bindView(v, directoryType, directoryName, displayName, emailAddress); 2535cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 2545cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 2555cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 2565cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov @Override 2575cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public boolean areAllItemsEnabled() { 2585cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov return false; 2595cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 2605cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 2615cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov @Override 2625cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov protected boolean isEnabled(int partitionIndex, int position) { 2635cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov // The "Searching..." item should not be selectable 2645cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov return !((DirectoryPartition)getPartition(partitionIndex)).loading; 2655cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 2665cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 2675cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov @Override 2685cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public Filter getFilter() { 2695cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov return new DefaultPartitionFilter(); 2705cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 2715cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 2725cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov /** 2735cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * Handles the result of the initial call, which brings back the list of 2745cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * directories as well as the search results for the local directories. 2755cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov */ 2765cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov protected void onDirectoryLoadFinished( 2775cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov CharSequence constraint, Cursor directoryCursor, Cursor defaultPartitionCursor) { 2785cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov if (directoryCursor != null) { 2795cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov PackageManager packageManager = getContext().getPackageManager(); 2805cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov DirectoryPartition preferredDirectory = null; 2815cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov List<DirectoryPartition> directories = new ArrayList<DirectoryPartition>(); 2825cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov while (directoryCursor.moveToNext()) { 2835cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov long id = directoryCursor.getLong(DirectoryListQuery.ID); 2845cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 2855cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov // Skip the local invisible directory, because the default directory 2865cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov // already includes all local results. 2875cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov if (id == Directory.LOCAL_INVISIBLE) { 2885cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov continue; 2895cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 2905cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 2915cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov DirectoryPartition partition = new DirectoryPartition(); 2925cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov partition.directoryId = id; 2935cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov partition.displayName = directoryCursor.getString(DirectoryListQuery.DISPLAY_NAME); 2945cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov partition.accountName = directoryCursor.getString(DirectoryListQuery.ACCOUNT_NAME); 2955cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov partition.accountType = directoryCursor.getString(DirectoryListQuery.ACCOUNT_TYPE); 2965cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov String packageName = directoryCursor.getString(DirectoryListQuery.PACKAGE_NAME); 2975cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov int resourceId = directoryCursor.getInt(DirectoryListQuery.TYPE_RESOURCE_ID); 2985cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov if (packageName != null && resourceId != 0) { 2995cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov try { 3005cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov Resources resources = 3015cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov packageManager.getResourcesForApplication(packageName); 3025cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov partition.directoryType = resources.getString(resourceId); 3035cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov if (partition.directoryType == null) { 3045cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov Log.e(TAG, "Cannot resolve directory name: " 3055cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov + resourceId + "@" + packageName); 3065cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 3075cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } catch (NameNotFoundException e) { 3085cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov Log.e(TAG, "Cannot resolve directory name: " 3095cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov + resourceId + "@" + packageName, e); 3105cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 3115cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 3125cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 3135cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov // If an account has been provided and we found a directory that 3145cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov // corresponds to that account, place that directory second, directly 3155cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov // underneath the local contacts. 3165cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov if (mAccount != null && mAccount.name.equals(partition.accountName) && 3175cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov mAccount.type.equals(partition.accountType)) { 3185cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov preferredDirectory = partition; 3195cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } else { 3205cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov directories.add(partition); 3215cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 3225cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 3235cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 3245cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov if (preferredDirectory != null) { 3255cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov directories.add(1, preferredDirectory); 3265cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 3275cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 3285cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov for (DirectoryPartition partition : directories) { 3295cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov addPartition(partition); 3305cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 3315cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 3325cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 3335cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov // The filter has loaded results for the default partition too. 3345cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov if (defaultPartitionCursor != null && getPartitionCount() > 0) { 3355cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov changeCursor(0, defaultPartitionCursor); 3365cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 3375cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 3385cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov // Start search in other directories 3395cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov int count = getPartitionCount(); 3405cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov // Note: skipping the default partition (index 0), which has already been loaded 3415cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov for (int i = 1; i < count; i++) { 3425cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov DirectoryPartition partition = (DirectoryPartition) getPartition(i); 3435cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov partition.constraint = constraint; 3445cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 3455cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov if (!partition.loading) { 3465cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov partition.loading = true; 3475cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov changeCursor(i, createLoadingCursor()); 3485cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 3495cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 3505cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov if (partition.filter == null) { 3515cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov partition.filter = new DirectoryPartitionFilter(i, partition.directoryId); 3525cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 3535cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov partition.filter.filter(constraint); 3545cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 3555cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 3565cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 3575cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov /** 3585cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov * Creates a dummy cursor to represent the "Searching directory..." item. 3595cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov */ 3605cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov private Cursor createLoadingCursor() { 3615cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov MatrixCursor cursor = new MatrixCursor(new String[]{SEARCHING_CURSOR_MARKER}); 3625cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov cursor.addRow(new Object[]{""}); 3635cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov return cursor; 3645cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 3655cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 3665cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov public void onPartitionLoadFinished( 3675cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov CharSequence constraint, int partitionIndex, Cursor cursor) { 3685cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov if (partitionIndex < getPartitionCount()) { 3695cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov DirectoryPartition partition = (DirectoryPartition) getPartition(partitionIndex); 3705cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov // Check if the received result matches the current constraint 3715cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov // If not - the user must have continued typing after the request 3725cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov // was issued 3735cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov if (TextUtils.equals(constraint, partition.constraint)) { 3745cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov partition.loading = false; 3755cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov changeCursor(partitionIndex, cursor); 3765cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } else { 3775cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov // We got the result for an unexpected query (the user is still typing) 3785cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov // Just ignore this result 3795cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov if (cursor != null) { 3805cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov cursor.close(); 3815cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 3825cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 3835cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } else if (cursor != null) { 3845cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov cursor.close(); 3855cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 3865cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 3875cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 3885cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov private final String makeDisplayString(Cursor cursor) { 3895cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov if (cursor.getColumnName(0).equals(SEARCHING_CURSOR_MARKER)) { 3905cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov return ""; 3915cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 3925cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov 3935cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov String name = cursor.getString(EmailQuery.NAME); 3945cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov String address = cursor.getString(EmailQuery.ADDRESS); 3955cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov return new Rfc822Token(name, address, null).toString(); 3965cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov } 3975cc774535d73c09b6788b63ecc728e60da09cfa9Dmitri Plotnikov} 398