diff options
Diffstat (limited to 'src/com/android/contacts/common/list/ContactListAdapter.java')
-rw-r--r-- | src/com/android/contacts/common/list/ContactListAdapter.java | 362 |
1 files changed, 362 insertions, 0 deletions
diff --git a/src/com/android/contacts/common/list/ContactListAdapter.java b/src/com/android/contacts/common/list/ContactListAdapter.java new file mode 100644 index 00000000..1be48c42 --- /dev/null +++ b/src/com/android/contacts/common/list/ContactListAdapter.java @@ -0,0 +1,362 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.contacts.common.list; + +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; +import android.provider.ContactsContract; +import android.provider.ContactsContract.ContactCounts; +import android.provider.ContactsContract.Contacts; +import android.provider.ContactsContract.Directory; +import android.provider.ContactsContract.SearchSnippetColumns; +import android.text.TextUtils; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ListView; + +import com.android.contacts.common.R; + +/** + * A cursor adapter for the {@link ContactsContract.Contacts#CONTENT_TYPE} content type. + * Also includes support for including the {@link ContactsContract.Profile} record in the + * list. + */ +public abstract class ContactListAdapter extends ContactEntryListAdapter { + + protected static class ContactQuery { + private static final String[] CONTACT_PROJECTION_PRIMARY = new String[] { + Contacts._ID, // 0 + Contacts.DISPLAY_NAME_PRIMARY, // 1 + Contacts.CONTACT_PRESENCE, // 2 + Contacts.CONTACT_STATUS, // 3 + Contacts.PHOTO_ID, // 4 + Contacts.PHOTO_THUMBNAIL_URI, // 5 + Contacts.LOOKUP_KEY, // 6 + Contacts.IS_USER_PROFILE, // 7 + }; + + private static final String[] CONTACT_PROJECTION_ALTERNATIVE = new String[] { + Contacts._ID, // 0 + Contacts.DISPLAY_NAME_ALTERNATIVE, // 1 + Contacts.CONTACT_PRESENCE, // 2 + Contacts.CONTACT_STATUS, // 3 + Contacts.PHOTO_ID, // 4 + Contacts.PHOTO_THUMBNAIL_URI, // 5 + Contacts.LOOKUP_KEY, // 6 + Contacts.IS_USER_PROFILE, // 7 + }; + + private static final String[] FILTER_PROJECTION_PRIMARY = new String[] { + Contacts._ID, // 0 + Contacts.DISPLAY_NAME_PRIMARY, // 1 + Contacts.CONTACT_PRESENCE, // 2 + Contacts.CONTACT_STATUS, // 3 + Contacts.PHOTO_ID, // 4 + Contacts.PHOTO_THUMBNAIL_URI, // 5 + Contacts.LOOKUP_KEY, // 6 + Contacts.IS_USER_PROFILE, // 7 + SearchSnippetColumns.SNIPPET, // 8 + }; + + private static final String[] FILTER_PROJECTION_ALTERNATIVE = new String[] { + Contacts._ID, // 0 + Contacts.DISPLAY_NAME_ALTERNATIVE, // 1 + Contacts.CONTACT_PRESENCE, // 2 + Contacts.CONTACT_STATUS, // 3 + Contacts.PHOTO_ID, // 4 + Contacts.PHOTO_THUMBNAIL_URI, // 5 + Contacts.LOOKUP_KEY, // 6 + Contacts.IS_USER_PROFILE, // 7 + SearchSnippetColumns.SNIPPET, // 8 + }; + + public static final int CONTACT_ID = 0; + public static final int CONTACT_DISPLAY_NAME = 1; + public static final int CONTACT_PRESENCE_STATUS = 2; + public static final int CONTACT_CONTACT_STATUS = 3; + public static final int CONTACT_PHOTO_ID = 4; + public static final int CONTACT_PHOTO_URI = 5; + public static final int CONTACT_LOOKUP_KEY = 6; + public static final int CONTACT_IS_USER_PROFILE = 7; + public static final int CONTACT_SNIPPET = 8; + } + + private CharSequence mUnknownNameText; + + private long mSelectedContactDirectoryId; + private String mSelectedContactLookupKey; + private long mSelectedContactId; + + public ContactListAdapter(Context context) { + super(context); + + mUnknownNameText = context.getText(R.string.missing_name); + } + + public CharSequence getUnknownNameText() { + return mUnknownNameText; + } + + public long getSelectedContactDirectoryId() { + return mSelectedContactDirectoryId; + } + + public String getSelectedContactLookupKey() { + return mSelectedContactLookupKey; + } + + public long getSelectedContactId() { + return mSelectedContactId; + } + + public void setSelectedContact(long selectedDirectoryId, String lookupKey, long contactId) { + mSelectedContactDirectoryId = selectedDirectoryId; + mSelectedContactLookupKey = lookupKey; + mSelectedContactId = contactId; + } + + protected static Uri buildSectionIndexerUri(Uri uri) { + return uri.buildUpon() + .appendQueryParameter(ContactCounts.ADDRESS_BOOK_INDEX_EXTRAS, "true").build(); + } + + @Override + public String getContactDisplayName(int position) { + return ((Cursor) getItem(position)).getString(ContactQuery.CONTACT_DISPLAY_NAME); + } + + /** + * Builds the {@link Contacts#CONTENT_LOOKUP_URI} for the given + * {@link ListView} position. + */ + public Uri getContactUri(int position) { + int partitionIndex = getPartitionForPosition(position); + Cursor item = (Cursor)getItem(position); + return item != null ? getContactUri(partitionIndex, item) : null; + } + + public Uri getContactUri(int partitionIndex, Cursor cursor) { + long contactId = cursor.getLong(ContactQuery.CONTACT_ID); + String lookupKey = cursor.getString(ContactQuery.CONTACT_LOOKUP_KEY); + Uri uri = Contacts.getLookupUri(contactId, lookupKey); + long directoryId = ((DirectoryPartition)getPartition(partitionIndex)).getDirectoryId(); + if (directoryId != Directory.DEFAULT) { + uri = uri.buildUpon().appendQueryParameter( + ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(directoryId)).build(); + } + return uri; + } + + /** + * Returns true if the specified contact is selected in the list. For a + * contact to be shown as selected, we need both the directory and and the + * lookup key to be the same. We are paying no attention to the contactId, + * because it is volatile, especially in the case of directories. + */ + public boolean isSelectedContact(int partitionIndex, Cursor cursor) { + long directoryId = ((DirectoryPartition)getPartition(partitionIndex)).getDirectoryId(); + if (getSelectedContactDirectoryId() != directoryId) { + return false; + } + String lookupKey = getSelectedContactLookupKey(); + if (lookupKey != null && TextUtils.equals(lookupKey, + cursor.getString(ContactQuery.CONTACT_LOOKUP_KEY))) { + return true; + } + + return directoryId != Directory.DEFAULT && directoryId != Directory.LOCAL_INVISIBLE + && getSelectedContactId() == cursor.getLong(ContactQuery.CONTACT_ID); + } + + @Override + protected View newView(Context context, int partition, Cursor cursor, int position, + ViewGroup parent) { + ContactListItemView view = new ContactListItemView(context, null); + view.setUnknownNameText(mUnknownNameText); + view.setQuickContactEnabled(isQuickContactEnabled()); + view.setActivatedStateSupported(isSelectionVisible()); + return view; + } + + protected void bindSectionHeaderAndDivider(ContactListItemView view, int position, + Cursor cursor) { + if (isSectionHeaderDisplayEnabled()) { + Placement placement = getItemPlacementInSection(position); + + // First position, set the contacts number string + if (position == 0 && cursor.getInt(ContactQuery.CONTACT_IS_USER_PROFILE) == 1) { + view.setCountView(getContactsCount()); + } else { + view.setCountView(null); + } + view.setSectionHeader(placement.sectionHeader); + view.setDividerVisible(!placement.lastInSection); + } else { + view.setSectionHeader(null); + view.setDividerVisible(true); + view.setCountView(null); + } + } + + protected void bindPhoto(final ContactListItemView view, int partitionIndex, Cursor cursor) { + if (!isPhotoSupported(partitionIndex)) { + view.removePhotoView(); + return; + } + + // Set the photo, if available + long photoId = 0; + if (!cursor.isNull(ContactQuery.CONTACT_PHOTO_ID)) { + photoId = cursor.getLong(ContactQuery.CONTACT_PHOTO_ID); + } + + if (photoId != 0) { + getPhotoLoader().loadThumbnail(view.getPhotoView(), photoId, false); + } else { + final String photoUriString = cursor.getString(ContactQuery.CONTACT_PHOTO_URI); + final Uri photoUri = photoUriString == null ? null : Uri.parse(photoUriString); + getPhotoLoader().loadDirectoryPhoto(view.getPhotoView(), photoUri, false); + } + } + + protected void bindName(final ContactListItemView view, Cursor cursor) { + view.showDisplayName( + cursor, ContactQuery.CONTACT_DISPLAY_NAME, getContactNameDisplayOrder()); + // Note: we don't show phonetic any more (See issue 5265330) + } + + protected void bindPresenceAndStatusMessage(final ContactListItemView view, Cursor cursor) { + view.showPresenceAndStatusMessage(cursor, ContactQuery.CONTACT_PRESENCE_STATUS, + ContactQuery.CONTACT_CONTACT_STATUS); + } + + protected void bindSearchSnippet(final ContactListItemView view, Cursor cursor) { + view.showSnippet(cursor, ContactQuery.CONTACT_SNIPPET); + } + + public int getSelectedContactPosition() { + if (mSelectedContactLookupKey == null && mSelectedContactId == 0) { + return -1; + } + + Cursor cursor = null; + int partitionIndex = -1; + int partitionCount = getPartitionCount(); + for (int i = 0; i < partitionCount; i++) { + DirectoryPartition partition = (DirectoryPartition) getPartition(i); + if (partition.getDirectoryId() == mSelectedContactDirectoryId) { + partitionIndex = i; + break; + } + } + if (partitionIndex == -1) { + return -1; + } + + cursor = getCursor(partitionIndex); + if (cursor == null) { + return -1; + } + + cursor.moveToPosition(-1); // Reset cursor + int offset = -1; + while (cursor.moveToNext()) { + if (mSelectedContactLookupKey != null) { + String lookupKey = cursor.getString(ContactQuery.CONTACT_LOOKUP_KEY); + if (mSelectedContactLookupKey.equals(lookupKey)) { + offset = cursor.getPosition(); + break; + } + } + if (mSelectedContactId != 0 && (mSelectedContactDirectoryId == Directory.DEFAULT + || mSelectedContactDirectoryId == Directory.LOCAL_INVISIBLE)) { + long contactId = cursor.getLong(ContactQuery.CONTACT_ID); + if (contactId == mSelectedContactId) { + offset = cursor.getPosition(); + break; + } + } + } + if (offset == -1) { + return -1; + } + + int position = getPositionForPartition(partitionIndex) + offset; + if (hasHeader(partitionIndex)) { + position++; + } + return position; + } + + public boolean hasValidSelection() { + return getSelectedContactPosition() != -1; + } + + public Uri getFirstContactUri() { + int partitionCount = getPartitionCount(); + for (int i = 0; i < partitionCount; i++) { + DirectoryPartition partition = (DirectoryPartition) getPartition(i); + if (partition.isLoading()) { + continue; + } + + Cursor cursor = getCursor(i); + if (cursor == null) { + continue; + } + + if (!cursor.moveToFirst()) { + continue; + } + + return getContactUri(i, cursor); + } + + return null; + } + + @Override + public void changeCursor(int partitionIndex, Cursor cursor) { + super.changeCursor(partitionIndex, cursor); + + // Check if a profile exists + if (cursor != null && cursor.getCount() > 0) { + cursor.moveToFirst(); + setProfileExists(cursor.getInt(ContactQuery.CONTACT_IS_USER_PROFILE) == 1); + } + } + + /** + * @return Projection useful for children. + */ + protected final String[] getProjection(boolean forSearch) { + final int sortOrder = getContactNameDisplayOrder(); + if (forSearch) { + if (sortOrder == ContactsContract.Preferences.DISPLAY_ORDER_PRIMARY) { + return ContactQuery.FILTER_PROJECTION_PRIMARY; + } else { + return ContactQuery.FILTER_PROJECTION_ALTERNATIVE; + } + } else { + if (sortOrder == ContactsContract.Preferences.DISPLAY_ORDER_PRIMARY) { + return ContactQuery.CONTACT_PROJECTION_PRIMARY; + } else { + return ContactQuery.CONTACT_PROJECTION_ALTERNATIVE; + } + } + } +} |