Merge "Add different Uri formats for Contact-Editor Tests"
diff --git a/res/layout-finger/recent_calls_list_child_item.xml b/res/layout-finger/recent_calls_list_child_item.xml
index 14eb24d..527e259 100644
--- a/res/layout-finger/recent_calls_list_child_item.xml
+++ b/res/layout-finger/recent_calls_list_child_item.xml
@@ -21,7 +21,7 @@
android:background="@drawable/list_item_background_secondary"
>
- <com.android.contacts.ui.widget.DontPressWithParentImageView android:id="@+id/call_icon"
+ <ImageView android:id="@+id/call_icon"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingLeft="14dip"
diff --git a/res/layout-finger/recent_calls_list_group_item.xml b/res/layout-finger/recent_calls_list_group_item.xml
index 2d3e7af..5b4cf21 100644
--- a/res/layout-finger/recent_calls_list_group_item.xml
+++ b/res/layout-finger/recent_calls_list_group_item.xml
@@ -20,7 +20,7 @@
android:paddingLeft="7dip"
>
- <com.android.contacts.ui.widget.DontPressWithParentImageView android:id="@+id/call_icon"
+ <ImageView android:id="@+id/call_icon"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingLeft="14dip"
diff --git a/res/layout-finger/recent_calls_list_item.xml b/res/layout-finger/recent_calls_list_item.xml
index 8efa23c..2c519d6 100644
--- a/res/layout-finger/recent_calls_list_item.xml
+++ b/res/layout-finger/recent_calls_list_item.xml
@@ -20,7 +20,7 @@
android:paddingLeft="7dip"
>
- <com.android.contacts.ui.widget.DontPressWithParentImageView android:id="@+id/call_icon"
+ <ImageView android:id="@+id/call_icon"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingLeft="14dip"
diff --git a/src/com/android/contacts/ContactsListActivity.java b/src/com/android/contacts/ContactsListActivity.java
index 5d061f7..8a52786 100644
--- a/src/com/android/contacts/ContactsListActivity.java
+++ b/src/com/android/contacts/ContactsListActivity.java
@@ -17,16 +17,17 @@
package com.android.contacts;
import com.android.contacts.list.ContactBrowseListContextMenuAdapter;
-import com.android.contacts.list.ContactBrowseListFragment;
import com.android.contacts.list.ContactEntryListAdapter;
import com.android.contacts.list.ContactEntryListFragment;
import com.android.contacts.list.ContactItemListAdapter;
import com.android.contacts.list.ContactPickerFragment;
import com.android.contacts.list.ContactsIntentResolver;
+import com.android.contacts.list.DefaultContactBrowseListFragment;
import com.android.contacts.list.DefaultContactListFragment;
import com.android.contacts.list.MultiplePhonePickerFragment;
import com.android.contacts.list.OnContactBrowserActionListener;
import com.android.contacts.list.OnContactPickerActionListener;
+import com.android.contacts.list.StrequentContactListFragment;
import com.android.contacts.model.ContactsSource;
import com.android.contacts.model.Sources;
import com.android.contacts.ui.ContactsPreferences;
@@ -66,7 +67,6 @@
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
-import android.os.Parcelable;
import android.preference.PreferenceManager;
import android.provider.ContactsContract;
import android.provider.Settings;
@@ -87,9 +87,7 @@
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
import android.provider.ContactsContract.Intents.Insert;
import android.telephony.TelephonyManager;
-import android.text.Editable;
import android.text.TextUtils;
-import android.text.TextWatcher;
import android.util.Log;
import android.view.ContextThemeWrapper;
import android.view.KeyEvent;
@@ -97,17 +95,12 @@
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
-import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
-import android.view.View.OnFocusChangeListener;
-import android.view.View.OnTouchListener;
-import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.ArrayAdapter;
import android.widget.Button;
-import android.widget.Filter;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
@@ -514,10 +507,9 @@
case MODE_DEFAULT:
case MODE_INSERT_OR_EDIT_CONTACT:
case MODE_QUERY_PICK_TO_EDIT:
- case MODE_STREQUENT:
case MODE_FREQUENT:
case MODE_QUERY: {
- ContactBrowseListFragment fragment = new ContactBrowseListFragment();
+ DefaultContactBrowseListFragment fragment = new DefaultContactBrowseListFragment();
if (!mSearchMode) {
fragment.setSectionHeaderDisplayEnabled(true);
}
@@ -594,6 +586,68 @@
mListFragment = fragment;
break;
}
+ case MODE_STREQUENT: {
+ StrequentContactListFragment fragment = new StrequentContactListFragment();
+ fragment.setSectionHeaderDisplayEnabled(false);
+ fragment.setOnContactListActionListener(new OnContactBrowserActionListener() {
+ public void onSearchAllContactsAction(String string) {
+ doSearch();
+ }
+
+ public void onViewContactAction(Uri contactLookupUri) {
+ startActivity(new Intent(Intent.ACTION_VIEW, contactLookupUri));
+ }
+
+ public void onCreateNewContactAction() {
+ Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
+ Bundle extras = getIntent().getExtras();
+ if (extras != null) {
+ intent.putExtras(extras);
+ }
+ startActivity(intent);
+ }
+
+ public void onEditContactAction(Uri contactLookupUri) {
+ Intent intent = new Intent(Intent.ACTION_EDIT, contactLookupUri);
+ Bundle extras = getIntent().getExtras();
+ if (extras != null) {
+ intent.putExtras(extras);
+ }
+ startActivity(intent);
+ }
+
+ public void onAddToFavoritesAction(Uri contactUri) {
+ ContentValues values = new ContentValues(1);
+ values.put(Contacts.STARRED, 1);
+ getContentResolver().update(contactUri, values, null, null);
+ }
+
+ public void onRemoveFromFavoritesAction(Uri contactUri) {
+ ContentValues values = new ContentValues(1);
+ values.put(Contacts.STARRED, 0);
+ getContentResolver().update(contactUri, values, null, null);
+ }
+
+ public void onCallContactAction(Uri contactUri) {
+ // TODO
+ }
+
+ public void onSmsContactAction(Uri contactUri) {
+ // TODO
+ }
+
+ public void onDeleteContactAction(Uri contactUri) {
+ doContactDelete(contactUri);
+ }
+
+ public void onFinishAction() {
+ onBackPressed();
+ }
+ });
+ fragment.setContextMenuAdapter(new ContactBrowseListContextMenuAdapter(fragment));
+ mListFragment = fragment;
+ break;
+ }
case MODE_PICK_CONTACT:
case MODE_PICK_OR_CREATE_CONTACT: {
ContactPickerFragment fragment = new ContactPickerFragment();
diff --git a/src/com/android/contacts/list/ContactBrowseListFragment.java b/src/com/android/contacts/list/ContactBrowseListFragment.java
index 5ae425f..0614772 100644
--- a/src/com/android/contacts/list/ContactBrowseListFragment.java
+++ b/src/com/android/contacts/list/ContactBrowseListFragment.java
@@ -15,26 +15,20 @@
*/
package com.android.contacts.list;
-import com.android.contacts.R;
-
import android.app.patterns.CursorLoader;
import android.app.patterns.Loader;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
/**
* 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<ContactListAdapter> {
+public abstract class ContactBrowseListFragment extends
+ ContactEntryListFragment<ContactListAdapter> {
private OnContactBrowserActionListener mListener;
- private boolean mEditMode;
- private boolean mCreateContactEnabled;
private CursorLoader mLoader;
@@ -44,6 +38,10 @@
return mLoader;
}
+ public CursorLoader getLoader() {
+ return mLoader;
+ }
+
@Override
protected void reloadData() {
getAdapter().configureLoader(mLoader);
@@ -65,68 +63,12 @@
getAdapter().changeCursor(data);
}
- @Override
- protected void onItemClick(int position, long id) {
- ContactListAdapter adapter = getAdapter();
- if (adapter.isSearchAllContactsItemPosition(position)) {
- mListener.onSearchAllContactsAction((String)null);
- } else if (isEditMode()) {
- if (position == 0 && !isSearchMode() && isCreateContactEnabled()) {
- mListener.onCreateNewContactAction();
- } else {
- adapter.moveToPosition(position);
- mListener.onEditContactAction(adapter.getContactUri());
- }
- } else {
- adapter.moveToPosition(position);
- mListener.onViewContactAction(adapter.getContactUri());
- }
+ public void createNewContact() {
+ mListener.onCreateNewContactAction();
}
- @Override
- protected ContactListAdapter createListAdapter() {
- ContactListAdapter adapter = new ContactListAdapter(getActivity());
- adapter.setSectionHeaderDisplayEnabled(isSectionHeaderDisplayEnabled());
-
- 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;
- }
-
- @Override
- protected View inflateView(LayoutInflater inflater, ViewGroup container) {
- if (isSearchMode()) {
- return inflater.inflate(R.layout.contacts_search_content, null);
- } else if (isSearchResultsMode()) {
- return inflater.inflate(R.layout.contacts_list_search_results, null);
- } else {
- return inflater.inflate(R.layout.contacts_list_content, null);
- }
- }
-
- public void setEditMode(boolean flag) {
- mEditMode = flag;
- }
-
- public boolean isEditMode() {
- return mEditMode;
- }
-
- public void setCreateContactEnabled(boolean flag) {
- this.mCreateContactEnabled = flag;
- }
-
- public boolean isCreateContactEnabled() {
- return mCreateContactEnabled;
+ public void searchAllContacts() {
+ mListener.onSearchAllContactsAction((String)null);
}
public void viewContact(Uri contactUri) {
diff --git a/src/com/android/contacts/list/ContactEntryListAdapter.java b/src/com/android/contacts/list/ContactEntryListAdapter.java
index 9da3704..c37010e 100644
--- a/src/com/android/contacts/list/ContactEntryListAdapter.java
+++ b/src/com/android/contacts/list/ContactEntryListAdapter.java
@@ -18,6 +18,7 @@
import com.android.contacts.ContactPhotoLoader;
import com.android.contacts.ContactsSectionIndexer;
import com.android.contacts.R;
+import com.android.contacts.widget.PinnedHeaderListAdapter;
import com.android.contacts.widget.TextWithHighlightingFactory;
import android.app.patterns.CursorLoader;
@@ -53,7 +54,8 @@
private boolean mSearchResultsMode;
public ContactEntryListAdapter(Context context) {
- super(context);
+ super(context, R.layout.list_section, R.id.header_text,
+ context.getResources().getColor(R.color.pinned_header_background));
}
public Context getContext() {
diff --git a/src/com/android/contacts/list/ContactEntryListFragment.java b/src/com/android/contacts/list/ContactEntryListFragment.java
index fefa718..9a3bf1d 100644
--- a/src/com/android/contacts/list/ContactEntryListFragment.java
+++ b/src/com/android/contacts/list/ContactEntryListFragment.java
@@ -90,12 +90,35 @@
protected abstract View inflateView(LayoutInflater inflater, ViewGroup container);
protected abstract T createListAdapter();
+
+ /**
+ * @param position Please note that the position is already adjusted for
+ * header views, so "0" means the first list item below header
+ * views.
+ */
protected abstract void onItemClick(int position, long id);
public T getAdapter() {
return mAdapter;
}
+ public void setListAdapter(T adapter) {
+ mAdapter = adapter;
+ mListView.setAdapter(mAdapter);
+ if (isPhotoLoaderEnabled()) {
+ mAdapter.setPhotoLoader(mPhotoLoader);
+ }
+ ((ContactsListActivity)getActivity()).setupListView(mAdapter, mListView);
+ }
+
+ public View getView() {
+ return mView;
+ }
+
+ public ListView getListView() {
+ return mListView;
+ }
+
// TODO make abstract
@Override
protected Loader<Cursor> onCreateLoader(int id, Bundle args) {
@@ -109,12 +132,17 @@
@Override
protected void onLoadFinished(Loader<Cursor> loader, Cursor data) {
- 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);
+ if (data == null) {
+ return;
}
+
+ showCount(data);
+ }
+
+ /**
+ * Shows the count of entries included in the list.
+ */
+ protected void showCount(Cursor data) {
}
protected void reloadData() {
@@ -222,26 +250,27 @@
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container) {
- mView = inflateView(inflater, container);
+ mView = createView(inflater, container);
mAdapter = createListAdapter();
- configureView(mView);
+ setListAdapter(mAdapter);
return mView;
}
- protected void configureView(View view) {
- mListView = (ListView)view.findViewById(android.R.id.list);
+ protected View createView(LayoutInflater inflater, ViewGroup container) {
+ mView = inflateView(inflater, container);
+
+ mListView = (ListView)mView.findViewById(android.R.id.list);
if (mListView == null) {
throw new RuntimeException(
"Your content must have a ListView whose id attribute is " +
"'android.R.id.list'");
}
- View emptyView = view.findViewById(com.android.internal.R.id.empty);
+ View emptyView = mView.findViewById(com.android.internal.R.id.empty);
if (emptyView != null) {
mListView.setEmptyView(emptyView);
}
- mListView.setAdapter(mAdapter);
mListView.setOnItemClickListener(this);
mListView.setOnFocusChangeListener(this);
mListView.setOnTouchListener(this);
@@ -257,17 +286,14 @@
mListView.setOnCreateContextMenuListener(mContextMenuAdapter);
}
- configurePinnedHeader();
-
if (isPhotoLoaderEnabled()) {
mPhotoLoader =
new ContactPhotoLoader(getActivity(), R.drawable.ic_contact_list_picture);
- mAdapter.setPhotoLoader(mPhotoLoader);
mListView.setOnScrollListener(this);
}
if (isSearchMode()) {
- mSearchEditText = (SearchEditText)view.findViewById(R.id.search_src_text);
+ mSearchEditText = (SearchEditText)mView.findViewById(R.id.search_src_text);
mSearchEditText.setText(getQueryString());
mSearchEditText.addTextChangedListener(this);
mSearchEditText.setOnEditorActionListener(this);
@@ -275,14 +301,13 @@
}
if (isSearchResultsMode()) {
- TextView titleText = (TextView)view.findViewById(R.id.search_results_for);
+ TextView titleText = (TextView)mView.findViewById(R.id.search_results_for);
if (titleText != null) {
titleText.setText(Html.fromHtml(getActivity().getString(R.string.search_results_for,
"<b>" + getQueryString() + "</b>")));
}
}
-
- ((ContactsListActivity)getActivity()).setupListView(mAdapter, mListView);
+ return mView;
}
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
@@ -314,22 +339,14 @@
super.onDestroy();
}
- private void configurePinnedHeader() {
- if (!mSectionHeaderDisplayEnabled) {
- return;
- }
-
- if (mListView instanceof PinnedHeaderListView) {
- PinnedHeaderListView pinnedHeaderList = (PinnedHeaderListView)mListView;
- View headerView = mAdapter.createPinnedHeaderView(pinnedHeaderList);
- pinnedHeaderList.setPinnedHeaderView(headerView);
- }
- }
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
hideSoftKeyboard();
- onItemClick(position, id);
+ int adjPosition = position - mListView.getHeaderViewsCount();
+ if (adjPosition >= 0) {
+ onItemClick(adjPosition, id);
+ }
}
private void hideSoftKeyboard() {
diff --git a/src/com/android/contacts/list/ContactListAdapter.java b/src/com/android/contacts/list/ContactListAdapter.java
index db4017c..1d7f72f 100644
--- a/src/com/android/contacts/list/ContactListAdapter.java
+++ b/src/com/android/contacts/list/ContactListAdapter.java
@@ -15,7 +15,6 @@
*/
package com.android.contacts.list;
-import android.app.patterns.CursorLoader;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
@@ -23,7 +22,6 @@
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;
@@ -33,9 +31,9 @@
/**
* A cursor adapter for the {@link ContactsContract.Contacts#CONTENT_TYPE} content type.
*/
-public class ContactListAdapter extends ContactEntryListAdapter {
+public abstract class ContactListAdapter extends ContactEntryListAdapter {
- private static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
+ protected static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
Contacts._ID, // 0
Contacts.DISPLAY_NAME_PRIMARY, // 1
Contacts.DISPLAY_NAME_ALTERNATIVE, // 2
@@ -49,7 +47,7 @@
Contacts.HAS_PHONE_NUMBER, // 10
};
- private static final String[] CONTACTS_SUMMARY_FILTER_PROJECTION = new String[] {
+ protected static final String[] CONTACTS_SUMMARY_FILTER_PROJECTION = new String[] {
Contacts._ID, // 0
Contacts.DISPLAY_NAME_PRIMARY, // 1
Contacts.DISPLAY_NAME_ALTERNATIVE, // 2
@@ -66,20 +64,20 @@
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;
+ protected static final int SUMMARY_ID_COLUMN_INDEX = 0;
+ protected static final int SUMMARY_DISPLAY_NAME_PRIMARY_COLUMN_INDEX = 1;
+ protected static final int SUMMARY_DISPLAY_NAME_ALTERNATIVE_COLUMN_INDEX = 2;
+ protected static final int SUMMARY_SORT_KEY_PRIMARY_COLUMN_INDEX = 3;
+ protected static final int SUMMARY_STARRED_COLUMN_INDEX = 4;
+ protected static final int SUMMARY_TIMES_CONTACTED_COLUMN_INDEX = 5;
+ protected static final int SUMMARY_PRESENCE_STATUS_COLUMN_INDEX = 6;
+ protected static final int SUMMARY_PHOTO_ID_COLUMN_INDEX = 7;
+ protected static final int SUMMARY_LOOKUP_KEY_COLUMN_INDEX = 8;
+ protected static final int SUMMARY_PHONETIC_NAME_COLUMN_INDEX = 9;
+ protected static final int SUMMARY_HAS_PHONE_COLUMN_INDEX = 10;
+ protected static final int SUMMARY_SNIPPET_MIMETYPE_COLUMN_INDEX = 11;
+ protected static final int SUMMARY_SNIPPET_DATA1_COLUMN_INDEX = 12;
+ protected static final int SUMMARY_SNIPPET_DATA4_COLUMN_INDEX = 13;
private boolean mQuickContactEnabled;
private CharSequence mUnknownNameText;
@@ -92,37 +90,11 @@
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);
- }
+ public CharSequence getUnknownNameText() {
+ return mUnknownNameText;
}
- private static Uri buildSectionIndexerUri(Uri uri) {
+ protected static Uri buildSectionIndexerUri(Uri uri) {
return uri.buildUpon()
.appendQueryParameter(ContactCounts.ADDRESS_BOOK_INDEX_EXTRAS, "true").build();
}
diff --git a/src/com/android/contacts/list/ContactPickerFragment.java b/src/com/android/contacts/list/ContactPickerFragment.java
index 07908dd..930646b 100644
--- a/src/com/android/contacts/list/ContactPickerFragment.java
+++ b/src/com/android/contacts/list/ContactPickerFragment.java
@@ -57,7 +57,8 @@
@Override
protected ContactListAdapter createListAdapter() {
- ContactListAdapter adapter = new ContactListAdapter(getActivity());
+ // TODO different adapter
+ ContactListAdapter adapter = new DefaultContactListAdapter(getActivity());
adapter.setSectionHeaderDisplayEnabled(isSectionHeaderDisplayEnabled());
adapter.setDisplayPhotos(isPhotoLoaderEnabled());
diff --git a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
new file mode 100644
index 0000000..50a3f4b
--- /dev/null
+++ b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
@@ -0,0 +1,139 @@
+/*
+ * 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 com.android.contacts.R;
+
+import android.database.Cursor;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+/**
+ * Fragment containing a contact list used for browsing (as compared to
+ * picking a contact with one of the PICK intents).
+ */
+public class DefaultContactBrowseListFragment extends ContactBrowseListFragment {
+
+ private boolean mEditMode;
+ private boolean mCreateContactEnabled;
+
+ @Override
+ protected void onItemClick(int position, long id) {
+ ContactListAdapter adapter = getAdapter();
+ if (adapter.isSearchAllContactsItemPosition(position)) {
+ searchAllContacts();
+ } else {
+ if (isEditMode()) {
+ if (position == 0 && !isSearchMode() && isCreateContactEnabled()) {
+ createNewContact();
+ } else {
+ adapter.moveToPosition(position);
+ editContact(adapter.getContactUri());
+ }
+ } else {
+ adapter.moveToPosition(position);
+ viewContact(adapter.getContactUri());
+ }
+ }
+ }
+
+ @Override
+ protected ContactListAdapter createListAdapter() {
+ DefaultContactListAdapter adapter = new DefaultContactListAdapter(getActivity());
+ adapter.setSectionHeaderDisplayEnabled(isSectionHeaderDisplayEnabled());
+
+ adapter.setSearchMode(isSearchMode());
+ adapter.setSearchResultsMode(isSearchResultsMode());
+ adapter.setQueryString(getQueryString());
+
+ adapter.setContactNameDisplayOrder(getContactNameDisplayOrder());
+ adapter.setSortOrder(getSortOrder());
+
+ adapter.setDisplayPhotos(true);
+ adapter.setQuickContactEnabled(true);
+
+ adapter.configureLoader(getLoader());
+ return adapter;
+ }
+
+ @Override
+ protected View inflateView(LayoutInflater inflater, ViewGroup container) {
+ if (isSearchMode()) {
+ return inflater.inflate(R.layout.contacts_search_content, null);
+ } else if (isSearchResultsMode()) {
+ return inflater.inflate(R.layout.contacts_list_search_results, null);
+ } else {
+ return inflater.inflate(R.layout.contacts_list_content, null);
+ }
+ }
+
+ @Override
+ protected View createView(LayoutInflater inflater, ViewGroup container) {
+ View view = super.createView(inflater, container);
+ if (!isSearchResultsMode()) {
+ // In the search-results mode the count is shown in the fat header above the list
+ getListView().addHeaderView(inflater.inflate(R.layout.total_contacts, null, false));
+ }
+ return view;
+ }
+
+ @Override
+ protected void showCount(Cursor data) {
+ int count = data.getCount();
+ if (isSearchMode()) {
+ TextView textView = (TextView) getView().findViewById(R.id.totalContactsText);
+ // TODO
+ // if (TextUtils.isEmpty(getQueryString())) {
+ String text = getQuantityText(count, R.string.listFoundAllContactsZero,
+ R.plurals.searchFoundContacts);
+ textView.setText(text);
+ }
+ else if (isSearchResultsMode()) {
+ TextView countText = (TextView)getView().findViewById(R.id.search_results_found);
+ String text = getQuantityText(data.getCount(),
+ R.string.listFoundAllContactsZero, R.plurals.listFoundAllContacts);
+ countText.setText(text);
+ } else {
+ // TODO
+ // if (contactsListActivity.mDisplayOnlyPhones) {
+ // text = contactsListActivity.getQuantityText(count,
+ // R.string.listTotalPhoneContactsZero,
+ // R.plurals.listTotalPhoneContacts);
+ TextView textView = (TextView)getView().findViewById(R.id.totalContactsText);
+ String text = getQuantityText(count, R.string.listTotalAllContactsZero,
+ R.plurals.listTotalAllContacts);
+ textView.setText(text);
+ }
+ }
+
+ public void setEditMode(boolean flag) {
+ mEditMode = flag;
+ }
+
+ public boolean isEditMode() {
+ return mEditMode;
+ }
+
+ public void setCreateContactEnabled(boolean flag) {
+ this.mCreateContactEnabled = flag;
+ }
+
+ public boolean isCreateContactEnabled() {
+ return mCreateContactEnabled;
+ }
+}
diff --git a/src/com/android/contacts/list/DefaultContactListAdapter.java b/src/com/android/contacts/list/DefaultContactListAdapter.java
new file mode 100644
index 0000000..f310c5c
--- /dev/null
+++ b/src/com/android/contacts/list/DefaultContactListAdapter.java
@@ -0,0 +1,81 @@
+/*
+ * 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.Contacts;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * A cursor adapter for the {@link ContactsContract.Contacts#CONTENT_TYPE} content type.
+ */
+public class DefaultContactListAdapter extends ContactListAdapter {
+
+ public DefaultContactListAdapter(Context context) {
+ super(context);
+ }
+
+ @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);
+ }
+ }
+
+ @Override
+ public View newView(Context context, Cursor cursor, ViewGroup parent) {
+ final ContactListItemView view = new ContactListItemView(context, null);
+ view.setUnknownNameText(getUnknownNameText());
+ view.setTextWithHighlightingFactory(getTextWithHighlightingFactory());
+ // TODO
+// view.setOnCallButtonClickListener(contactsListActivity);
+ return view;
+ }
+
+ @Override
+ public void bindView(View itemView, Context context, Cursor cursor) {
+ super.bindView(itemView, context, cursor);
+ }
+}
diff --git a/src/com/android/contacts/list/StrequentContactListAdapter.java b/src/com/android/contacts/list/StrequentContactListAdapter.java
new file mode 100644
index 0000000..dc20c97
--- /dev/null
+++ b/src/com/android/contacts/list/StrequentContactListAdapter.java
@@ -0,0 +1,154 @@
+/*
+ * 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 com.android.contacts.R;
+
+import android.app.patterns.CursorLoader;
+import android.content.Context;
+import android.database.Cursor;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Contacts;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ListView;
+import android.widget.TextView;
+
+/**
+ * A cursor adapter for the {@link ContactsContract.Contacts#CONTENT_TYPE} content type loading
+ * a combination of starred and frequently contacted.
+ */
+public class StrequentContactListAdapter extends ContactListAdapter {
+
+ private int mFrequentSeparatorPos;
+ private TextView mSeparatorView;
+
+ public StrequentContactListAdapter(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void configureLoader(CursorLoader loader) {
+ loader.setUri(Contacts.CONTENT_STREQUENT_URI);
+ loader.setProjection(CONTACTS_SUMMARY_PROJECTION);
+ if (getSortOrder() == ContactsContract.Preferences.SORT_ORDER_PRIMARY) {
+ loader.setSortOrder(Contacts.SORT_KEY_PRIMARY);
+ } else {
+ loader.setSortOrder(Contacts.SORT_KEY_ALTERNATIVE);
+ }
+ }
+
+ @Override
+ public void changeCursor(Cursor cursor) {
+ super.changeCursor(cursor);
+
+ // Get the split between starred and frequent items, if the mode is strequent
+ mFrequentSeparatorPos = ListView.INVALID_POSITION;
+ int count = 0;
+ if (cursor != null && (count = cursor.getCount()) > 0) {
+ cursor.moveToPosition(-1);
+ for (int i = 0; cursor.moveToNext(); i++) {
+ int starred = cursor.getInt(SUMMARY_STARRED_COLUMN_INDEX);
+ if (starred == 0) {
+ if (i > 0) {
+ // Only add the separator when there are starred items present
+ mFrequentSeparatorPos = i;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ @Override
+ public int getCount() {
+ if (mFrequentSeparatorPos == ListView.INVALID_POSITION) {
+ return super.getCount();
+ } else {
+ // Add a row for the separator
+ return super.getCount() + 1;
+ }
+ }
+
+ @Override
+ public boolean areAllItemsEnabled() {
+ return mFrequentSeparatorPos == ListView.INVALID_POSITION;
+ }
+
+ @Override
+ public boolean isEnabled(int position) {
+ return position != mFrequentSeparatorPos;
+ }
+
+ @Override
+ public Object getItem(int position) {
+ if (position < mFrequentSeparatorPos) {
+ return super.getItem(position);
+ } else {
+ return super.getItem(position - 1);
+ }
+ }
+
+ @Override
+ public long getItemId(int position) {
+ if (position < mFrequentSeparatorPos) {
+ return super.getItemId(position);
+ } else {
+ return super.getItemId(position - 1);
+ }
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ if (position == mFrequentSeparatorPos) {
+ return IGNORE_ITEM_VIEW_TYPE;
+ }
+
+ return super.getItemViewType(position);
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (position < mFrequentSeparatorPos) {
+ return super.getView(position, convertView, parent);
+ } else if (position == mFrequentSeparatorPos) {
+ if (mSeparatorView == null) {
+ mSeparatorView = (TextView)LayoutInflater.from(getContext()).
+ inflate(R.layout.list_separator, parent, false);
+ mSeparatorView.setText(R.string.favoritesFrquentSeparator);
+ }
+ return mSeparatorView;
+ } else {
+ return super.getView(position - 1, convertView, parent);
+ }
+ }
+
+ @Override
+ public View newView(Context context, Cursor cursor, ViewGroup parent) {
+ final ContactListItemView view = new ContactListItemView(context, null);
+ view.setUnknownNameText(getUnknownNameText());
+ view.setTextWithHighlightingFactory(getTextWithHighlightingFactory());
+ // TODO
+// view.setOnCallButtonClickListener(contactsListActivity);
+ return view;
+ }
+
+ @Override
+ public void bindView(View itemView, Context context, Cursor cursor) {
+ super.bindView(itemView, context, cursor);
+ }
+}
diff --git a/src/com/android/contacts/list/StrequentContactListFragment.java b/src/com/android/contacts/list/StrequentContactListFragment.java
new file mode 100644
index 0000000..fd746ae
--- /dev/null
+++ b/src/com/android/contacts/list/StrequentContactListFragment.java
@@ -0,0 +1,55 @@
+/*
+ * 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 com.android.contacts.R;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Fragment containing a list of starred contacts followed by a list of frequently contacted.
+ */
+public class StrequentContactListFragment extends ContactBrowseListFragment {
+
+ @Override
+ protected void onItemClick(int position, long id) {
+ ContactListAdapter adapter = getAdapter();
+ adapter.moveToPosition(position);
+ viewContact(adapter.getContactUri());
+ }
+
+ @Override
+ protected ContactListAdapter createListAdapter() {
+ StrequentContactListAdapter adapter = new StrequentContactListAdapter(getActivity());
+ adapter.setSectionHeaderDisplayEnabled(false);
+
+ adapter.setContactNameDisplayOrder(getContactNameDisplayOrder());
+ adapter.setSortOrder(getSortOrder());
+
+ adapter.setDisplayPhotos(true);
+ adapter.setQuickContactEnabled(true);
+
+ adapter.configureLoader(getLoader());
+ return adapter;
+ }
+
+ @Override
+ protected View inflateView(LayoutInflater inflater, ViewGroup container) {
+ return inflater.inflate(R.layout.contacts_list_content, null);
+ }
+}
diff --git a/src/com/android/contacts/list/PinnedHeaderListAdapter.java b/src/com/android/contacts/widget/PinnedHeaderListAdapter.java
similarity index 78%
rename from src/com/android/contacts/list/PinnedHeaderListAdapter.java
rename to src/com/android/contacts/widget/PinnedHeaderListAdapter.java
index 27deef3..db99e14 100644
--- a/src/com/android/contacts/list/PinnedHeaderListAdapter.java
+++ b/src/com/android/contacts/widget/PinnedHeaderListAdapter.java
@@ -13,10 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.contacts.list;
-
-import com.android.contacts.R;
-import com.android.contacts.widget.PinnedHeaderListView;
+package com.android.contacts.widget;
import android.content.Context;
import android.content.res.ColorStateList;
@@ -35,22 +32,32 @@
public abstract class PinnedHeaderListAdapter extends CursorAdapter
implements SectionIndexer, PinnedHeaderListView.PinnedHeaderAdapter {
- /**
- * An approximation of the background color of the pinned header. This color
- * is used when the pinned header is being pushed up. At that point the header
- * "fades away". Rather than computing a faded bitmap based on the 9-patch
- * normally used for the background, we will use a solid color, which will
- * provide better performance and reduced complexity.
- */
- private int mPinnedHeaderBackgroundColor;
+ private final int mPinnedHeaderBackgroundColor;
+ private final int mSectionHeaderTextViewId;
+ private final int mSectionHeaderLayoutResId;
private SectionIndexer mIndexer;
- public PinnedHeaderListAdapter(Context context) {
+ /**
+ * Constructor.
+ *
+ * @param context
+ * @param sectionHeaderLayoutResourceId section header layout resource ID
+ * @param sectionHeaderTextViewId section header text view ID
+ * @param backgroundColor An approximation of the background color of the
+ * pinned header. This color is used when the pinned header is
+ * being pushed up. At that point the header "fades away". Rather
+ * than computing a faded bitmap based on the 9-patch normally
+ * used for the background, we will use a solid color, which will
+ * provide better performance and reduced complexity.
+ */
+ public PinnedHeaderListAdapter(Context context, int sectionHeaderLayoutResourceId,
+ int sectionHeaderTextViewId, int backgroundColor) {
super(context, null, false);
this.mContext = context;
- mPinnedHeaderBackgroundColor =
- context.getResources().getColor(R.color.pinned_header_background);
+ mPinnedHeaderBackgroundColor = backgroundColor;
+ mSectionHeaderLayoutResId = sectionHeaderLayoutResourceId;
+ mSectionHeaderTextViewId = sectionHeaderTextViewId;
}
public void setIndexer(SectionIndexer indexer) {
@@ -131,7 +138,7 @@
PinnedHeaderCache cache = (PinnedHeaderCache)header.getTag();
if (cache == null) {
cache = new PinnedHeaderCache();
- cache.titleView = (TextView)header.findViewById(R.id.header_text);
+ cache.titleView = (TextView)header.findViewById(mSectionHeaderTextViewId);
cache.textColor = cache.titleView.getTextColors();
cache.background = header.getBackground();
header.setTag(cache);
@@ -162,6 +169,6 @@
}
public View createPinnedHeaderView(ViewGroup parent) {
- return LayoutInflater.from(mContext).inflate(R.layout.list_section, parent, false);
+ return LayoutInflater.from(mContext).inflate(mSectionHeaderLayoutResId, parent, false);
}
}
diff --git a/src/com/android/contacts/widget/PinnedHeaderListView.java b/src/com/android/contacts/widget/PinnedHeaderListView.java
index 24e5638..80db26f 100644
--- a/src/com/android/contacts/widget/PinnedHeaderListView.java
+++ b/src/com/android/contacts/widget/PinnedHeaderListView.java
@@ -20,6 +20,7 @@
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.ListAdapter;
import android.widget.ListView;
@@ -53,6 +54,11 @@
public static final int PINNED_HEADER_PUSHED_UP = 2;
/**
+ * Creates the pinned header view.
+ */
+ View createPinnedHeaderView(ViewGroup parent);
+
+ /**
* Computes the desired state of the pinned header for the given
* position of the first visible list item. Allowed return values are
* {@link #PINNED_HEADER_GONE}, {@link #PINNED_HEADER_VISIBLE} or
@@ -75,13 +81,14 @@
private PinnedHeaderAdapter mAdapter;
private View mHeaderView;
private boolean mHeaderViewVisible;
-
+ private float mHeaderOffset;
private int mHeaderViewWidth;
-
private int mHeaderViewHeight;
private OnScrollListener mOnScrollListener;
+ private boolean mHeaderViewConfigured;
+
public PinnedHeaderListView(Context context) {
super(context);
}
@@ -105,6 +112,7 @@
if (mHeaderView != null) {
setFadingEdgeLength(0);
}
+ mHeaderViewConfigured = false;
requestLayout();
}
@@ -112,6 +120,8 @@
public void setAdapter(ListAdapter adapter) {
super.setAdapter(adapter);
mAdapter = (PinnedHeaderAdapter)adapter;
+ View headerView = mAdapter.createPinnedHeaderView(this);
+ setPinnedHeaderView(headerView);
}
@Override
@@ -124,7 +134,9 @@
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mHeaderView != null) {
- configureHeaderView(getFirstVisiblePosition());
+ if (!mHeaderViewConfigured) {
+ configureHeaderView(getFirstVisiblePosition() - getHeaderViewsCount());
+ }
measureChild(mHeaderView, widthMeasureSpec, heightMeasureSpec);
mHeaderViewWidth = mHeaderView.getMeasuredWidth();
mHeaderViewHeight = mHeaderView.getMeasuredHeight();
@@ -135,13 +147,16 @@
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (mHeaderView != null) {
+ if (!mHeaderViewConfigured) {
+ configureHeaderView(getFirstVisiblePosition() - getHeaderViewsCount());
+ }
mHeaderView.layout(0, 0, mHeaderViewWidth, mHeaderViewHeight);
}
}
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
int totalItemCount) {
- configureHeaderView(firstVisibleItem);
+ configureHeaderView(firstVisibleItem - getHeaderViewsCount());
if (mOnScrollListener != null) {
mOnScrollListener.onScroll(this, firstVisibleItem, visibleItemCount, totalItemCount);
}
@@ -167,9 +182,7 @@
case PinnedHeaderAdapter.PINNED_HEADER_VISIBLE: {
mAdapter.configurePinnedHeader(mHeaderView, position, MAX_ALPHA);
- if (mHeaderView.getTop() != 0) {
- mHeaderView.layout(0, 0, mHeaderViewWidth, mHeaderViewHeight);
- }
+ mHeaderOffset = 0;
mHeaderViewVisible = true;
break;
}
@@ -177,10 +190,9 @@
case PinnedHeaderAdapter.PINNED_HEADER_PUSHED_UP: {
View firstView = getChildAt(0);
int bottom = firstView.getBottom();
- int itemHeight = firstView.getHeight();
- int headerHeight = mHeaderView.getHeight();
- int y;
+ int headerHeight = mHeaderViewHeight;
int alpha;
+ int y;
if (bottom < headerHeight) {
y = (bottom - headerHeight);
alpha = MAX_ALPHA * (headerHeight + y) / headerHeight;
@@ -189,20 +201,22 @@
alpha = MAX_ALPHA;
}
mAdapter.configurePinnedHeader(mHeaderView, position, alpha);
- if (mHeaderView.getTop() != y) {
- mHeaderView.layout(0, y, mHeaderViewWidth, mHeaderViewHeight + y);
- }
+ mHeaderOffset = y;
mHeaderViewVisible = true;
break;
}
}
+ mHeaderViewConfigured = true;
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (mHeaderViewVisible) {
+ canvas.save();
+ canvas.translate(0, mHeaderOffset);
drawChild(canvas, mHeaderView, getDrawingTime());
+ canvas.restore();
}
}
}