summaryrefslogtreecommitdiffstats
path: root/src/com/android/contacts/common/list/PhoneNumberListAdapter.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/contacts/common/list/PhoneNumberListAdapter.java')
-rw-r--r--src/com/android/contacts/common/list/PhoneNumberListAdapter.java334
1 files changed, 260 insertions, 74 deletions
diff --git a/src/com/android/contacts/common/list/PhoneNumberListAdapter.java b/src/com/android/contacts/common/list/PhoneNumberListAdapter.java
index c62b6b1f..ad370353 100644
--- a/src/com/android/contacts/common/list/PhoneNumberListAdapter.java
+++ b/src/com/android/contacts/common/list/PhoneNumberListAdapter.java
@@ -29,12 +29,15 @@ import android.provider.ContactsContract.ContactCounts;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.Directory;
-import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
+import com.android.contacts.common.GeoUtil;
import com.android.contacts.common.R;
+import com.android.contacts.common.extensions.ExtendedPhoneDirectoriesManager;
+import com.android.contacts.common.extensions.ExtensionsFactory;
+import com.android.contacts.common.util.Constants;
import java.util.ArrayList;
import java.util.List;
@@ -48,10 +51,19 @@ import java.util.List;
* API instead of {@link Phone}.
*/
public class PhoneNumberListAdapter extends ContactEntryListAdapter {
+
private static final String TAG = PhoneNumberListAdapter.class.getSimpleName();
- protected static class PhoneQuery {
- private static final String[] PROJECTION_PRIMARY = new String[] {
+ // A list of extended directories to add to the directories from the database
+ private final List<DirectoryPartition> mExtendedDirectories;
+
+ // Extended directories will have ID's that are higher than any of the id's from the database.
+ // Thi sis so that we can identify them and set them up properly. If no extended directories
+ // exist, this will be Long.MAX_VALUE
+ private long mFirstExtendedDirectoryId = Long.MAX_VALUE;
+
+ public static class PhoneQuery {
+ public static final String[] PROJECTION_PRIMARY = new String[] {
Phone._ID, // 0
Phone.TYPE, // 1
Phone.LABEL, // 2
@@ -60,9 +72,10 @@ public class PhoneNumberListAdapter extends ContactEntryListAdapter {
Phone.LOOKUP_KEY, // 5
Phone.PHOTO_ID, // 6
Phone.DISPLAY_NAME_PRIMARY, // 7
+ Phone.PHOTO_THUMBNAIL_URI, // 8
};
- private static final String[] PROJECTION_ALTERNATIVE = new String[] {
+ public static final String[] PROJECTION_ALTERNATIVE = new String[] {
Phone._ID, // 0
Phone.TYPE, // 1
Phone.LABEL, // 2
@@ -71,16 +84,18 @@ public class PhoneNumberListAdapter extends ContactEntryListAdapter {
Phone.LOOKUP_KEY, // 5
Phone.PHOTO_ID, // 6
Phone.DISPLAY_NAME_ALTERNATIVE, // 7
+ Phone.PHOTO_THUMBNAIL_URI, // 8
};
- public static final int PHONE_ID = 0;
- public static final int PHONE_TYPE = 1;
- public static final int PHONE_LABEL = 2;
- public static final int PHONE_NUMBER = 3;
- public static final int PHONE_CONTACT_ID = 4;
- public static final int PHONE_LOOKUP_KEY = 5;
- public static final int PHONE_PHOTO_ID = 6;
- public static final int PHONE_DISPLAY_NAME = 7;
+ public static final int PHONE_ID = 0;
+ public static final int PHONE_TYPE = 1;
+ public static final int PHONE_LABEL = 2;
+ public static final int PHONE_NUMBER = 3;
+ public static final int CONTACT_ID = 4;
+ public static final int LOOKUP_KEY = 5;
+ public static final int PHOTO_ID = 6;
+ public static final int DISPLAY_NAME = 7;
+ public static final int PHOTO_URI = 8;
}
private final CharSequence mUnknownNameText;
@@ -93,6 +108,15 @@ public class PhoneNumberListAdapter extends ContactEntryListAdapter {
super(context);
setDefaultFilterHeaderText(R.string.list_filter_phones);
mUnknownNameText = context.getText(android.R.string.unknownName);
+
+ final ExtendedPhoneDirectoriesManager manager
+ = ExtensionsFactory.getExtendedPhoneDirectoriesManager();
+ if (manager != null) {
+ mExtendedDirectories = manager.getExtendedDirectories(mContext);
+ } else {
+ // Empty list to avoid sticky NPE's
+ mExtendedDirectories = new ArrayList<DirectoryPartition>();
+ }
}
protected CharSequence getUnknownNameText() {
@@ -101,52 +125,82 @@ public class PhoneNumberListAdapter extends ContactEntryListAdapter {
@Override
public void configureLoader(CursorLoader loader, long directoryId) {
- if (directoryId != Directory.DEFAULT) {
- Log.w(TAG, "PhoneNumberListAdapter is not ready for non-default directory ID ("
- + "directoryId: " + directoryId + ")");
+ String query = getQueryString();
+ if (query == null) {
+ query = "";
}
-
- final Builder builder;
- if (isSearchMode()) {
- final Uri baseUri =
- mUseCallableUri ? Callable.CONTENT_FILTER_URI : Phone.CONTENT_FILTER_URI;
- builder = baseUri.buildUpon();
- final String query = getQueryString();
- if (TextUtils.isEmpty(query)) {
- builder.appendPath("");
- } else {
- builder.appendPath(query); // Builder will encode the query
+ if (isExtendedDirectory(directoryId)) {
+ final DirectoryPartition directory = getExtendedDirectoryFromId(directoryId);
+ final String contentUri = directory.getContentUri();
+ if (contentUri == null) {
+ throw new IllegalStateException("Extended directory must have a content URL: "
+ + directory);
}
- builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
- String.valueOf(directoryId));
+ final Builder builder = Uri.parse(contentUri).buildUpon();
+ builder.appendPath(query);
+ builder.appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY,
+ String.valueOf(getDirectoryResultLimit(directory)));
+ loader.setUri(builder.build());
+ loader.setProjection(PhoneQuery.PROJECTION_PRIMARY);
} else {
- final Uri baseUri = mUseCallableUri ? Callable.CONTENT_URI : Phone.CONTENT_URI;
- builder = baseUri.buildUpon().appendQueryParameter(
- ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(Directory.DEFAULT));
- if (isSectionHeaderDisplayEnabled()) {
- builder.appendQueryParameter(ContactCounts.ADDRESS_BOOK_INDEX_EXTRAS, "true");
+ final boolean isRemoteDirectoryQuery = isRemoteDirectory(directoryId);
+ final Builder builder;
+ if (isSearchMode()) {
+ final Uri baseUri;
+ if (isRemoteDirectoryQuery) {
+ baseUri = Phone.CONTENT_FILTER_URI;
+ } else if (mUseCallableUri) {
+ baseUri = Callable.CONTENT_FILTER_URI;
+ } else {
+ baseUri = Phone.CONTENT_FILTER_URI;
+ }
+ builder = baseUri.buildUpon();
+ builder.appendPath(query); // Builder will encode the query
+ builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+ String.valueOf(directoryId));
+ if (isRemoteDirectoryQuery) {
+ builder.appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY,
+ String.valueOf(getDirectoryResultLimit(getDirectoryById(directoryId))));
+ }
+ } else {
+ final Uri baseUri = mUseCallableUri ? Callable.CONTENT_URI : Phone.CONTENT_URI;
+ builder = baseUri.buildUpon().appendQueryParameter(
+ ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(Directory.DEFAULT));
+ if (isSectionHeaderDisplayEnabled()) {
+ builder.appendQueryParameter(ContactCounts.ADDRESS_BOOK_INDEX_EXTRAS, "true");
+ }
+ applyFilter(loader, builder, directoryId, getFilter());
}
- applyFilter(loader, builder, directoryId, getFilter());
- }
- // Remove duplicates when it is possible.
- builder.appendQueryParameter(ContactsContract.REMOVE_DUPLICATE_ENTRIES, "true");
- loader.setUri(builder.build());
+ // Remove duplicates when it is possible.
+ builder.appendQueryParameter(ContactsContract.REMOVE_DUPLICATE_ENTRIES, "true");
+ loader.setUri(builder.build());
- // TODO a projection that includes the search snippet
- if (getContactNameDisplayOrder() == ContactsContract.Preferences.DISPLAY_ORDER_PRIMARY) {
- loader.setProjection(PhoneQuery.PROJECTION_PRIMARY);
- } else {
- loader.setProjection(PhoneQuery.PROJECTION_ALTERNATIVE);
- }
+ // TODO a projection that includes the search snippet
+ if (getContactNameDisplayOrder() ==
+ ContactsContract.Preferences.DISPLAY_ORDER_PRIMARY) {
+ loader.setProjection(PhoneQuery.PROJECTION_PRIMARY);
+ } else {
+ loader.setProjection(PhoneQuery.PROJECTION_ALTERNATIVE);
+ }
- if (getSortOrder() == ContactsContract.Preferences.SORT_ORDER_PRIMARY) {
- loader.setSortOrder(Phone.SORT_KEY_PRIMARY);
- } else {
- loader.setSortOrder(Phone.SORT_KEY_ALTERNATIVE);
+ if (getSortOrder() == ContactsContract.Preferences.SORT_ORDER_PRIMARY) {
+ loader.setSortOrder(Phone.SORT_KEY_PRIMARY);
+ } else {
+ loader.setSortOrder(Phone.SORT_KEY_ALTERNATIVE);
+ }
}
}
+ protected boolean isExtendedDirectory(long directoryId) {
+ return directoryId >= mFirstExtendedDirectoryId;
+ }
+
+ private DirectoryPartition getExtendedDirectoryFromId(long directoryId) {
+ final int directoryIndex = (int) (directoryId - mFirstExtendedDirectoryId);
+ return mExtendedDirectories.get(directoryIndex);
+ }
+
/**
* Configure {@code loader} and {@code uriBuilder} according to {@code directoryId} and {@code
* filter}.
@@ -188,7 +242,12 @@ public class PhoneNumberListAdapter extends ContactEntryListAdapter {
@Override
public String getContactDisplayName(int position) {
- return ((Cursor) getItem(position)).getString(PhoneQuery.PHONE_DISPLAY_NAME);
+ return ((Cursor) getItem(position)).getString(PhoneQuery.DISPLAY_NAME);
+ }
+
+ public String getPhoneNumber(int position) {
+ final Cursor item = (Cursor)getItem(position);
+ return item != null ? item.getString(PhoneQuery.PHONE_NUMBER) : null;
}
/**
@@ -197,14 +256,19 @@ public class PhoneNumberListAdapter extends ContactEntryListAdapter {
* @return Uri for the data. may be null if the cursor is not ready.
*/
public Uri getDataUri(int position) {
- Cursor cursor = ((Cursor)getItem(position));
- if (cursor != null) {
- long id = cursor.getLong(PhoneQuery.PHONE_ID);
- return ContentUris.withAppendedId(Data.CONTENT_URI, id);
- } else {
- Log.w(TAG, "Cursor was null in getDataUri() call. Returning null instead.");
- return null;
+ final int partitionIndex = getPartitionForPosition(position);
+ final Cursor item = (Cursor)getItem(position);
+ return item != null ? getDataUri(partitionIndex, item) : null;
+ }
+
+ public Uri getDataUri(int partitionIndex, Cursor cursor) {
+ final long directoryId =
+ ((DirectoryPartition)getPartition(partitionIndex)).getDirectoryId();
+ if (!isRemoteDirectory(directoryId)) {
+ final long phoneId = cursor.getLong(PhoneQuery.PHONE_ID);
+ return ContentUris.withAppendedId(Data.CONTENT_URI, phoneId);
}
+ return null;
}
@Override
@@ -217,11 +281,35 @@ public class PhoneNumberListAdapter extends ContactEntryListAdapter {
return view;
}
+ protected void setHighlight(ContactListItemView view, Cursor cursor) {
+ view.setHighlightedPrefix(isSearchMode() ? getUpperCaseQueryString() : null);
+ }
+
+ // Override default, which would return number of phone numbers, so we
+ // instead return number of contacts.
+ @Override
+ protected int getResultCount(Cursor cursor) {
+ if (cursor == null) {
+ return 0;
+ }
+ cursor.moveToPosition(-1);
+ long curContactId = -1;
+ int numContacts = 0;
+ while(cursor.moveToNext()) {
+ final long contactId = cursor.getLong(PhoneQuery.CONTACT_ID);
+ if (contactId != curContactId) {
+ curContactId = contactId;
+ ++numContacts;
+ }
+ }
+ return numContacts;
+ }
+
@Override
protected void bindView(View itemView, int partition, Cursor cursor, int position) {
ContactListItemView view = (ContactListItemView)itemView;
- view.setHighlightedPrefix(isSearchMode() ? getUpperCaseQueryString() : null);
+ setHighlight(view, cursor);
// Look at elements before and after this position, checking if contact IDs are same.
// If they have one same contact ID, it means they can be grouped.
@@ -231,16 +319,16 @@ public class PhoneNumberListAdapter extends ContactEntryListAdapter {
cursor.moveToPosition(position);
boolean isFirstEntry = true;
boolean showBottomDivider = true;
- final long currentContactId = cursor.getLong(PhoneQuery.PHONE_CONTACT_ID);
+ final long currentContactId = cursor.getLong(PhoneQuery.CONTACT_ID);
if (cursor.moveToPrevious() && !cursor.isBeforeFirst()) {
- final long previousContactId = cursor.getLong(PhoneQuery.PHONE_CONTACT_ID);
+ final long previousContactId = cursor.getLong(PhoneQuery.CONTACT_ID);
if (currentContactId == previousContactId) {
isFirstEntry = false;
}
}
cursor.moveToPosition(position);
if (cursor.moveToNext() && !cursor.isAfterLast()) {
- final long nextContactId = cursor.getLong(PhoneQuery.PHONE_CONTACT_ID);
+ final long nextContactId = cursor.getLong(PhoneQuery.CONTACT_ID);
if (currentContactId == nextContactId) {
// The following entry should be in the same group, which means we don't want a
// divider between them.
@@ -255,25 +343,28 @@ public class PhoneNumberListAdapter extends ContactEntryListAdapter {
if (isFirstEntry) {
bindName(view, cursor);
if (isQuickContactEnabled()) {
- // No need for photo uri here, because we can not have directory results. If we
- // ever do, we need to add photo uri to the query
- bindQuickContact(view, partition, cursor, PhoneQuery.PHONE_PHOTO_ID, -1,
- PhoneQuery.PHONE_CONTACT_ID, PhoneQuery.PHONE_LOOKUP_KEY);
+ bindQuickContact(view, partition, cursor, PhoneQuery.PHOTO_ID,
+ PhoneQuery.PHOTO_URI, PhoneQuery.CONTACT_ID,
+ PhoneQuery.LOOKUP_KEY);
} else {
- bindPhoto(view, cursor);
+ if (getDisplayPhotos()) {
+ bindPhoto(view, partition, cursor);
+ }
}
} else {
unbindName(view);
view.removePhotoView(true, false);
}
- bindPhoneNumber(view, cursor);
+
+ final DirectoryPartition directory = (DirectoryPartition) getPartition(partition);
+ bindPhoneNumber(view, cursor, directory.isDisplayNumber());
view.setDividerVisible(showBottomDivider);
}
- protected void bindPhoneNumber(ContactListItemView view, Cursor cursor) {
+ protected void bindPhoneNumber(ContactListItemView view, Cursor cursor, boolean displayNumber) {
CharSequence label = null;
- if (!cursor.isNull(PhoneQuery.PHONE_TYPE)) {
+ if (displayNumber && !cursor.isNull(PhoneQuery.PHONE_TYPE)) {
final int type = cursor.getInt(PhoneQuery.PHONE_TYPE);
final String customLabel = cursor.getString(PhoneQuery.PHONE_LABEL);
@@ -281,7 +372,20 @@ public class PhoneNumberListAdapter extends ContactEntryListAdapter {
label = Phone.getTypeLabel(getContext().getResources(), type, customLabel);
}
view.setLabel(label);
- view.showData(cursor, PhoneQuery.PHONE_NUMBER);
+ final String text;
+ if (displayNumber) {
+ text = cursor.getString(PhoneQuery.PHONE_NUMBER);
+ } else {
+ // Display phone label. If that's null, display geocoded location for the number
+ final String phoneLabel = cursor.getString(PhoneQuery.PHONE_LABEL);
+ if (phoneLabel != null) {
+ text = phoneLabel;
+ } else {
+ final String phoneNumber = cursor.getString(PhoneQuery.PHONE_NUMBER);
+ text = GeoUtil.getGeocodedLocationFor(mContext, phoneNumber);
+ }
+ }
+ view.setPhoneNumber(text);
}
protected void bindSectionHeaderAndDivider(final ContactListItemView view, int position) {
@@ -296,7 +400,7 @@ public class PhoneNumberListAdapter extends ContactEntryListAdapter {
}
protected void bindName(final ContactListItemView view, Cursor cursor) {
- view.showDisplayName(cursor, PhoneQuery.PHONE_DISPLAY_NAME, getContactNameDisplayOrder());
+ view.showDisplayName(cursor, PhoneQuery.DISPLAY_NAME, getContactNameDisplayOrder());
// Note: we don't show phonetic names any more (see issue 5265330)
}
@@ -304,13 +408,24 @@ public class PhoneNumberListAdapter extends ContactEntryListAdapter {
view.hideDisplayName();
}
- protected void bindPhoto(final ContactListItemView view, Cursor cursor) {
+ protected void bindPhoto(final ContactListItemView view, int partitionIndex, Cursor cursor) {
+ if (!isPhotoSupported(partitionIndex)) {
+ view.removePhotoView();
+ return;
+ }
+
long photoId = 0;
- if (!cursor.isNull(PhoneQuery.PHONE_PHOTO_ID)) {
- photoId = cursor.getLong(PhoneQuery.PHONE_PHOTO_ID);
+ if (!cursor.isNull(PhoneQuery.PHOTO_ID)) {
+ photoId = cursor.getLong(PhoneQuery.PHOTO_ID);
}
- getPhotoLoader().loadThumbnail(view.getPhotoView(), photoId, false);
+ if (photoId != 0) {
+ getPhotoLoader().loadThumbnail(view.getPhotoView(), photoId, false);
+ } else {
+ final String photoUriString = cursor.getString(PhoneQuery.PHOTO_URI);
+ final Uri photoUri = photoUriString == null ? null : Uri.parse(photoUriString);
+ getPhotoLoader().loadDirectoryPhoto(view.getPhotoView(), photoUri, false);
+ }
}
public void setPhotoPosition(ContactListItemView.PhotoPosition photoPosition) {
@@ -328,4 +443,75 @@ public class PhoneNumberListAdapter extends ContactEntryListAdapter {
public boolean usesCallableUri() {
return mUseCallableUri;
}
+
+ /**
+ * Override base implementation to inject extended directories between local & remote
+ * directories. This is done in the following steps:
+ * 1. Call base implementation to add directories from the cursor.
+ * 2. Iterate all base directories and establish the following information:
+ * a. The highest directory id so that we can assign unused id's to the extended directories.
+ * b. The index of the last non-remote directory. This is where we will insert extended
+ * directories.
+ * 3. Iterate the extended directories and for each one, assign an ID and insert it in the
+ * proper location.
+ */
+ @Override
+ public void changeDirectories(Cursor cursor) {
+ super.changeDirectories(cursor);
+ if (getDirectorySearchMode() == DirectoryListLoader.SEARCH_MODE_NONE) {
+ return;
+ }
+ final int numExtendedDirectories = mExtendedDirectories.size();
+ if (getPartitionCount() == cursor.getCount() + numExtendedDirectories) {
+ // already added all directories;
+ return;
+ }
+ //
+ mFirstExtendedDirectoryId = Long.MAX_VALUE;
+ if (numExtendedDirectories > 0) {
+ // The Directory.LOCAL_INVISIBLE is not in the cursor but we can't reuse it's
+ // "special" ID.
+ long maxId = Directory.LOCAL_INVISIBLE;
+ int insertIndex = 0;
+ for (int i = 0, n = getPartitionCount(); i < n; i++) {
+ final DirectoryPartition partition = (DirectoryPartition) getPartition(i);
+ final long id = partition.getDirectoryId();
+ if (id > maxId) {
+ maxId = id;
+ }
+ if (!isRemoteDirectory(id)) {
+ // assuming remote directories come after local, we will end up with the index
+ // where we should insert extended directories. This also works if there are no
+ // remote directories at all.
+ insertIndex = i + 1;
+ }
+ }
+ // Extended directories ID's cannot collide with base directories
+ mFirstExtendedDirectoryId = maxId + 1;
+ for (int i = 0; i < numExtendedDirectories; i++) {
+ final long id = mFirstExtendedDirectoryId + i;
+ final DirectoryPartition directory = mExtendedDirectories.get(i);
+ if (getPartitionByDirectoryId(id) == -1) {
+ addPartition(insertIndex, directory);
+ directory.setDirectoryId(id);
+ }
+ }
+ }
+ }
+
+ protected Uri getContactUri(int partitionIndex, Cursor cursor,
+ int contactIdColumn, int lookUpKeyColumn) {
+ final DirectoryPartition directory = (DirectoryPartition) getPartition(partitionIndex);
+ final long directoryId = directory.getDirectoryId();
+ if (!isExtendedDirectory(directoryId)) {
+ return super.getContactUri(partitionIndex, cursor, contactIdColumn, lookUpKeyColumn);
+ }
+ return Contacts.CONTENT_LOOKUP_URI.buildUpon()
+ .appendPath(Constants.LOOKUP_URI_ENCODED)
+ .appendQueryParameter(Directory.DISPLAY_NAME, directory.getLabel())
+ .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+ String.valueOf(directoryId))
+ .encodedFragment(cursor.getString(lookUpKeyColumn))
+ .build();
+ }
}