Merge "Allow overwriting "All Contacts" by a custom text (e.g. "All Friends") Bug:2116002"
diff --git a/src/com/android/contacts/list/ContactBrowseListContextMenuAdapter.java b/src/com/android/contacts/list/ContactBrowseListContextMenuAdapter.java
index 6ff3110..c9d4635 100644
--- a/src/com/android/contacts/list/ContactBrowseListContextMenuAdapter.java
+++ b/src/com/android/contacts/list/ContactBrowseListContextMenuAdapter.java
@@ -55,7 +55,7 @@
return;
}
- ContactEntryListAdapter adapter = mContactListFragment.getAdapter();
+ ContactListAdapter adapter = mContactListFragment.getAdapter();
adapter.moveToPosition(info.position);
// Setup the menu header
@@ -92,10 +92,10 @@
return false;
}
- ContactEntryListAdapter adapter = mContactListFragment.getAdapter();
+ ContactListAdapter adapter = mContactListFragment.getAdapter();
adapter.moveToPosition(info.position);
- final Uri contactUri = adapter.getContactUri();
+ final Uri contactUri = adapter.getContactUri();
switch (item.getItemId()) {
case MENU_ITEM_VIEW_CONTACT: {
mContactListFragment.viewContact(contactUri);
diff --git a/src/com/android/contacts/list/ContactBrowseListFragment.java b/src/com/android/contacts/list/ContactBrowseListFragment.java
index 97c7a1c..5ae425f 100644
--- a/src/com/android/contacts/list/ContactBrowseListFragment.java
+++ b/src/com/android/contacts/list/ContactBrowseListFragment.java
@@ -15,7 +15,6 @@
*/
package com.android.contacts.list;
-import com.android.contacts.ContactsListActivity;
import com.android.contacts.R;
import android.app.patterns.CursorLoader;
@@ -31,7 +30,7 @@
* Fragment containing a contact list used for browsing (as compared to
* picking a contact with one of the PICK intents).
*/
-public class ContactBrowseListFragment extends ContactEntryListFragment {
+public class ContactBrowseListFragment extends ContactEntryListFragment<ContactListAdapter> {
private OnContactBrowserActionListener mListener;
private boolean mEditMode;
@@ -55,10 +54,6 @@
mListener = listener;
}
- public boolean isSearchAllContactsItemPosition(int position) {
- return isSearchMode() && position == getAdapter().getCount() - 1;
- }
-
@Override
protected void onInitializeLoaders() {
startLoading(0, null);
@@ -66,40 +61,43 @@
@Override
protected void onLoadFinished(Loader<Cursor> loader, Cursor data) {
+ super.onLoadFinished(loader, data);
getAdapter().changeCursor(data);
}
@Override
protected void onItemClick(int position, long id) {
- if (isSearchAllContactsItemPosition(position)) {
+ ContactListAdapter adapter = getAdapter();
+ if (adapter.isSearchAllContactsItemPosition(position)) {
mListener.onSearchAllContactsAction((String)null);
} else if (isEditMode()) {
if (position == 0 && !isSearchMode() && isCreateContactEnabled()) {
mListener.onCreateNewContactAction();
} else {
- ContactEntryListAdapter adapter = getAdapter();
adapter.moveToPosition(position);
mListener.onEditContactAction(adapter.getContactUri());
}
} else {
- ContactEntryListAdapter adapter = getAdapter();
adapter.moveToPosition(position);
mListener.onViewContactAction(adapter.getContactUri());
}
}
@Override
- protected ContactEntryListAdapter createListAdapter() {
- ContactItemListAdapter adapter =
- new ContactItemListAdapter((ContactsListActivity)getActivity());
+ protected ContactListAdapter createListAdapter() {
+ ContactListAdapter adapter = new ContactListAdapter(getActivity());
adapter.setSectionHeaderDisplayEnabled(isSectionHeaderDisplayEnabled());
- adapter.setDisplayPhotos(isPhotoLoaderEnabled());
+
adapter.setSearchMode(isSearchMode());
adapter.setSearchResultsMode(isSearchResultsMode());
adapter.setQueryString(getQueryString());
+
adapter.setContactNameDisplayOrder(getContactNameDisplayOrder());
adapter.setSortOrder(getSortOrder());
+ adapter.setDisplayPhotos(true);
+ adapter.setQuickContactEnabled(true);
+
adapter.configureLoader(mLoader);
return adapter;
}
diff --git a/src/com/android/contacts/list/ContactEntryListAdapter.java b/src/com/android/contacts/list/ContactEntryListAdapter.java
index dbd6561..9da3704 100644
--- a/src/com/android/contacts/list/ContactEntryListAdapter.java
+++ b/src/com/android/contacts/list/ContactEntryListAdapter.java
@@ -16,20 +16,18 @@
package com.android.contacts.list;
import com.android.contacts.ContactPhotoLoader;
-import com.android.contacts.widget.TextWithHighlighting;
+import com.android.contacts.ContactsSectionIndexer;
+import com.android.contacts.R;
import com.android.contacts.widget.TextWithHighlightingFactory;
import android.app.patterns.CursorLoader;
import android.content.Context;
import android.database.Cursor;
-import android.database.DatabaseUtils;
-import android.net.Uri;
-import android.provider.ContactsContract;
+import android.os.Bundle;
import android.provider.ContactsContract.ContactCounts;
-import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.SearchSnippetColumns;
-import android.text.TextUtils;
-import android.widget.ListView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
/**
* Common base class for various contact-related lists, e.g. contact list, phone number list
@@ -37,47 +35,6 @@
*/
public abstract class ContactEntryListAdapter extends PinnedHeaderListAdapter {
- // TODO move to type-specific adapter
- static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
- Contacts._ID, // 0
- Contacts.DISPLAY_NAME_PRIMARY, // 1
- Contacts.DISPLAY_NAME_ALTERNATIVE, // 2
- Contacts.SORT_KEY_PRIMARY, // 3
- Contacts.STARRED, // 4
- Contacts.TIMES_CONTACTED, // 5
- Contacts.CONTACT_PRESENCE, // 6
- Contacts.PHOTO_ID, // 7
- Contacts.LOOKUP_KEY, // 8
- Contacts.PHONETIC_NAME, // 9
- Contacts.HAS_PHONE_NUMBER, // 10
- };
-
- // TODO move to type-specific adapter
- static final String[] CONTACTS_SUMMARY_FILTER_PROJECTION = new String[] {
- Contacts._ID, // 0
- Contacts.DISPLAY_NAME_PRIMARY, // 1
- Contacts.DISPLAY_NAME_ALTERNATIVE, // 2
- Contacts.SORT_KEY_PRIMARY, // 3
- Contacts.STARRED, // 4
- Contacts.TIMES_CONTACTED, // 5
- Contacts.CONTACT_PRESENCE, // 6
- Contacts.PHOTO_ID, // 7
- Contacts.LOOKUP_KEY, // 8
- Contacts.PHONETIC_NAME, // 9
- Contacts.HAS_PHONE_NUMBER, // 10
- SearchSnippetColumns.SNIPPET_MIMETYPE, // 11
- SearchSnippetColumns.SNIPPET_DATA1, // 12
- SearchSnippetColumns.SNIPPET_DATA4, // 13
- };
-
- // TODO move to a type-specific adapter
- public static final int SUMMARY_ID_COLUMN_INDEX = 0;
- public static final int SUMMARY_DISPLAY_NAME_PRIMARY_COLUMN_INDEX = 1;
- public static final int SUMMARY_DISPLAY_NAME_ALTERNATIVE_COLUMN_INDEX = 2;
- public static final int SUMMARY_STARRED_COLUMN_INDEX = 4;
- public static final int SUMMARY_LOOKUP_KEY_COLUMN_INDEX = 8;
- public static final int SUMMARY_HAS_PHONE_COLUMN_INDEX = 10;
-
/**
* The animation is used here to allocate animated name text views.
*/
@@ -86,9 +43,11 @@
private int mDisplayOrder;
private int mSortOrder;
private boolean mNameHighlightingEnabled;
- private ContactPhotoLoader mPhotoLoader;
private boolean mSectionHeaderDisplayEnabled;
+ private boolean mDisplayPhotos;
+ private ContactPhotoLoader mPhotoLoader;
+
private String mQueryString;
private boolean mSearchMode;
private boolean mSearchResultsMode;
@@ -97,6 +56,13 @@
super(context);
}
+ public Context getContext() {
+ return mContext;
+ }
+
+ public abstract String getContactDisplayName();
+ public abstract void configureLoader(CursorLoader loader);
+
public boolean isSearchMode() {
return mSearchMode;
}
@@ -121,10 +87,6 @@
mQueryString = queryString;
}
- public Context getContext() {
- return mContext;
- }
-
public boolean isSectionHeaderDisplayEnabled() {
return mSectionHeaderDisplayEnabled;
}
@@ -149,6 +111,7 @@
mSortOrder = sortOrder;
}
+ // TODO no highlighting in STREQUENT mode
public void setNameHighlightingEnabled(boolean flag) {
mNameHighlightingEnabled = flag;
}
@@ -161,8 +124,8 @@
mTextWithHighlightingFactory = factory;
}
- protected TextWithHighlighting createTextWithHighlighting() {
- return mTextWithHighlightingFactory.createTextWithHighlighting();
+ protected TextWithHighlightingFactory getTextWithHighlightingFactory() {
+ return mTextWithHighlightingFactory;
}
public void setPhotoLoader(ContactPhotoLoader photoLoader) {
@@ -173,37 +136,12 @@
return mPhotoLoader;
}
- public void configureLoader(CursorLoader loader) {
- Uri uri;
- if (isSearchMode() || isSearchResultsMode()) {
- String query = getQueryString();
- uri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,
- TextUtils.isEmpty(query) ? "" : Uri.encode(query));
- loader.setProjection(CONTACTS_SUMMARY_FILTER_PROJECTION);
- if (!isSearchResultsMode()) {
- loader.setSelection(Contacts.IN_VISIBLE_GROUP + "=1");
- }
- } else {
- uri = Contacts.CONTENT_URI;
- loader.setProjection(CONTACTS_SUMMARY_PROJECTION);
- loader.setSelection(Contacts.IN_VISIBLE_GROUP + "=1");
- }
-
- if (isSectionHeaderDisplayEnabled()) {
- uri = buildSectionIndexerUri(uri);
- }
-
- loader.setUri(uri);
- if (mSortOrder == ContactsContract.Preferences.SORT_ORDER_PRIMARY) {
- loader.setSortOrder(Contacts.SORT_KEY_PRIMARY);
- } else {
- loader.setSortOrder(Contacts.SORT_KEY_ALTERNATIVE);
- }
+ public boolean getDisplayPhotos() {
+ return mDisplayPhotos;
}
- private static Uri buildSectionIndexerUri(Uri uri) {
- return uri.buildUpon()
- .appendQueryParameter(ContactCounts.ADDRESS_BOOK_INDEX_EXTRAS, "true").build();
+ public void setDisplayPhotos(boolean displayPhotos) {
+ mDisplayPhotos = displayPhotos;
}
/*
@@ -215,39 +153,75 @@
super.onContentChanged();
}
+ @Override
+ public void changeCursor(Cursor cursor) {
+ super.changeCursor(cursor);
+
+ if (isSectionHeaderDisplayEnabled()) {
+ updateIndexer(cursor);
+ }
+ }
+
+ /**
+ * Updates the indexer, which is used to produce section headers.
+ */
+ private void updateIndexer(Cursor cursor) {
+ if (cursor == null) {
+ setIndexer(null);
+ return;
+ }
+
+ Bundle bundle = cursor.getExtras();
+ if (bundle.containsKey(ContactCounts.EXTRA_ADDRESS_BOOK_INDEX_TITLES)) {
+ String sections[] =
+ bundle.getStringArray(ContactCounts.EXTRA_ADDRESS_BOOK_INDEX_TITLES);
+ int counts[] = bundle.getIntArray(ContactCounts.EXTRA_ADDRESS_BOOK_INDEX_COUNTS);
+ setIndexer(new ContactsSectionIndexer(sections, counts));
+ } else {
+ setIndexer(null);
+ }
+ }
+
public void moveToPosition(int position) {
// For side-effect
getItem(position);
}
- public boolean getHasPhoneNumber() {
- return getCursor().getInt(SUMMARY_HAS_PHONE_COLUMN_INDEX) != 0;
- }
-
- public boolean isContactStarred() {
- return getCursor().getInt(SUMMARY_STARRED_COLUMN_INDEX) != 0;
- }
-
- public String getContactDisplayName() {
- return getCursor().getString(getSummaryDisplayNameColumnIndex());
- }
-
- public int getSummaryDisplayNameColumnIndex() {
- if (mDisplayOrder == ContactsContract.Preferences.DISPLAY_ORDER_PRIMARY) {
- return SUMMARY_DISPLAY_NAME_PRIMARY_COLUMN_INDEX;
- } else {
- return SUMMARY_DISPLAY_NAME_ALTERNATIVE_COLUMN_INDEX;
+ @Override
+ public int getCount() {
+ if (!mDataValid) {
+ return 0;
}
+
+ int count = super.getCount();
+
+ if (mSearchMode) {
+ // Last element in the list is "Search all contacts"
+ count++;
+ }
+
+ return count;
}
- /**
- * Builds the {@link Contacts#CONTENT_LOOKUP_URI} for the given
- * {@link ListView} position.
- */
- public Uri getContactUri() {
- Cursor cursor = getCursor();
- long contactId = cursor.getLong(SUMMARY_ID_COLUMN_INDEX);
- String lookupKey = cursor.getString(SUMMARY_LOOKUP_KEY_COLUMN_INDEX);
- return Contacts.getLookupUri(contactId, lookupKey);
+ public boolean isSearchAllContactsItemPosition(int position) {
+ return isSearchMode() && position == getCount() - 1;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ if (isSearchAllContactsItemPosition(position)) {
+ return IGNORE_ITEM_VIEW_TYPE;
+ }
+
+ return 0;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (isSearchAllContactsItemPosition(position)) {
+ return LayoutInflater.from(getContext()).inflate(
+ R.layout.contacts_list_search_all_item, parent, false);
+ }
+ return super.getView(position, convertView, parent);
}
}
diff --git a/src/com/android/contacts/list/ContactEntryListFragment.java b/src/com/android/contacts/list/ContactEntryListFragment.java
index aaa7f13..fefa718 100644
--- a/src/com/android/contacts/list/ContactEntryListFragment.java
+++ b/src/com/android/contacts/list/ContactEntryListFragment.java
@@ -46,7 +46,6 @@
import android.view.inputmethod.InputMethodManager;
import android.widget.AbsListView;
import android.widget.AdapterView;
-import android.widget.Filter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.AbsListView.OnScrollListener;
@@ -56,7 +55,8 @@
/**
* Common base class for various contact-related list fragments.
*/
-public abstract class ContactEntryListFragment extends LoaderManagingFragment<Cursor>
+public abstract class ContactEntryListFragment<T extends ContactEntryListAdapter>
+ extends LoaderManagingFragment<Cursor>
implements OnItemClickListener,
OnScrollListener, TextWatcher, OnEditorActionListener, OnCloseListener,
OnFocusChangeListener, OnTouchListener {
@@ -70,7 +70,8 @@
private String mQueryString;
private ContactsApplicationController mAppController;
- private ContactEntryListAdapter mAdapter;
+ private T mAdapter;
+ private View mView;
private ListView mListView;
/**
@@ -88,10 +89,10 @@
protected abstract View inflateView(LayoutInflater inflater, ViewGroup container);
- protected abstract ContactEntryListAdapter createListAdapter();
+ protected abstract T createListAdapter();
protected abstract void onItemClick(int position, long id);
- public ContactEntryListAdapter getAdapter() {
+ public T getAdapter() {
return mAdapter;
}
@@ -106,10 +107,14 @@
protected void onInitializeLoaders() {
}
- // TODO make abstract
@Override
protected void onLoadFinished(Loader<Cursor> loader, Cursor data) {
- throw new UnsupportedOperationException();
+ if (data != null && isSearchResultsMode()) {
+ TextView foundContactsText = (TextView)mView.findViewById(R.id.search_results_found);
+ String text = getQuantityText(data.getCount(),
+ R.string.listFoundAllContactsZero, R.plurals.listFoundAllContacts);
+ foundContactsText.setText(text);
+ }
}
protected void reloadData() {
@@ -217,10 +222,10 @@
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container) {
- View view = inflateView(inflater, container);
+ mView = inflateView(inflater, container);
mAdapter = createListAdapter();
- configureView(view);
- return view;
+ configureView(mView);
+ return mView;
}
protected void configureView(View view) {
@@ -415,4 +420,15 @@
mListState = null;
}
}
+
+ // TODO: fix PluralRules to handle zero correctly and use Resources.getQuantityText directly
+ public String getQuantityText(int count, int zeroResourceId, int pluralResourceId) {
+ if (count == 0) {
+ return getActivity().getString(zeroResourceId);
+ } else {
+ String format = getActivity().getResources()
+ .getQuantityText(pluralResourceId, count).toString();
+ return String.format(format, count);
+ }
+ }
}
diff --git a/src/com/android/contacts/list/ContactItemListAdapter.java b/src/com/android/contacts/list/ContactItemListAdapter.java
index 35c0fb5..fb7f942 100644
--- a/src/com/android/contacts/list/ContactItemListAdapter.java
+++ b/src/com/android/contacts/list/ContactItemListAdapter.java
@@ -21,6 +21,7 @@
import com.android.contacts.R;
import com.android.contacts.widget.TextWithHighlighting;
+import android.app.patterns.CursorLoader;
import android.content.Context;
import android.database.CharArrayBuffer;
import android.database.Cursor;
@@ -45,6 +46,7 @@
import android.widget.QuickContactBadge;
import android.widget.TextView;
+@Deprecated
public class ContactItemListAdapter extends ContactEntryListAdapter {
private final ContactsListActivity contactsListActivity;
@@ -81,6 +83,7 @@
}
}
+ @Override
public void setDisplayPhotos(boolean flag) {
mDisplayPhotos = flag;
}
@@ -226,6 +229,7 @@
return view;
}
+ @Override
public boolean isSearchAllContactsItemPosition(int position) {
return contactsListActivity.mSearchMode && contactsListActivity.mMode != ContactsListActivity.MODE_PICK_MULTIPLE_PHONES && position == getCount() - 1;
}
@@ -309,7 +313,8 @@
if (size != 0) {
if (highlightingEnabled) {
if (view.textWithHighlighting == null) {
- view.textWithHighlighting = createTextWithHighlighting();
+ view.textWithHighlighting =
+ getTextWithHighlightingFactory().createTextWithHighlighting();
}
buildDisplayNameWithHighlighting(nameView, cursor, view.nameBuffer,
view.highlightedTextBuffer, view.textWithHighlighting);
@@ -698,4 +703,17 @@
}
return super.getItemId(realPosition);
}
+
+ @Override
+ public void configureLoader(CursorLoader loader) {
+ }
+
+ @Override
+ public String getContactDisplayName() {
+ return "TODO";
+ }
+
+ public boolean isContactStarred() {
+ return false;
+ }
}
\ No newline at end of file
diff --git a/src/com/android/contacts/list/ContactListAdapter.java b/src/com/android/contacts/list/ContactListAdapter.java
new file mode 100644
index 0000000..db4017c
--- /dev/null
+++ b/src/com/android/contacts/list/ContactListAdapter.java
@@ -0,0 +1,242 @@
+/*
+ * 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.list;
+
+import android.app.patterns.CursorLoader;
+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.SearchSnippetColumns;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.QuickContactBadge;
+
+/**
+ * A cursor adapter for the {@link ContactsContract.Contacts#CONTENT_TYPE} content type.
+ */
+public class ContactListAdapter extends ContactEntryListAdapter {
+
+ private static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
+ Contacts._ID, // 0
+ Contacts.DISPLAY_NAME_PRIMARY, // 1
+ Contacts.DISPLAY_NAME_ALTERNATIVE, // 2
+ Contacts.SORT_KEY_PRIMARY, // 3
+ Contacts.STARRED, // 4
+ Contacts.TIMES_CONTACTED, // 5
+ Contacts.CONTACT_PRESENCE, // 6
+ Contacts.PHOTO_ID, // 7
+ Contacts.LOOKUP_KEY, // 8
+ Contacts.PHONETIC_NAME, // 9
+ Contacts.HAS_PHONE_NUMBER, // 10
+ };
+
+ private static final String[] CONTACTS_SUMMARY_FILTER_PROJECTION = new String[] {
+ Contacts._ID, // 0
+ Contacts.DISPLAY_NAME_PRIMARY, // 1
+ Contacts.DISPLAY_NAME_ALTERNATIVE, // 2
+ Contacts.SORT_KEY_PRIMARY, // 3
+ Contacts.STARRED, // 4
+ Contacts.TIMES_CONTACTED, // 5
+ Contacts.CONTACT_PRESENCE, // 6
+ Contacts.PHOTO_ID, // 7
+ Contacts.LOOKUP_KEY, // 8
+ Contacts.PHONETIC_NAME, // 9
+ Contacts.HAS_PHONE_NUMBER, // 10
+ SearchSnippetColumns.SNIPPET_MIMETYPE, // 11
+ SearchSnippetColumns.SNIPPET_DATA1, // 12
+ SearchSnippetColumns.SNIPPET_DATA4, // 13
+ };
+
+ private static final int SUMMARY_ID_COLUMN_INDEX = 0;
+ private static final int SUMMARY_DISPLAY_NAME_PRIMARY_COLUMN_INDEX = 1;
+ private static final int SUMMARY_DISPLAY_NAME_ALTERNATIVE_COLUMN_INDEX = 2;
+ private static final int SUMMARY_SORT_KEY_PRIMARY_COLUMN_INDEX = 3;
+ private static final int SUMMARY_STARRED_COLUMN_INDEX = 4;
+ private static final int SUMMARY_TIMES_CONTACTED_COLUMN_INDEX = 5;
+ private static final int SUMMARY_PRESENCE_STATUS_COLUMN_INDEX = 6;
+ private static final int SUMMARY_PHOTO_ID_COLUMN_INDEX = 7;
+ private static final int SUMMARY_LOOKUP_KEY_COLUMN_INDEX = 8;
+ private static final int SUMMARY_PHONETIC_NAME_COLUMN_INDEX = 9;
+ private static final int SUMMARY_HAS_PHONE_COLUMN_INDEX = 10;
+ private static final int SUMMARY_SNIPPET_MIMETYPE_COLUMN_INDEX = 11;
+ private static final int SUMMARY_SNIPPET_DATA1_COLUMN_INDEX = 12;
+ private static final int SUMMARY_SNIPPET_DATA4_COLUMN_INDEX = 13;
+
+ private boolean mQuickContactEnabled;
+ private CharSequence mUnknownNameText;
+ private int mDisplayNameColumnIndex;
+ private int mAlternativeDisplayNameColumnIndex;
+
+ public ContactListAdapter(Context context) {
+ super(context);
+
+ mUnknownNameText = context.getText(android.R.string.unknownName);
+ }
+
+ @Override
+ public void configureLoader(CursorLoader loader) {
+ Uri uri;
+ if (isSearchMode() || isSearchResultsMode()) {
+ String query = getQueryString();
+ uri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,
+ TextUtils.isEmpty(query) ? "" : Uri.encode(query));
+ loader.setProjection(CONTACTS_SUMMARY_FILTER_PROJECTION);
+ if (!isSearchResultsMode()) {
+ loader.setSelection(Contacts.IN_VISIBLE_GROUP + "=1");
+ }
+ } else {
+ uri = Contacts.CONTENT_URI;
+ loader.setProjection(CONTACTS_SUMMARY_PROJECTION);
+ loader.setSelection(Contacts.IN_VISIBLE_GROUP + "=1");
+ }
+
+ if (isSectionHeaderDisplayEnabled()) {
+ uri = buildSectionIndexerUri(uri);
+ }
+
+ loader.setUri(uri);
+
+ if (getSortOrder() == ContactsContract.Preferences.SORT_ORDER_PRIMARY) {
+ loader.setSortOrder(Contacts.SORT_KEY_PRIMARY);
+ } else {
+ loader.setSortOrder(Contacts.SORT_KEY_ALTERNATIVE);
+ }
+ }
+
+ private static Uri buildSectionIndexerUri(Uri uri) {
+ return uri.buildUpon()
+ .appendQueryParameter(ContactCounts.ADDRESS_BOOK_INDEX_EXTRAS, "true").build();
+ }
+
+ public boolean getHasPhoneNumber() {
+ return getCursor().getInt(SUMMARY_HAS_PHONE_COLUMN_INDEX) != 0;
+ }
+
+ public boolean isContactStarred() {
+ return getCursor().getInt(SUMMARY_STARRED_COLUMN_INDEX) != 0;
+ }
+
+ @Override
+ public String getContactDisplayName() {
+ return getCursor().getString(mDisplayNameColumnIndex);
+ }
+
+ public void setQuickContactEnabled(boolean quickContactEnabled) {
+ mQuickContactEnabled = quickContactEnabled;
+ }
+
+ @Override
+ public void setContactNameDisplayOrder(int displayOrder) {
+ super.setContactNameDisplayOrder(displayOrder);
+ if (getContactNameDisplayOrder() == ContactsContract.Preferences.DISPLAY_ORDER_PRIMARY) {
+ mDisplayNameColumnIndex = SUMMARY_DISPLAY_NAME_PRIMARY_COLUMN_INDEX;
+ mAlternativeDisplayNameColumnIndex = SUMMARY_DISPLAY_NAME_ALTERNATIVE_COLUMN_INDEX;
+ } else {
+ mDisplayNameColumnIndex = SUMMARY_DISPLAY_NAME_ALTERNATIVE_COLUMN_INDEX;
+ mAlternativeDisplayNameColumnIndex = SUMMARY_DISPLAY_NAME_PRIMARY_COLUMN_INDEX;
+ }
+ }
+
+ /**
+ * Builds the {@link Contacts#CONTENT_LOOKUP_URI} for the given
+ * {@link ListView} position.
+ */
+ public Uri getContactUri() {
+ Cursor cursor = getCursor();
+ long contactId = cursor.getLong(SUMMARY_ID_COLUMN_INDEX);
+ String lookupKey = cursor.getString(SUMMARY_LOOKUP_KEY_COLUMN_INDEX);
+ return Contacts.getLookupUri(contactId, lookupKey);
+ }
+
+ @Override
+ public View newView(Context context, Cursor cursor, ViewGroup parent) {
+ final ContactListItemView view = new ContactListItemView(context, null);
+ view.setUnknownNameText(mUnknownNameText);
+ view.setTextWithHighlightingFactory(getTextWithHighlightingFactory());
+ // TODO
+// view.setOnCallButtonClickListener(contactsListActivity);
+ return view;
+ }
+
+ @Override
+ public void bindView(View itemView, Context context, Cursor cursor) {
+ final ContactListItemView view = (ContactListItemView)itemView;
+
+ if (isSectionHeaderDisplayEnabled()) {
+ final int position = cursor.getPosition();
+ final int section = getSectionForPosition(position);
+ if (getPositionForSection(section) == position) {
+ String title = (String)getSections()[section];
+ view.setSectionHeader(title);
+ } else {
+ view.setDividerVisible(false);
+ view.setSectionHeader(null);
+ }
+
+ // move the divider for the last item in a section
+ if (getPositionForSection(section + 1) - 1 == position) {
+ view.setDividerVisible(false);
+ } else {
+ view.setDividerVisible(true);
+ }
+ }
+
+ view.showDisplayName(cursor, mDisplayNameColumnIndex, isNameHighlightingEnabled(),
+ mAlternativeDisplayNameColumnIndex);
+//
+// // Make the call button visible if requested.
+// if (mDisplayCallButton
+// && cursor.getColumnCount() > ContactsListActivity.SUMMARY_HAS_PHONE_COLUMN_INDEX
+// && cursor.getInt(ContactsListActivity.SUMMARY_HAS_PHONE_COLUMN_INDEX) != 0) {
+// int pos = cursor.getPosition();
+// view.showCallButton(android.R.id.button1, pos);
+// } else {
+// view.hideCallButton();
+// }
+//
+
+ // Set the photo, if available
+ long photoId = 0;
+ if (!cursor.isNull(SUMMARY_PHOTO_ID_COLUMN_INDEX)) {
+ photoId = cursor.getLong(SUMMARY_PHOTO_ID_COLUMN_INDEX);
+ }
+
+ ImageView viewToUse;
+ if (mQuickContactEnabled) {
+ QuickContactBadge quickContact = view.getQuickContact();
+ quickContact.assignContactUri(getContactUri());
+ viewToUse = quickContact;
+ } else {
+ viewToUse = view.getPhotoView();
+ }
+
+ getPhotoLoader().loadPhoto(viewToUse, photoId);
+
+ view.showPresence(cursor, SUMMARY_PRESENCE_STATUS_COLUMN_INDEX);
+ view.showPhoneticName(cursor, SUMMARY_PHONETIC_NAME_COLUMN_INDEX);
+
+ if (isSearchMode() || isSearchResultsMode()) {
+ view.showSnippet(cursor, SUMMARY_SNIPPET_MIMETYPE_COLUMN_INDEX,
+ SUMMARY_SNIPPET_DATA1_COLUMN_INDEX, SUMMARY_SNIPPET_DATA4_COLUMN_INDEX);
+ }
+ }
+}
diff --git a/src/com/android/contacts/list/ContactListItemView.java b/src/com/android/contacts/list/ContactListItemView.java
index 4db52fa..ef131d1 100644
--- a/src/com/android/contacts/list/ContactListItemView.java
+++ b/src/com/android/contacts/list/ContactListItemView.java
@@ -16,24 +16,29 @@
package com.android.contacts.list;
+import com.android.contacts.ContactPresenceIconUtil;
import com.android.contacts.R;
import com.android.contacts.widget.TextWithHighlighting;
+import com.android.contacts.widget.TextWithHighlightingFactory;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.database.CharArrayBuffer;
+import android.database.Cursor;
import android.graphics.Canvas;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Nickname;
+import android.provider.ContactsContract.CommonDataKinds.Organization;
import android.text.TextUtils;
import android.text.TextUtils.TruncateAt;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.QuickContactBadge;
import android.widget.TextView;
@@ -61,7 +66,7 @@
private final int mPresenceIconMargin;
private final int mHeaderTextWidth;
- private boolean mHorizontalDividerVisible;
+ private boolean mHorizontalDividerVisible = true;
private Drawable mHorizontalDividerDrawable;
private int mHorizontalDividerHeight;
@@ -90,13 +95,15 @@
private int mLine3Height;
private OnClickListener mCallButtonClickListener;
-
+ private TextWithHighlightingFactory mTextWithHighlightingFactory;
public CharArrayBuffer nameBuffer = new CharArrayBuffer(128);
public CharArrayBuffer dataBuffer = new CharArrayBuffer(128);
public CharArrayBuffer highlightedTextBuffer = new CharArrayBuffer(128);
public TextWithHighlighting textWithHighlighting;
public CharArrayBuffer phoneticNameBuffer = new CharArrayBuffer(128);
+ private CharSequence mUnknownNameText;
+
/**
* Special class to allow the parent to be pressed without being pressed itself.
* This way the line of a tab can be pressed, but the image itself is not.
@@ -158,6 +165,14 @@
mCallButtonClickListener = callButtonClickListener;
}
+ public void setTextWithHighlightingFactory(TextWithHighlightingFactory factory) {
+ mTextWithHighlightingFactory = factory;
+ }
+
+ public void setUnknownNameText(CharSequence unknownNameText) {
+ mUnknownNameText = unknownNameText;
+ }
+
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// We will match parent's width and wrap content vertically, but make sure
@@ -655,4 +670,90 @@
}
}
}
+
+ public void showDisplayName(Cursor cursor, int nameColumnIndex, boolean highlightingEnabled,
+ int alternativeNameColumnIndex) {
+ cursor.copyStringToBuffer(nameColumnIndex, nameBuffer);
+ TextView nameView = getNameTextView();
+ int size = nameBuffer.sizeCopied;
+ if (size != 0) {
+ if (highlightingEnabled) {
+ if (textWithHighlighting == null) {
+ textWithHighlighting =
+ mTextWithHighlightingFactory.createTextWithHighlighting();
+ }
+ cursor.copyStringToBuffer(alternativeNameColumnIndex, highlightedTextBuffer);
+ textWithHighlighting.setText(nameBuffer, highlightedTextBuffer);
+ nameView.setText(textWithHighlighting);
+ } else {
+ nameView.setText(nameBuffer.data, 0, size);
+ }
+ } else {
+ nameView.setText(mUnknownNameText);
+ }
+ }
+
+ public void showPhoneticName(Cursor cursor, int phoneticNameColumnIndex) {
+ cursor.copyStringToBuffer(phoneticNameColumnIndex, phoneticNameBuffer);
+ int phoneticNameSize = phoneticNameBuffer.sizeCopied;
+ if (phoneticNameSize != 0) {
+ setLabel(phoneticNameBuffer.data, phoneticNameSize);
+ } else {
+ setLabel(null);
+ }
+ }
+
+ /**
+ * Sets the proper icon (star or presence or nothing)
+ */
+ public void showPresence(Cursor cursor, int presenceColumnIndex) {
+ int serverStatus;
+ if (!cursor.isNull(presenceColumnIndex)) {
+ serverStatus = cursor.getInt(presenceColumnIndex);
+
+ // TODO consider caching these drawables
+ Drawable icon = ContactPresenceIconUtil.getPresenceIcon(getContext(), serverStatus);
+ if (icon != null) {
+ setPresence(icon);
+ } else {
+ setPresence(null);
+ }
+ } else {
+ setPresence(null);
+ }
+ }
+
+ /**
+ * Shows search snippet.
+ */
+ public void showSnippet(Cursor cursor, int summarySnippetMimetypeColumnIndex,
+ int summarySnippetData1ColumnIndex, int summarySnippetData4ColumnIndex) {
+ String snippet = null;
+ String snippetMimeType = cursor.getString(summarySnippetMimetypeColumnIndex);
+ if (Email.CONTENT_ITEM_TYPE.equals(snippetMimeType)) {
+ String email = cursor.getString(summarySnippetData1ColumnIndex);
+ if (!TextUtils.isEmpty(email)) {
+ snippet = email;
+ }
+ } else if (Organization.CONTENT_ITEM_TYPE.equals(snippetMimeType)) {
+ String company = cursor.getString(summarySnippetData1ColumnIndex);
+ String title = cursor.getString(summarySnippetData4ColumnIndex);
+ if (!TextUtils.isEmpty(company)) {
+ if (!TextUtils.isEmpty(title)) {
+ snippet = company + " / " + title;
+ } else {
+ snippet = company;
+ }
+ } else if (!TextUtils.isEmpty(title)) {
+ snippet = title;
+ }
+ } else if (Nickname.CONTENT_ITEM_TYPE.equals(snippetMimeType)) {
+ String nickname = cursor.getString(summarySnippetData1ColumnIndex);
+ if (!TextUtils.isEmpty(nickname)) {
+ snippet = nickname;
+ }
+ }
+
+ setSnippet(snippet);
+ }
}
diff --git a/src/com/android/contacts/list/ContactPickerFragment.java b/src/com/android/contacts/list/ContactPickerFragment.java
index b1768a2..07908dd 100644
--- a/src/com/android/contacts/list/ContactPickerFragment.java
+++ b/src/com/android/contacts/list/ContactPickerFragment.java
@@ -15,11 +15,9 @@
*/
package com.android.contacts.list;
-import com.android.contacts.ContactsListActivity;
import com.android.contacts.R;
import android.content.Intent;
-import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -28,7 +26,7 @@
* Fragment for the contact list used for browsing contacts (as compared to
* picking a contact with one of the PICK or SHORTCUT intents).
*/
-public class ContactPickerFragment extends ContactEntryListFragment {
+public class ContactPickerFragment extends ContactEntryListFragment<ContactListAdapter> {
private OnContactPickerActionListener mListener;
private boolean mCreateContactEnabled;
@@ -50,7 +48,7 @@
if (position == 0 && !isSearchMode() && isCreateContactEnabled()) {
mListener.onCreateNewContactAction();
} else {
- ContactEntryListAdapter adapter = getAdapter();
+ ContactListAdapter adapter = getAdapter();
adapter.moveToPosition(position);
mListener.onPickContactAction(adapter.getContactUri());
}
@@ -58,11 +56,13 @@
}
@Override
- protected ContactEntryListAdapter createListAdapter() {
- ContactItemListAdapter adapter =
- new ContactItemListAdapter((ContactsListActivity)getActivity());
+ protected ContactListAdapter createListAdapter() {
+ ContactListAdapter adapter = new ContactListAdapter(getActivity());
adapter.setSectionHeaderDisplayEnabled(isSectionHeaderDisplayEnabled());
adapter.setDisplayPhotos(isPhotoLoaderEnabled());
+
+ // TODO more settings
+
return adapter;
}
diff --git a/src/com/android/contacts/widget/PinnedHeaderListView.java b/src/com/android/contacts/widget/PinnedHeaderListView.java
index f37423d..24e5638 100644
--- a/src/com/android/contacts/widget/PinnedHeaderListView.java
+++ b/src/com/android/contacts/widget/PinnedHeaderListView.java
@@ -124,6 +124,7 @@
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mHeaderView != null) {
+ configureHeaderView(getFirstVisiblePosition());
measureChild(mHeaderView, widthMeasureSpec, heightMeasureSpec);
mHeaderViewWidth = mHeaderView.getMeasuredWidth();
mHeaderViewHeight = mHeaderView.getMeasuredHeight();
@@ -135,7 +136,6 @@
super.onLayout(changed, left, top, right, bottom);
if (mHeaderView != null) {
mHeaderView.layout(0, 0, mHeaderViewWidth, mHeaderViewHeight);
- configureHeaderView(getFirstVisiblePosition());
}
}