Merge "Group list: Don't reset scroll position during sync"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 56bf4e5..e27445f 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -315,11 +315,17 @@
android:label="@string/activity_title_settings"
android:theme="@style/ContactsPreferencesTheme" />
+ <!-- Used to filter contacts list by account -->
+ <activity
+ android:name=".list.AccountFilterActivity"
+ android:label="@string/activity_title_contacts_filter"
+ android:theme="@style/ContactListFilterTheme" />
+
<!-- Used to select display and sync groups -->
<activity
android:name=".list.CustomContactListFilterActivity"
android:label="@string/custom_list_filter"
- android:theme="@style/CustomContactListFilterTheme" />
+ android:theme="@style/ContactListFilterTheme" />
<activity
android:name=".activities.ShowOrCreateActivity"
diff --git a/res/layout-sw580dp/people_activity.xml b/res/layout-sw580dp/people_activity.xml
index 7301d24..a6d9a37 100644
--- a/res/layout-sw580dp/people_activity.xml
+++ b/res/layout-sw580dp/people_activity.xml
@@ -45,9 +45,9 @@
android:layout_marginLeft="40dip"
android:layout_marginTop="24dip" />
- <!-- Contacts -->
+ <!-- All -->
<fragment
- android:id="@+id/contacts_fragment"
+ android:id="@+id/all_fragment"
class="com.android.contacts.list.DefaultContactBrowseListFragment"
android:layout_height="0dip"
android:layout_width="match_parent"
diff --git a/res/layout/contact_list_filter.xml b/res/layout/contact_list_filter.xml
new file mode 100644
index 0000000..de05cf8
--- /dev/null
+++ b/res/layout/contact_list_filter.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:fillViewport="true">
+
+ <ListView
+ android:id="@android:id/list"
+ android:layout_width="match_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:layout_marginLeft="16dip"
+ android:layout_marginRight="16dip"
+ android:background="?android:attr/dividerHorizontal" />
+</LinearLayout>
diff --git a/res/layout/contact_list_filter_phones_only.xml b/res/layout/contact_list_filter_phones_only.xml
deleted file mode 100644
index 35965da..0000000
--- a/res/layout/contact_list_filter_phones_only.xml
+++ /dev/null
@@ -1,66 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="?android:attr/listPreferredItemHeight"
- android:gravity="center_vertical"
- android:paddingRight="?android:attr/scrollbarSize"
->
-
- <RelativeLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="14dip"
- android:layout_marginRight="6dip"
- android:layout_marginTop="6dip"
- android:layout_marginBottom="6dip"
- android:layout_weight="1"
- >
-
- <TextView
- android:id="@android:id/text1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:textAppearance="?android:attr/textAppearanceMedium"
- />
-
- <TextView
- android:id="@android:id/text2"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@android:id/text1"
- android:layout_alignLeft="@android:id/text1"
- android:maxLines="2"
- android:textAppearance="?android:attr/textAppearanceSmall"
- />
-
- </RelativeLayout>
-
- <CheckBox
- android:id="@android:id/checkbox"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginRight="4dip"
- android:focusable="false"
- android:clickable="false"
- android:gravity="center_vertical"
- android:orientation="vertical" />
-
-</LinearLayout>
diff --git a/res/layout/contacts_list_content.xml b/res/layout/contacts_list_content.xml
index 6792f9c..b92929b 100644
--- a/res/layout/contacts_list_content.xml
+++ b/res/layout/contacts_list_content.xml
@@ -21,6 +21,19 @@
android:layout_height="match_parent"
android:orientation="vertical">
+ <TextView
+ android:id="@+id/account_filter_header"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:gravity="center"
+ android:padding="5dip"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="@android:color/white"
+ android:background="@android:color/black"
+ android:visibility="gone" />
+
<view
class="com.android.contacts.list.ContactEntryListView"
android:id="@android:id/list"
diff --git a/res/layout/custom_action_bar.xml b/res/layout/custom_action_bar.xml
index 2357756..f749586 100644
--- a/res/layout/custom_action_bar.xml
+++ b/res/layout/custom_action_bar.xml
@@ -14,11 +14,20 @@
limitations under the License.
-->
+<!-- Dimensions are set at runtime in ActionBarAdapter -->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
+ android:layout_width="0dip"
+ android:layout_height="0dip" >
+ <!-- To prevent the search view from getting the initial focus. -->
+ <View
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:layout_width="1px"
+ android:layout_height="1px" >
+ <requestFocus />
+ </View>
<SearchView
android:id="@+id/search_view"
android:layout_width="match_parent"
diff --git a/res/layout/people_activity.xml b/res/layout/people_activity.xml
index bcf218b..11431b3 100644
--- a/res/layout/people_activity.xml
+++ b/res/layout/people_activity.xml
@@ -26,9 +26,9 @@
android:layout_height="match_parent"
android:layout_width="match_parent" />
- <!-- Contacts -->
+ <!-- All -->
<fragment
- android:id="@+id/contacts_fragment"
+ android:id="@+id/all_fragment"
class="com.android.contacts.list.DefaultContactBrowseListFragment"
android:layout_height="match_parent"
android:layout_width="match_parent"
diff --git a/res/menu-sw580dp-w720dp/actions.xml b/res/menu-sw580dp-w720dp/actions.xml
index 081065c..d87b091 100644
--- a/res/menu-sw580dp-w720dp/actions.xml
+++ b/res/menu-sw580dp-w720dp/actions.xml
@@ -15,11 +15,6 @@
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
- android:id="@+id/menu_search"
- android:showAsAction="always"
- android:actionViewClass="android.widget.SearchView" />
-
- <item
android:id="@+id/menu_add_contact"
android:icon="@drawable/ic_menu_add_contact_holo_light"
android:title="@string/menu_new_contact_action_bar"
diff --git a/res/menu-sw580dp/actions.xml b/res/menu-sw580dp/actions.xml
index 1d955c1..fea883e 100644
--- a/res/menu-sw580dp/actions.xml
+++ b/res/menu-sw580dp/actions.xml
@@ -15,11 +15,6 @@
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
- android:id="@+id/menu_search"
- android:showAsAction="always"
- android:actionViewClass="android.widget.SearchView" />
-
- <item
android:id="@+id/menu_add_contact"
android:icon="@drawable/ic_menu_add_contact_holo_light"
android:title="@string/menu_new_contact_action_bar"
diff --git a/res/values-sw580dp/dimens.xml b/res/values-sw580dp/dimens.xml
index 0c1e5fb..bcaf1d2 100644
--- a/res/values-sw580dp/dimens.xml
+++ b/res/values-sw580dp/dimens.xml
@@ -33,4 +33,5 @@
<dimen name="list_section_height">37dip</dimen>
<dimen name="directory_header_height">56dip</dimen>
<dimen name="detail_tab_carousel_height">256dip</dimen>
+ <dimen name="search_view_width">400dip</dimen>
</resources>
diff --git a/res/values-sw580dp/donottranslate_config.xml b/res/values-sw580dp/donottranslate_config.xml
index fcb7da9..5ca1af6 100644
--- a/res/values-sw580dp/donottranslate_config.xml
+++ b/res/values-sw580dp/donottranslate_config.xml
@@ -19,4 +19,5 @@
<resources>
<bool name="config_use_two_panes">true</bool>
+ <bool name="always_show_search_view">true</bool>
</resources>
diff --git a/res/values-sw580dp/styles.xml b/res/values-sw580dp/styles.xml
index 32d02be..4f2b073 100644
--- a/res/values-sw580dp/styles.xml
+++ b/res/values-sw580dp/styles.xml
@@ -60,10 +60,11 @@
<item name="list_item_header_text_size">14sp</item>
</style>
- <style name="CustomContactListFilterTheme" parent="@android:Theme.Holo.Light.Dialog">
+ <style name="ContactListFilterTheme" parent="@android:Theme.Holo.Light.Dialog">
+ <item name="android:windowCloseOnTouchOutside">true</item>
</style>
- <style name="CustomContactListFilterView" parent="CustomContactListFilterTheme">
+ <style name="CustomContactListFilterView" parent="ContactListFilterTheme">
<item name="android:layout_width">400dip</item>
<item name="android:layout_height">400dip</item>
</style>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index a0c4845..948d357 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -148,7 +148,7 @@
<!-- Spacing on the left the search field in the action bar -->
<dimen name="action_bar_search_spacing">12dip</dimen>
- <!-- Size of the shortcut icon. 0dip means: use the system default -->
+ <!-- Size of the shortcut icon. 0dip means: use the system default -->
<dimen name="shortcut_icon_size">0dip</dimen>
<!-- Height of list sections (A, B, C) that show the first character of the contacts -->
@@ -181,4 +181,7 @@
<dimen name="dialpad_digits_margin_top">1dip</dimen>
<!-- Just used in landscape mode -->
<dimen name="dialpad_digits_margin_bottom">50dip</dimen>
+
+ <!-- Width of search view in action bar. Use 0dip for MATCH_PARENT -->
+ <dimen name="search_view_width">0dip</dimen>
</resources>
diff --git a/res/values/donottranslate_config.xml b/res/values/donottranslate_config.xml
index e310953..c778212 100644
--- a/res/values/donottranslate_config.xml
+++ b/res/values/donottranslate_config.xml
@@ -103,4 +103,8 @@
<!-- If true, Contacts uses two panes: List and Detail. If false, Details are
shown in their own screens. This flag must be in sync with the layout definitions. -->
<bool name="config_use_two_panes">false</bool>
+
+ <!-- If true, search view on action bar will always be visible. If false, it'll only be
+ visible in search mode. -->
+ <bool name="always_show_search_view">false</bool>
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 6e88440..e17648a 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -296,12 +296,6 @@
<!-- The text displayed when the contacts list is empty while displaying only contacts that have phone numbers -->
<string name="noContactsWithPhoneNumbers">No contacts with phone numbers.</string>
- <!-- The title of the filter to only show contacts with phone numbers -->
- <string name="showFilterPhones">Only contacts with phones</string>
-
- <!-- The description of the filter to only show contacts with phone numbers -->
- <string name="showFilterPhonesDescrip">Only display contacts that have phone numbers</string>
-
<!-- The header over the list of all contacts groups -->
<string name="headerContactGroups">Choose contacts to display</string>
@@ -366,6 +360,9 @@
<!-- Displayed at the top of the contacts showing the zero total number of contacts visible when a group or account is selected [CHAR LIMIT=64]-->
<string name="listTotalAllContactsZeroGroup">No contacts in <xliff:g id="name" example="Friends">%s</xliff:g></string>
+ <!-- Displayed at the top of the contacts showing the account filter selected [CHAR LIMIT=64] -->
+ <string name="listAllContactsInAccount">Contacts in <xliff:g id="name" example="abc@gmail.com">%s</xliff:g></string>
+
<!-- Displayed at the top of the contacts showing the total number of contacts found when "Only contacts with phones" not selected -->
<plurals name="listFoundAllContacts">
<item quantity="one">1 found</item>
@@ -384,8 +381,8 @@
<item quantity="other"><xliff:g id="count">%d</xliff:g> found</item>
</plurals>
- <!-- The description text for the contacts tab. Space is limited for this string, so the shorter the better -->
- <string name="contactsIconLabel">Contacts</string>
+ <!-- The description text for the "all contacts" tab. Space is limited for this string, so the shorter the better -->
+ <string name="contactsAllLabel">All</string>
<!-- The description text for the groups tab. Space is limited for this string, so the shorter the better -->
<string name="contactsGroupsLabel">Groups</string>
@@ -1490,6 +1487,9 @@
<!-- Title of the settings activity [CHAR LIMIT=64] -->
<string name="activity_title_settings">Settings</string>
+ <!-- Title of the activity that allows the uesr to filter the list of contacts displayed according to account [CHAR LIMIT=25] -->
+ <string name="activity_title_contacts_filter">Contacts to display</string>
+
<!-- Menu item for the settings activity [CHAR LIMIT=64] -->
<string name="menu_settings">Settings</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 067a730..914532c 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -227,7 +227,7 @@
<style name="ContactsPreferencesTheme" parent="@android:Theme.Holo.Light">
</style>
- <style name="CustomContactListFilterTheme" parent="@android:Theme">
+ <style name="ContactListFilterTheme" parent="@android:Theme.Holo.Light">
</style>
<style name="ContactPickerLayout" parent="ContactPickerTheme">
@@ -235,7 +235,7 @@
<item name="android:layout_height">match_parent</item>
</style>
- <style name="CustomContactListFilterView" parent="CustomContactListFilterTheme">
+ <style name="CustomContactListFilterView" parent="ContactListFilterTheme">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">match_parent</item>
</style>
diff --git a/src/com/android/contacts/CallDetailActivity.java b/src/com/android/contacts/CallDetailActivity.java
index a4a578f..7f01481 100644
--- a/src/com/android/contacts/CallDetailActivity.java
+++ b/src/com/android/contacts/CallDetailActivity.java
@@ -169,7 +169,7 @@
*
* @param callUri Uri into {@link CallLog.Calls}
*/
- private void updateData(Uri callUri) {
+ private void updateData(final Uri callUri) {
ContentResolver resolver = getContentResolver();
Cursor callCursor = resolver.query(callUri, CALL_LOG_PROJECTION, null, null, null);
try {
@@ -261,15 +261,42 @@
// Build list of various available actions
List<ViewEntry> actions = new ArrayList<ViewEntry>();
- Intent callIntent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
- Uri.fromParts("tel", mNumber, null));
- actions.add(new ViewEntry(android.R.drawable.sym_action_call,
- getString(R.string.menu_callNumber, mNumber), callIntent));
+ final boolean isSipNumber = PhoneNumberUtils.isUriNumber(mNumber);
+ final Uri numberCallUri;
+ if (isSipNumber) {
+ numberCallUri = Uri.fromParts("sip", mNumber, null);
+ } else {
+ numberCallUri = Uri.fromParts("tel", mNumber, null);
+ }
- Intent smsIntent = new Intent(Intent.ACTION_SENDTO,
- Uri.fromParts("sms", mNumber, null));
- actions.add(new ViewEntry(R.drawable.sym_action_sms,
- getString(R.string.menu_sendTextMessage), smsIntent));
+ actions.add(new ViewEntry(android.R.drawable.sym_action_call,
+ getString(R.string.menu_callNumber, mNumber),
+ new Intent(Intent.ACTION_CALL_PRIVILEGED, numberCallUri)));
+
+ if (!isSipNumber) {
+ Intent smsIntent = new Intent(Intent.ACTION_SENDTO,
+ Uri.fromParts("sms", mNumber, null));
+ actions.add(new ViewEntry(R.drawable.sym_action_sms,
+ getString(R.string.menu_sendTextMessage), smsIntent));
+ }
+
+ actions.add(new ViewEntry(android.R.drawable.ic_menu_close_clear_cancel,
+ getString(R.string.recentCalls_removeFromRecentList),
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ long id = ContentUris.parseId(callUri);
+ getContentResolver().delete(Calls.CONTENT_URI_WITH_VOICEMAIL,
+ Calls._ID + " = ?", new String[]{Long.toString(id)});
+ finish();
+ }
+ }));
+
+ if (!isSipNumber) {
+ actions.add(new ViewEntry(android.R.drawable.sym_action_call,
+ getString(R.string.recentCalls_editNumberBeforeCall),
+ new Intent(Intent.ACTION_DIAL, numberCallUri)));
+ }
ViewAdapter adapter = new ViewAdapter(this, actions);
setListAdapter(adapter);
@@ -317,9 +344,11 @@
}
static final class ViewEntry {
- public int icon = -1;
- public String text = null;
- public Intent intent = null;
+ public final int icon;
+ public final String text;
+ public final Intent intent;
+ public final View.OnClickListener action;
+
public String label = null;
public String number = null;
@@ -327,6 +356,14 @@
this.icon = icon;
this.text = text;
this.intent = intent;
+ this.action = null;
+ }
+
+ public ViewEntry(int icon, String text, View.OnClickListener listener) {
+ this.icon = icon;
+ this.text = text;
+ this.intent = null;
+ this.action = listener;
}
}
@@ -404,6 +441,8 @@
ViewEntry entry = (ViewEntry) view.getTag();
if (entry.intent != null) {
startActivity(entry.intent);
+ } else if (entry.action != null) {
+ entry.action.onClick(view);
}
}
}
diff --git a/src/com/android/contacts/ContactPhotoManager.java b/src/com/android/contacts/ContactPhotoManager.java
index e61d379..fe73fbe 100644
--- a/src/com/android/contacts/ContactPhotoManager.java
+++ b/src/com/android/contacts/ContactPhotoManager.java
@@ -66,11 +66,12 @@
* the available authenticators. This method can safely be called from the UI thread.
*/
public static ContactPhotoManager getInstance(Context context) {
+ Context applicationContext = context.getApplicationContext();
ContactPhotoManager service =
- (ContactPhotoManager) context.getSystemService(CONTACT_PHOTO_SERVICE);
+ (ContactPhotoManager) applicationContext.getSystemService(CONTACT_PHOTO_SERVICE);
if (service == null) {
- service = createContactPhotoManager(context);
- Log.e(TAG, "No contact photo service in context: " + context);
+ service = createContactPhotoManager(applicationContext);
+ Log.e(TAG, "No contact photo service in context: " + applicationContext);
}
return service;
}
diff --git a/src/com/android/contacts/GroupMetaDataLoader.java b/src/com/android/contacts/GroupMetaDataLoader.java
index d900825..8533bb6 100644
--- a/src/com/android/contacts/GroupMetaDataLoader.java
+++ b/src/com/android/contacts/GroupMetaDataLoader.java
@@ -34,6 +34,7 @@
Groups.AUTO_ADD,
Groups.FAVORITES,
Groups.GROUP_IS_READ_ONLY,
+ Groups.DELETED,
};
public final static int ACCOUNT_NAME = 0;
@@ -43,6 +44,7 @@
public final static int AUTO_ADD = 4;
public final static int FAVORITES = 5;
public final static int IS_READ_ONLY = 6;
+ public final static int DELETED = 7;
public GroupMetaDataLoader(Context context, Uri groupUri) {
super(context, ensureIsGroupUri(groupUri), COLUMNS, Groups.ACCOUNT_TYPE + " NOT NULL AND "
diff --git a/src/com/android/contacts/activities/ActionBarAdapter.java b/src/com/android/contacts/activities/ActionBarAdapter.java
index 073f665..51ed1e8 100644
--- a/src/com/android/contacts/activities/ActionBarAdapter.java
+++ b/src/com/android/contacts/activities/ActionBarAdapter.java
@@ -18,8 +18,6 @@
import com.android.contacts.R;
import com.android.contacts.activities.ActionBarAdapter.Listener.Action;
-import com.android.contacts.list.ContactListFilterController;
-import com.android.contacts.list.ContactListFilterController.ContactListFilterListener;
import com.android.contacts.list.ContactsRequest;
import android.app.ActionBar;
@@ -36,8 +34,7 @@
/**
* Adapter for the action bar at the top of the Contacts activity.
*/
-public class ActionBarAdapter
- implements OnQueryTextListener, OnCloseListener, ContactListFilterListener {
+public class ActionBarAdapter implements OnQueryTextListener, OnCloseListener {
public interface Listener {
public enum Action {
@@ -58,27 +55,23 @@
private SearchView mSearchView;
private final Context mContext;
+ private final boolean mAlwaysShowSearchView;
private Listener mListener;
- private ContactListFilterController mFilterController;
private ActionBar mActionBar;
- private View mCustomSearchView;
- private LayoutParams mLayoutParams;
- private boolean mIsSearchInOverflowMenu;
public ActionBarAdapter(Context context, Listener listener) {
mContext = context;
mListener = listener;
mSearchLabelText = mContext.getString(R.string.search_label);
+ mAlwaysShowSearchView = mContext.getResources().getBoolean(R.bool.always_show_search_view);
}
- public void onCreate(Bundle savedState, ContactsRequest request, ActionBar actionBar,
- boolean searchInOverflowMenu) {
+ public void onCreate(Bundle savedState, ContactsRequest request, ActionBar actionBar) {
mActionBar = actionBar;
mQueryString = null;
- mIsSearchInOverflowMenu = searchInOverflowMenu;
if (savedState != null) {
mSearchMode = savedState.getBoolean(EXTRA_KEY_SEARCH_MODE);
@@ -88,33 +81,29 @@
mQueryString = request.getQueryString();
}
- if (mSearchView != null) {
- mSearchView.setQuery(mQueryString, false);
+ // Set up search view.
+ View customSearchView = LayoutInflater.from(mContext).inflate(R.layout.custom_action_bar,
+ null);
+ int searchViewWidth = mContext.getResources().getDimensionPixelSize(
+ R.dimen.search_view_width);
+ if (searchViewWidth == 0) {
+ searchViewWidth = LayoutParams.MATCH_PARENT;
}
+ LayoutParams layoutParams = new LayoutParams(searchViewWidth, LayoutParams.WRAP_CONTENT);
+ mSearchView = (SearchView) customSearchView.findViewById(R.id.search_view);
+ mSearchView.setQueryHint(mContext.getString(R.string.hint_findContacts));
+ mSearchView.setOnQueryTextListener(this);
+ mSearchView.setOnCloseListener(this);
+ mSearchView.setQuery(mQueryString, false);
+ mActionBar.setCustomView(customSearchView, layoutParams);
update();
}
- public void setSearchView(SearchView searchView) {
- mSearchView = searchView;
- mSearchView.setOnQueryTextListener(this);
- mSearchView.setOnCloseListener(this);
- mSearchView.setQuery(mQueryString, false);
- }
-
public void setListener(Listener listener) {
mListener = listener;
}
- public void setContactListFilterController(ContactListFilterController controller) {
- mFilterController = controller;
- mFilterController.addListener(this);
- }
-
- public boolean isSearchInOverflowMenu() {
- return mIsSearchInOverflowMenu;
- }
-
public boolean isSearchMode() {
return mSearchMode;
}
@@ -127,7 +116,7 @@
return;
}
if (mSearchMode) {
- mSearchView.requestFocus();
+ setFocusOnSearchView();
} else {
mSearchView.setQuery(null, false);
}
@@ -147,31 +136,20 @@
public void update() {
if (mSearchMode) {
- // If the search icon was in the overflow menu, then inflate a custom view containing
- // a search view for the action bar (and hide the tabs).
- if (mIsSearchInOverflowMenu) {
- if (mCustomSearchView == null) {
- mCustomSearchView = LayoutInflater.from(mContext).inflate(
- R.layout.custom_action_bar, null);
- mLayoutParams = new LayoutParams(LayoutParams.MATCH_PARENT,
- LayoutParams.WRAP_CONTENT);
- SearchView searchView = (SearchView) mCustomSearchView.
- findViewById(R.id.search_view);
- searchView.setQueryHint(mContext.getString(R.string.hint_findContacts));
- setSearchView(searchView);
- }
- mActionBar.setDisplayShowCustomEnabled(true);
- mActionBar.setCustomView(mCustomSearchView, mLayoutParams);
- mSearchView.requestFocus();
- } else {
+ mActionBar.setDisplayShowCustomEnabled(true);
+ if (mAlwaysShowSearchView) {
+ // Tablet -- change the app title for the search mode
mActionBar.setTitle(mSearchLabelText);
+ } else {
+ // Phone -- search view gets focus
+ setFocusOnSearchView();
}
mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
if (mListener != null) {
mListener.onAction(Action.START_SEARCH_MODE);
}
} else {
- mActionBar.setDisplayShowCustomEnabled(false);
+ mActionBar.setDisplayShowCustomEnabled(mAlwaysShowSearchView);
mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
mActionBar.setTitle(null);
if (mListener != null) {
@@ -223,17 +201,8 @@
mActionBar.setSelectedNavigationItem(savedState.getInt(EXTRA_KEY_SELECTED_TAB));
}
- @Override
- public void onContactListFiltersLoaded() {
- update();
- }
-
- @Override
- public void onContactListFilterChanged() {
- update();
- }
-
- @Override
- public void onContactListFilterCustomizationRequest() {
+ private void setFocusOnSearchView() {
+ mSearchView.requestFocus();
+ mSearchView.setIconified(false); // Workaround for the "IME not popping up" issue.
}
}
diff --git a/src/com/android/contacts/activities/GroupDetailActivity.java b/src/com/android/contacts/activities/GroupDetailActivity.java
index 21900c6..c8f511b 100644
--- a/src/com/android/contacts/activities/GroupDetailActivity.java
+++ b/src/com/android/contacts/activities/GroupDetailActivity.java
@@ -43,6 +43,7 @@
R.id.group_detail_fragment);
fragment.setListener(mFragmentListener);
fragment.loadGroup(getIntent().getData());
+ fragment.closeActivityAfterDelete(true);
ActionBar actionBar = getActionBar();
if (actionBar != null) {
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index d5bdd61..3488bed 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -32,6 +32,7 @@
import com.android.contacts.interactions.ContactDeletionInteraction;
import com.android.contacts.interactions.ImportExportDialogFragment;
import com.android.contacts.interactions.PhoneNumberInteraction;
+import com.android.contacts.list.AccountFilterActivity;
import com.android.contacts.list.ContactBrowseListContextMenuAdapter;
import com.android.contacts.list.ContactBrowseListFragment;
import com.android.contacts.list.ContactEntryListFragment;
@@ -108,7 +109,8 @@
private static final int SUBACTIVITY_EDIT_CONTACT = 3;
private static final int SUBACTIVITY_NEW_GROUP = 4;
private static final int SUBACTIVITY_EDIT_GROUP = 5;
- private static final int SUBACTIVITY_CUSTOMIZE_FILTER = 6;
+ private static final int SUBACTIVITY_ACCOUNT_FILTER = 6;
+ private static final int SUBACTIVITY_CUSTOMIZE_FILTER = 7;
private static final String KEY_SEARCH_MODE = "searchMode";
@@ -121,8 +123,6 @@
private boolean mSearchMode;
- private ContactBrowseListFragment mListFragment;
-
/**
* Whether we have a right-side contact or group detail pane for displaying info on that
* contact or group while browsing. Generally means "this is a tablet".
@@ -155,7 +155,10 @@
private boolean mOptionsMenuContactsAvailable;
- private DefaultContactBrowseListFragment mContactsFragment;
+ /**
+ * Showing a list of Contacts. Also used for showing search results in search mode.
+ */
+ private DefaultContactBrowseListFragment mAllFragment;
private StrequentContactListFragment mFavoritesFragment;
private StrequentContactListFragment mFrequentFragment;
private GroupBrowseListFragment mGroupsFragment;
@@ -168,18 +171,39 @@
private ContactDetailLayoutController mContactDetailLayoutController;
- private Handler mHandler = new Handler();
+ private final Handler mHandler = new Handler();
+
+ /**
+ * TODO: Use ViewPager so that tabs can be swiped left and right. Figure out how to use the
+ * support library in our app.
+ */
+ private final TabListener mTabListener = new TabListener() {
+ @Override
+ public void onTabUnselected(Tab tab, FragmentTransaction ft) {
+ hideFragmentOnTabUnselect((TabState) tab.getTag(), ft);
+ }
+
+ @Override
+ public void onTabSelected(Tab tab, FragmentTransaction ft) {
+ final TabState tabState = (TabState) tab.getTag();
+ setSelectedTab(tabState);
+ showFragmentOnTabSelect(tabState, ft);
+ invalidateOptionsMenu();
+ }
+
+ @Override
+ public void onTabReselected(Tab tab, FragmentTransaction ft) {
+ }
+ };
private enum TabState {
- FAVORITES, CONTACTS, GROUPS
+ FAVORITES, ALL, GROUPS
}
private TabState mSelectedTab;
public PeopleActivity() {
mIntentResolver = new ContactsIntentResolver(this);
- // TODO: Get rid of the ContactListFilterController class because there aren't any
- // dropdown filters anymore. Just store the selected filter as a member variable.
mContactListFilterController = new ContactListFilterController(this);
mContactListFilterController.addListener(this);
mProviderStatusLoader = new ProviderStatusLoader(this);
@@ -191,12 +215,12 @@
@Override
public void onAttachFragment(Fragment fragment) {
- if (fragment instanceof ContactBrowseListFragment) {
- mListFragment = (ContactBrowseListFragment)fragment;
- mListFragment.setOnContactListActionListener(new ContactBrowserActionListener());
+ if (fragment instanceof DefaultContactBrowseListFragment) {
+ mAllFragment = (DefaultContactBrowseListFragment)fragment;
+ mAllFragment.setOnContactListActionListener(new ContactBrowserActionListener());
if (!getWindow().hasFeature(Window.FEATURE_ACTION_BAR)) {
- mListFragment.setContextMenuAdapter(
- new ContactBrowseListContextMenuAdapter(mListFragment));
+ mAllFragment.setContextMenuAdapter(
+ new ContactBrowseListContextMenuAdapter(mAllFragment));
}
} else if (fragment instanceof GroupBrowseListFragment) {
mGroupsFragment = (GroupBrowseListFragment) fragment;
@@ -269,13 +293,13 @@
.findFragmentById(R.id.favorites_fragment);
mFrequentFragment = (StrequentContactListFragment) fragmentManager
.findFragmentById(R.id.frequent_fragment);
- mContactsFragment = (DefaultContactBrowseListFragment) fragmentManager
- .findFragmentById(R.id.contacts_fragment);
+ mAllFragment = (DefaultContactBrowseListFragment) fragmentManager
+ .findFragmentById(R.id.all_fragment);
mGroupsFragment = (GroupBrowseListFragment) fragmentManager
.findFragmentById(R.id.groups_fragment);
// Hide all tabs (the current tab will later be reshown once a tab is selected)
final FragmentTransaction transaction = fragmentManager.beginTransaction();
- transaction.hide(mContactsFragment);
+ transaction.hide(mAllFragment);
transaction.hide(mGroupsFragment);
if (mFrequentFragment != null) {
@@ -303,8 +327,7 @@
setTitle(mRequest.getActivityTitle());
ActionBar actionBar = getActionBar();
mActionBarAdapter = new ActionBarAdapter(this, this);
- mActionBarAdapter.onCreate(savedState, mRequest, getActionBar(), !mContentPaneDisplayed);
- mActionBarAdapter.setContactListFilterController(mContactListFilterController);
+ mActionBarAdapter.onCreate(savedState, mRequest, getActionBar());
ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
ContactDetailTabCarousel tabCarousel = (ContactDetailTabCarousel)
@@ -316,21 +339,21 @@
if (createContentView) {
actionBar.removeAllTabs();
Tab favoritesTab = actionBar.newTab();
- favoritesTab.setText(getString(R.string.strequentList));
- favoritesTab.setTabListener(new TabChangeListener(mFavoritesFragment,
- mFrequentFragment, TabState.FAVORITES));
+ favoritesTab.setTag(TabState.FAVORITES);
+ favoritesTab.setText(getString(R.string.contactsFavoritesLabel));
+ favoritesTab.setTabListener(mTabListener);
actionBar.addTab(favoritesTab);
- Tab peopleTab = actionBar.newTab();
- peopleTab.setText(getString(R.string.people));
- peopleTab.setTabListener(new TabChangeListener(mContactsFragment,
- mContactDetailLoaderFragment, TabState.CONTACTS));
- actionBar.addTab(peopleTab);
+ Tab allTab = actionBar.newTab();
+ allTab.setTag(TabState.ALL);
+ allTab.setText(getString(R.string.contactsAllLabel));
+ allTab.setTabListener(mTabListener);
+ actionBar.addTab(allTab);
Tab groupsTab = actionBar.newTab();
+ groupsTab.setTag(TabState.GROUPS);
groupsTab.setText(getString(R.string.contactsGroupsLabel));
- groupsTab.setTabListener(new TabChangeListener(mGroupsFragment,
- mGroupDetailFragment, TabState.GROUPS));
+ groupsTab.setTabListener(mTabListener);
actionBar.addTab(groupsTab);
actionBar.setDisplayShowTitleEnabled(true);
@@ -344,47 +367,61 @@
configureFragments(savedState == null);
}
- /**
- * Tab change listener that is instantiated once for each tab. Handles showing/hiding fragments.
- * TODO: Use ViewPager so that tabs can be swiped left and right. Figure out how to use the
- * support library in our app.
- */
- private class TabChangeListener implements TabListener {
- private final Fragment mBrowseListFragment;
-
- /**
- * Right pane fragment that is present on larger screen sizes (can be
- * null for smaller screen sizes).
- */
- private final Fragment mDetailFragment;
- private final TabState mTabState;
-
- public TabChangeListener(Fragment listFragment, Fragment detailFragment, TabState state) {
- mBrowseListFragment = listFragment;
- mDetailFragment = detailFragment;
- mTabState = state;
- }
-
- @Override
- public void onTabUnselected(Tab tab, FragmentTransaction ft) {
- ft.hide(mBrowseListFragment);
- if (mDetailFragment != null) {
- ft.hide(mDetailFragment);
+ private void hideFragmentOnTabUnselect(TabState newTabState, FragmentTransaction ft) {
+ switch (newTabState) {
+ case FAVORITES: {
+ ft.hide(mFavoritesFragment);
+ if (mFrequentFragment != null) {
+ ft.hide(mFrequentFragment);
+ }
+ break;
+ }
+ case ALL: {
+ ft.hide(mAllFragment);
+ if (mContactDetailFragment != null) {
+ ft.hide(mContactDetailFragment);
+ }
+ break;
+ }
+ case GROUPS: {
+ ft.hide(mGroupsFragment);
+ if (mGroupDetailFragment != null) {
+ ft.hide(mGroupDetailFragment);
+ }
+ break;
+ }
+ default: {
+ throw new IllegalStateException("Unexpected tab state: " + newTabState);
}
}
+ }
- @Override
- public void onTabSelected(Tab tab, FragmentTransaction ft) {
- ft.show(mBrowseListFragment);
- if (mDetailFragment != null) {
- ft.show(mDetailFragment);
+ private void showFragmentOnTabSelect(TabState newTabState, FragmentTransaction ft) {
+ switch (newTabState) {
+ case FAVORITES: {
+ ft.show(mFavoritesFragment);
+ if (mFrequentFragment != null) {
+ ft.show(mFrequentFragment);
+ }
+ break;
}
- setSelectedTab(mTabState);
- invalidateOptionsMenu();
- }
-
- @Override
- public void onTabReselected(Tab tab, FragmentTransaction ft) {
+ case ALL: {
+ ft.show(mAllFragment);
+ if (mContactDetailFragment != null) {
+ ft.show(mContactDetailFragment);
+ }
+ break;
+ }
+ case GROUPS: {
+ ft.show(mGroupsFragment);
+ if (mGroupDetailFragment != null) {
+ ft.show(mGroupDetailFragment);
+ }
+ break;
+ }
+ default: {
+ throw new IllegalStateException("Unexpected tab state: " + newTabState);
+ }
}
}
@@ -399,7 +436,7 @@
mDetailsView.setVisibility(View.GONE);
break;
case GROUPS:
- case CONTACTS:
+ case ALL:
mFavoritesView.setVisibility(View.GONE);
mBrowserView.setVisibility(View.VISIBLE);
mDetailsView.setVisibility(View.VISIBLE);
@@ -475,7 +512,7 @@
mSearchMode = false;
}
- mListFragment.setContactsRequest(mRequest);
+ mAllFragment.setContactsRequest(mRequest);
configureContactListFragmentForRequest();
} else {
@@ -489,33 +526,16 @@
}
@Override
- public void onContactListFiltersLoaded() {
- if (mListFragment == null || !mListFragment.isAdded()) {
- return;
- }
-
- mListFragment.setFilter(mContactListFilterController.getFilter());
-
- invalidateOptionsMenuIfNeeded();
- }
-
- @Override
public void onContactListFilterChanged() {
- if (mListFragment == null || !mListFragment.isAdded()) {
+ if (mAllFragment == null || !mAllFragment.isAdded()) {
return;
}
- mListFragment.setFilter(mContactListFilterController.getFilter());
+ mAllFragment.setFilter(mContactListFilterController.getFilter());
invalidateOptionsMenuIfNeeded();
}
- @Override
- public void onContactListFilterCustomizationRequest() {
- startActivityForResult(new Intent(this, CustomContactListFilterActivity.class),
- SUBACTIVITY_CUSTOMIZE_FILTER);
- }
-
private void setupContactDetailFragment(final Uri contactLookupUri) {
mContactDetailLoaderFragment.loadUri(contactLookupUri);
invalidateOptionsMenuIfNeeded();
@@ -541,7 +561,7 @@
}
// Bring the contact list fragment (and detail fragment if applicable) to the front
FragmentTransaction ft = getFragmentManager().beginTransaction();
- ft.show(mContactsFragment);
+ ft.show(mAllFragment);
if (mContactDetailFragment != null) ft.show(mContactDetailFragment);
ft.commit();
clearSearch();
@@ -553,9 +573,9 @@
// If the last selected tab was not the "All contacts" tab, then hide these
// fragments because we need to show favorites or groups.
- if (mSelectedTab != null && !mSelectedTab.equals(TabState.CONTACTS)) {
+ if (mSelectedTab != null && !mSelectedTab.equals(TabState.ALL)) {
FragmentTransaction transaction = getFragmentManager().beginTransaction();
- transaction.hide(mContactsFragment);
+ transaction.hide(mAllFragment);
if (mContactDetailFragment != null) transaction.hide(mContactDetailFragment);
transaction.commit();
}
@@ -575,39 +595,39 @@
private void loadSearch(String query) {
configureFragments(false /* from request */);
- mListFragment.setQueryString(query, true);
+ mAllFragment.setQueryString(query, true);
}
private void configureContactListFragmentForRequest() {
Uri contactUri = mRequest.getContactUri();
if (contactUri != null) {
- mListFragment.setSelectedContactUri(contactUri);
+ mAllFragment.setSelectedContactUri(contactUri);
}
- mListFragment.setSearchMode(mRequest.isSearchMode());
- mListFragment.setQueryString(mRequest.getQueryString(), false);
+ mAllFragment.setSearchMode(mRequest.isSearchMode());
+ mAllFragment.setQueryString(mRequest.getQueryString(), false);
if (mRequest.isDirectorySearchEnabled()) {
- mListFragment.setDirectorySearchMode(DirectoryListLoader.SEARCH_MODE_DEFAULT);
+ mAllFragment.setDirectorySearchMode(DirectoryListLoader.SEARCH_MODE_DEFAULT);
} else {
- mListFragment.setDirectorySearchMode(DirectoryListLoader.SEARCH_MODE_NONE);
+ mAllFragment.setDirectorySearchMode(DirectoryListLoader.SEARCH_MODE_NONE);
}
- if (mContactListFilterController.isLoaded()) {
- mListFragment.setFilter(mContactListFilterController.getFilter());
+ if (mContactListFilterController.isInitialized()) {
+ mAllFragment.setFilter(mContactListFilterController.getFilter());
}
}
private void configureContactListFragment() {
- mListFragment.setSearchMode(mSearchMode);
+ mAllFragment.setSearchMode(mSearchMode);
- mListFragment.setVisibleScrollbarEnabled(!mSearchMode);
- mListFragment.setVerticalScrollbarPosition(
+ mAllFragment.setVisibleScrollbarEnabled(!mSearchMode);
+ mAllFragment.setVerticalScrollbarPosition(
mContentPaneDisplayed
? View.SCROLLBAR_POSITION_LEFT
: View.SCROLLBAR_POSITION_RIGHT);
- mListFragment.setSelectionVisible(mContentPaneDisplayed);
- mListFragment.setQuickContactEnabled(!mContentPaneDisplayed);
+ mAllFragment.setSelectionVisible(mContentPaneDisplayed);
+ mAllFragment.setQuickContactEnabled(!mContentPaneDisplayed);
}
private void configureGroupListFragment() {
@@ -639,12 +659,12 @@
if (mainView != null) {
mainView.setVisibility(View.VISIBLE);
}
- if (mListFragment != null) {
- mListFragment.setEnabled(true);
+ if (mAllFragment != null) {
+ mAllFragment.setEnabled(true);
}
} else {
- if (mListFragment != null) {
- mListFragment.setEnabled(false);
+ if (mAllFragment != null) {
+ mAllFragment.setEnabled(false);
}
if (mContactsUnavailableFragment == null) {
mContactsUnavailableFragment = new ContactsUnavailableFragment();
@@ -671,7 +691,7 @@
@Override
public void onSelectionChange() {
if (mContentPaneDisplayed) {
- setupContactDetailFragment(mListFragment.getSelectedContactUri());
+ setupContactDetailFragment(mAllFragment.getSelectedContactUri());
}
}
@@ -741,16 +761,16 @@
@Override
public void onInvalidSelection() {
ContactListFilter filter;
- ContactListFilter currentFilter = mListFragment.getFilter();
+ ContactListFilter currentFilter = mAllFragment.getFilter();
if (currentFilter != null
&& currentFilter.filterType == ContactListFilter.FILTER_TYPE_SINGLE_CONTACT) {
filter = ContactListFilter.createFilterWithType(
ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS);
- mListFragment.setFilter(filter);
+ mAllFragment.setFilter(filter);
} else {
filter = ContactListFilter.createFilterWithType(
ContactListFilter.FILTER_TYPE_SINGLE_CONTACT);
- mListFragment.setFilter(filter, false);
+ mAllFragment.setFilter(filter, false);
}
mContactListFilterController.setContactListFilter(filter, true);
}
@@ -935,16 +955,6 @@
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.actions, menu);
- MenuItem searchMenuItem = menu.findItem(R.id.menu_search);
- if (searchMenuItem != null && searchMenuItem.getActionView() instanceof SearchView) {
- SearchView searchView = (SearchView) searchMenuItem.getActionView();
- searchView.setQueryHint(getString(R.string.hint_findContacts));
- searchView.setIconifiedByDefault(false);
-
- if (mActionBarAdapter != null) {
- mActionBarAdapter.setSearchView(searchView);
- }
- }
// On narrow screens we specify a NEW group button in the {@link ActionBar}, so that
// it can be in the overflow menu. On wide screens, we use a custom view because we need
@@ -976,7 +986,7 @@
return true;
}
- if (mListFragment != null && mListFragment.isOptionsMenuChanged()) {
+ if (mAllFragment != null && mAllFragment.isOptionsMenuChanged()) {
return true;
}
@@ -1009,17 +1019,15 @@
if (mActionBarAdapter.isSearchMode()) {
addContactMenu.setVisible(false);
addGroupMenu.setVisible(false);
- // If search is normally in the overflow menu, when we are in search
- // mode, hide this option.
- if (mActionBarAdapter.isSearchInOverflowMenu()) {
- searchMenu.setVisible(false);
+ if (searchMenu != null) {
+ searchMenu.setVisible(false); // Don't show the search menu in search mode.
}
} else {
switch (mSelectedTab) {
case FAVORITES:
// TODO: Fall through until we determine what the menu items should be for
// this tab
- case CONTACTS:
+ case ALL:
addContactMenu.setVisible(true);
addGroupMenu.setVisible(false);
break;
@@ -1047,8 +1055,8 @@
return true;
}
case R.id.menu_contacts_filter: {
- final Intent intent = new Intent(this, CustomContactListFilterActivity.class);
- startActivityForResult(intent, SUBACTIVITY_CUSTOMIZE_FILTER);
+ final Intent intent = new Intent(this, AccountFilterActivity.class);
+ startActivityForResult(intent, SUBACTIVITY_ACCOUNT_FILTER);
return true;
}
case R.id.menu_search: {
@@ -1117,8 +1125,8 @@
@Override
public void startSearch(String initialQuery, boolean selectInitialQuery, Bundle appSearchData,
boolean globalSearch) {
- if (mListFragment != null && mListFragment.isAdded() && !globalSearch) {
- mListFragment.startSearch(initialQuery);
+ if (mAllFragment != null && mAllFragment.isAdded() && !globalSearch) {
+ mAllFragment.startSearch(initialQuery);
} else {
super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch);
}
@@ -1127,18 +1135,35 @@
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
+ case SUBACTIVITY_ACCOUNT_FILTER: {
+ if (resultCode == Activity.RESULT_OK) {
+ ContactListFilter filter = (ContactListFilter) data.getParcelableExtra(
+ AccountFilterActivity.KEY_EXTRA_CONTACT_LIST_FILTER);
+ if (filter == null) {
+ return;
+ }
+ // If this is a custom filter, launch the activity to customize the display list
+ if (filter.filterType == ContactListFilter.FILTER_TYPE_CUSTOM) {
+ final Intent intent = new Intent(this,
+ CustomContactListFilterActivity.class);
+ startActivityForResult(intent, SUBACTIVITY_CUSTOMIZE_FILTER);
+ } else {
+ mContactListFilterController.setContactListFilter(filter, true);
+ }
+ }
+ break;
+ }
case SUBACTIVITY_CUSTOMIZE_FILTER: {
if (resultCode == Activity.RESULT_OK) {
mContactListFilterController.selectCustomFilter();
}
break;
}
-
case SUBACTIVITY_EDIT_CONTACT:
case SUBACTIVITY_NEW_CONTACT: {
if (resultCode == RESULT_OK && mContentPaneDisplayed) {
mRequest.setActionCode(ContactsRequest.ACTION_VIEW_CONTACT);
- mListFragment.reloadDataAndSetSelectedUri(data.getData());
+ mAllFragment.reloadDataAndSetSelectedUri(data.getData());
}
break;
}
@@ -1156,7 +1181,7 @@
// anymore
case ContactEntryListFragment.ACTIVITY_REQUEST_CODE_PICKER:
if (resultCode == RESULT_OK) {
- mListFragment.onPickerResult(data);
+ mAllFragment.onPickerResult(data);
}
// TODO fix or remove multipicker code
@@ -1171,7 +1196,7 @@
@Override
public boolean onContextItemSelected(MenuItem item) {
- ContextMenuAdapter menuAdapter = mListFragment.getContextMenuAdapter();
+ ContextMenuAdapter menuAdapter = mAllFragment.getContextMenuAdapter();
if (menuAdapter != null) {
return menuAdapter.onContextItemSelected(item);
}
@@ -1274,7 +1299,7 @@
// Visible for testing
public ContactBrowseListFragment getListFragment() {
- return mListFragment;
+ return mAllFragment;
}
// Visible for testing
diff --git a/src/com/android/contacts/calllog/CallLogFragment.java b/src/com/android/contacts/calllog/CallLogFragment.java
index 9dc50f2..84e6a8a 100644
--- a/src/com/android/contacts/calllog/CallLogFragment.java
+++ b/src/com/android/contacts/calllog/CallLogFragment.java
@@ -176,8 +176,25 @@
/** Adapter class to fill in data for the Call Log */
public final class CallLogAdapter extends GroupingListAdapter
implements Runnable, ViewTreeObserver.OnPreDrawListener, View.OnClickListener {
+ /** The time in millis to delay starting the thread processing requests. */
+ private static final int START_PROCESSING_REQUESTS_DELAY_MILLIS = 1000;
+
+ /**
+ * A cache of the contact details for the phone numbers in the call log.
+ * <p>
+ * The content of the cache is expired (but not purged) whenever the application comes to
+ * the foreground.
+ */
private ExpirableCache<String, ContactInfo> mContactInfoCache;
+
+ /**
+ * List of requests to update contact details.
+ * <p>
+ * The requests are added when displaying the contacts and are processed by a background
+ * thread.
+ */
private final LinkedList<CallerInfoQuery> mRequests;
+
private volatile boolean mDone;
private boolean mLoading = true;
private ViewTreeObserver.OnPreDrawListener mPreDrawListener;
@@ -220,7 +237,8 @@
@Override
public boolean onPreDraw() {
if (mFirst) {
- mHandler.sendEmptyMessageDelayed(START_THREAD, 1000);
+ mHandler.sendEmptyMessageDelayed(START_THREAD,
+ START_PROCESSING_REQUESTS_DELAY_MILLIS);
mFirst = false;
}
return true;
@@ -234,9 +252,7 @@
notifyDataSetChanged();
break;
case START_THREAD:
- if (!mRequestProcessingDisabled) {
- startRequestProcessing();
- }
+ startRequestProcessing();
break;
}
}
@@ -296,6 +312,10 @@
}
public void startRequestProcessing() {
+ if (mRequestProcessingDisabled) {
+ return;
+ }
+
mDone = false;
mCallerIdThread = new Thread(this);
mCallerIdThread.setPriority(Thread.MIN_PRIORITY);
@@ -346,7 +366,7 @@
}
}
- private void enqueueRequest(String number, int position,
+ private void enqueueRequest(String number, boolean immediate, int position,
String name, int numberType, String numberLabel, long photoId, String lookupKey) {
CallerInfoQuery ciq = new CallerInfoQuery();
ciq.number = number;
@@ -360,6 +380,10 @@
mRequests.add(ciq);
mRequests.notifyAll();
}
+ if (mFirst && immediate) {
+ startRequestProcessing();
+ mFirst = false;
+ }
}
private boolean queryContactInfo(CallerInfoQuery ciq) {
@@ -675,7 +699,8 @@
info = ContactInfo.EMPTY;
mContactInfoCache.put(number, info);
Log.d(TAG, "Contact info missing: " + number);
- enqueueRequest(number, c.getPosition(),
+ // Request the contact details immediately since they are currently missing.
+ enqueueRequest(number, true, c.getPosition(),
callerName, callerNumberType, callerNumberLabel, 0L, "");
} else if (info != ContactInfo.EMPTY) { // Has been queried
// Check if any data is different from the data cached in the
@@ -686,7 +711,8 @@
|| !TextUtils.equals(info.label, callerNumberLabel)) {
// Something is amiss, so sync up.
Log.w(TAG, "Contact info inconsistent: " + number);
- enqueueRequest(number, c.getPosition(),
+ // Request the contact details immediately since they are probably wrong.
+ enqueueRequest(number, true, c.getPosition(),
callerName, callerNumberType, callerNumberLabel, info.photoId,
info.lookupKey);
} else if (cachedInfo.isExpired()) {
@@ -694,8 +720,9 @@
// Put it back in the cache, therefore marking it as not expired, so that other
// entries with the same number will not re-request it.
mContactInfoCache.put(number, info);
- // The contact info is no longer up to date, we should request it.
- enqueueRequest(number, c.getPosition(), info.name, info.type, info.label,
+ // The contact info is no longer up to date, we should request it. However, we
+ // do not need to request them immediately.
+ enqueueRequest(number, false, c.getPosition(), info.name, info.type, info.label,
info.photoId, info.lookupKey);
}
diff --git a/src/com/android/contacts/editor/ContactEditorFragment.java b/src/com/android/contacts/editor/ContactEditorFragment.java
index 2cd7b3c..ece2a29 100644
--- a/src/com/android/contacts/editor/ContactEditorFragment.java
+++ b/src/com/android/contacts/editor/ContactEditorFragment.java
@@ -110,6 +110,7 @@
private static final String KEY_VIEW_ID_GENERATOR = "viewidgenerator";
private static final String KEY_CURRENT_PHOTO_FILE = "currentphotofile";
private static final String KEY_CONTACT_ID_FOR_JOIN = "contactidforjoin";
+ private static final String KEY_CONTACT_WRITABLE_FOR_JOIN = "contactwritableforjoin";
private static final String KEY_SHOW_JOIN_SUGGESTIONS = "showJoinSuggestions";
private static final String KEY_ENABLED = "enabled";
private static final String KEY_STATUS = "status";
@@ -222,6 +223,7 @@
private Listener mListener;
private long mContactIdForJoin;
+ private boolean mContactWritableForJoin;
private LinearLayout mContent;
private EntityDeltaList mState;
@@ -274,9 +276,7 @@
// If anything was left unsaved, save it now but keep the editor open.
if (!getActivity().isChangingConfigurations() && mStatus == Status.EDITING) {
- if (mStatus != SaveMode.JOIN) {
- save(SaveMode.RELOAD);
- }
+ save(SaveMode.RELOAD);
}
}
@@ -373,6 +373,7 @@
mCurrentPhotoFile = new File(fileName);
}
mContactIdForJoin = savedState.getLong(KEY_CONTACT_ID_FOR_JOIN);
+ mContactWritableForJoin = savedState.getBoolean(KEY_CONTACT_WRITABLE_FOR_JOIN);
mAggregationSuggestionsRawContactId = savedState.getLong(KEY_SHOW_JOIN_SUGGESTIONS);
mEnabled = savedState.getBoolean(KEY_ENABLED);
mStatus = savedState.getInt(KEY_STATUS);
@@ -981,17 +982,17 @@
case SaveMode.RELOAD:
case SaveMode.JOIN:
if (success && contactLookupUri != null) {
+ // If it was a JOIN, we are now ready to bring up the join activity.
+ if (saveMode == SaveMode.JOIN) {
+ showJoinAggregateActivity(contactLookupUri);
+ }
+
// If this was in INSERT, we are changing into an EDIT now.
// If it already was an EDIT, we are changing to the new Uri now
mState = null;
load(Intent.ACTION_EDIT, contactLookupUri, null);
mStatus = Status.LOADING;
getLoaderManager().restartLoader(LOADER_DATA, null, mDataLoaderListener);
-
- // If it was a JOIN, we are now ready to bring up the join activity.
- if (saveMode == SaveMode.JOIN) {
- showJoinAggregateActivity(contactLookupUri);
- }
}
break;
@@ -1017,6 +1018,7 @@
}
mContactIdForJoin = ContentUris.parseId(contactLookupUri);
+ mContactWritableForJoin = isContactWritable();
final Intent intent = new Intent(JoinContactActivity.JOIN_CONTACT);
intent.putExtra(JoinContactActivity.EXTRA_TARGET_CONTACT_ID, mContactIdForJoin);
startActivityForResult(intent, REQUEST_CODE_JOIN);
@@ -1027,7 +1029,7 @@
*/
private void joinAggregate(final long contactId) {
Intent intent = ContactSaveService.createJoinContactsIntent(mContext, mContactIdForJoin,
- contactId, isContactWritable(),
+ contactId, mContactWritableForJoin,
ContactEditorActivity.class, ContactEditorActivity.ACTION_JOIN_COMPLETED);
mContext.startService(intent);
}
@@ -1460,6 +1462,7 @@
outState.putString(KEY_CURRENT_PHOTO_FILE, mCurrentPhotoFile.toString());
}
outState.putLong(KEY_CONTACT_ID_FOR_JOIN, mContactIdForJoin);
+ outState.putBoolean(KEY_CONTACT_WRITABLE_FOR_JOIN, mContactWritableForJoin);
outState.putLong(KEY_SHOW_JOIN_SUGGESTIONS, mAggregationSuggestionsRawContactId);
outState.putBoolean(KEY_ENABLED, mEnabled);
outState.putInt(KEY_STATUS, mStatus);
@@ -1586,6 +1589,7 @@
Log.v(TAG, "Time needed for setting UI: " + (setDataEndTime-setDataStartTime));
}
+ @Override
public void onLoaderReset(Loader<ContactLoader.Result> loader) {
}
};
diff --git a/src/com/android/contacts/group/GroupBrowseListFragment.java b/src/com/android/contacts/group/GroupBrowseListFragment.java
index db16502..0b53acf 100644
--- a/src/com/android/contacts/group/GroupBrowseListFragment.java
+++ b/src/com/android/contacts/group/GroupBrowseListFragment.java
@@ -197,6 +197,8 @@
String accountType = mGroupListCursor.getString(GroupMetaDataLoader.ACCOUNT_TYPE);
long groupId = mGroupListCursor.getLong(GroupMetaDataLoader.GROUP_ID);
String title = mGroupListCursor.getString(GroupMetaDataLoader.TITLE);
+ boolean deleted =
+ (mGroupListCursor.getInt(GroupMetaDataLoader.DELETED) == 1);
boolean defaultGroup = mGroupListCursor.isNull(GroupMetaDataLoader.AUTO_ADD)
? false
: mGroupListCursor.getInt(GroupMetaDataLoader.AUTO_ADD) != 0;
@@ -205,8 +207,8 @@
: mGroupListCursor.getInt(GroupMetaDataLoader.FAVORITES) != 0;
// Don't show the "auto-added" (i.e. My Contacts) or "favorites" groups because
- // they show up elsewhere in the app
- if (defaultGroup || favorites) {
+ // they show up elsewhere in the app. Also skip groups that are marked as "deleted"
+ if (defaultGroup || favorites || deleted) {
continue;
}
diff --git a/src/com/android/contacts/group/GroupDetailFragment.java b/src/com/android/contacts/group/GroupDetailFragment.java
index c4824ae..fe2605e 100644
--- a/src/com/android/contacts/group/GroupDetailFragment.java
+++ b/src/com/android/contacts/group/GroupDetailFragment.java
@@ -90,6 +90,7 @@
private String mGroupName;
private boolean mOptionsMenuEditable;
+ private boolean mCloseActivityAfterDelete;
public GroupDetailFragment() {
}
@@ -190,11 +191,20 @@
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
- bindGroupMetaData(data);
+ data.moveToPosition(-1);
+ if (data.moveToNext()) {
+ boolean deleted = data.getInt(GroupMetaDataLoader.DELETED) == 1;
+ if (!deleted) {
+ bindGroupMetaData(data);
- // Retrieve the list of members
- configureAdapter(mGroupId);
- startGroupMembersLoader();
+ // Retrieve the list of members
+ configureAdapter(mGroupId);
+ startGroupMembersLoader();
+ return;
+ }
+ }
+ updateSize(null);
+ updateTitle(null);
}
@Override
@@ -295,10 +305,15 @@
break;
}
case R.id.menu_delete_group: {
- GroupDeletionDialogFragment.show(getFragmentManager(), mGroupId, mGroupName);
+ GroupDeletionDialogFragment.show(getFragmentManager(), mGroupId, mGroupName,
+ mCloseActivityAfterDelete);
return true;
}
}
return false;
}
+
+ public void closeActivityAfterDelete(boolean closeActivity) {
+ mCloseActivityAfterDelete = closeActivity;
+ }
}
diff --git a/src/com/android/contacts/interactions/GroupDeletionDialogFragment.java b/src/com/android/contacts/interactions/GroupDeletionDialogFragment.java
index 44d31be..c9c1342 100644
--- a/src/com/android/contacts/interactions/GroupDeletionDialogFragment.java
+++ b/src/com/android/contacts/interactions/GroupDeletionDialogFragment.java
@@ -33,8 +33,15 @@
private static final String ARG_GROUP_ID = "groupId";
private static final String ARG_LABEL = "label";
- public static void show(FragmentManager fragmentManager, long groupId, String label) {
- GroupDeletionDialogFragment dialog = new GroupDeletionDialogFragment();
+ private boolean mEndActivity;
+
+ public GroupDeletionDialogFragment(boolean endActivity) {
+ mEndActivity = endActivity;
+ }
+
+ public static void show(FragmentManager fragmentManager, long groupId, String label,
+ boolean endActivity) {
+ GroupDeletionDialogFragment dialog = new GroupDeletionDialogFragment(endActivity);
Bundle args = new Bundle();
args.putLong(ARG_GROUP_ID, groupId);
args.putString(ARG_LABEL, label);
@@ -69,5 +76,8 @@
getActivity().startService(ContactSaveService.createGroupDeletionIntent(
getActivity(), groupId));
+ if (mEndActivity) {
+ getActivity().finish();
+ }
}
}
diff --git a/src/com/android/contacts/list/AccountFilterActivity.java b/src/com/android/contacts/list/AccountFilterActivity.java
new file mode 100644
index 0000000..c38599e
--- /dev/null
+++ b/src/com/android/contacts/list/AccountFilterActivity.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2011 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.ContactsActivity;
+import com.android.contacts.ContactsSearchManager;
+import com.android.contacts.R;
+import com.android.contacts.model.AccountType;
+import com.android.contacts.model.AccountTypeManager;
+
+import android.accounts.Account;
+import android.app.ActionBar;
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.BaseAdapter;
+import android.widget.ListView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Shows a list of all available accounts, letting the user select under which account to view
+ * contacts.
+ */
+public class AccountFilterActivity extends ContactsActivity
+ implements AdapterView.OnItemClickListener {
+
+ private static final String TAG = AccountFilterActivity.class.getSimpleName();
+
+ public static final String KEY_EXTRA_CONTACT_LIST_FILTER = "contactListFilter";
+
+ private ListView mListView;
+
+ private List<ContactListFilter> mFilters = new ArrayList<ContactListFilter>();
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.contact_list_filter);
+
+ mListView = (ListView) findViewById(com.android.internal.R.id.list);
+ mListView.setOnItemClickListener(new OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ finishAndSetResult(mFilters.get(position));
+ }
+ });
+
+ ActionBar actionBar = getActionBar();
+ if (actionBar != null) {
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ }
+
+ loadAccountFilters();
+ }
+
+ private void loadAccountFilters() {
+ ArrayList<ContactListFilter> accountFilters = new ArrayList<ContactListFilter>();
+ final AccountTypeManager accountTypes = AccountTypeManager.getInstance(this);
+ ArrayList<Account> accounts = accountTypes.getAccounts(false);
+ for (Account account : accounts) {
+ AccountType accountType = accountTypes.getAccountType(account.type);
+ Drawable icon = accountType != null ? accountType.getDisplayIcon(this) : null;
+ accountFilters.add(ContactListFilter.createAccountFilter(account.type, account.name,
+ icon, account.name));
+ }
+ int count = accountFilters.size();
+
+ if (count >= 1) {
+ // If we only have one account, don't show it as "account", instead show it as "all"
+ mFilters.add(ContactListFilter.createFilterWithType(
+ ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS));
+ if (count > 1) {
+ mFilters.addAll(accountFilters);
+ mFilters.add(ContactListFilter.createFilterWithType(
+ ContactListFilter.FILTER_TYPE_CUSTOM));
+ }
+ }
+
+ mListView.setAdapter(new FilterListAdapter(this));
+ }
+
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ finishAndSetResult(mFilters.get(position));
+ }
+
+ private void finishAndSetResult(ContactListFilter filter) {
+ final Intent intent = new Intent();
+ intent.putExtra(KEY_EXTRA_CONTACT_LIST_FILTER, filter);
+ setResult(Activity.RESULT_OK, intent);
+ finish();
+ }
+
+ @Override
+ public void startSearch(String initialQuery, boolean selectInitialQuery, Bundle appSearchData,
+ boolean globalSearch) {
+ if (globalSearch) {
+ super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch);
+ } else {
+ ContactsSearchManager.startSearch(this, initialQuery);
+ }
+ }
+
+ private class FilterListAdapter extends BaseAdapter {
+ private LayoutInflater mLayoutInflater;
+
+ public FilterListAdapter(Context context) {
+ mLayoutInflater = (LayoutInflater) context.getSystemService
+ (Context.LAYOUT_INFLATER_SERVICE);
+ }
+
+ @Override
+ public int getCount() {
+ return mFilters.size();
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public ContactListFilter getItem(int position) {
+ return mFilters.get(position);
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ ContactListFilterView view;
+ if (convertView != null) {
+ view = (ContactListFilterView) convertView;
+ } else {
+ view = (ContactListFilterView) mLayoutInflater.inflate(
+ R.layout.filter_spinner_item, parent, false);
+ }
+ view.setSingleAccount(mFilters.size() == 1);
+ ContactListFilter filter = mFilters.get(position);
+ view.setContactListFilter(filter);
+ view.bindView(true);
+ return view;
+ }
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home:
+ finish();
+ return true;
+ default:
+ break;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+}
diff --git a/src/com/android/contacts/list/ContactListFilterController.java b/src/com/android/contacts/list/ContactListFilterController.java
index 533f24a..28b62ca 100644
--- a/src/com/android/contacts/list/ContactListFilterController.java
+++ b/src/com/android/contacts/list/ContactListFilterController.java
@@ -15,67 +15,43 @@
*/
package com.android.contacts.list;
-import com.android.contacts.R;
-
import android.app.Activity;
-import android.app.LoaderManager;
-import android.app.LoaderManager.LoaderCallbacks;
import android.content.Context;
-import android.content.Loader;
import android.content.SharedPreferences;
-import android.content.res.TypedArray;
-import android.os.Bundle;
import android.preference.PreferenceManager;
-import android.text.TextUtils;
-import android.util.SparseArray;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.BaseAdapter;
-import android.widget.ListPopupWindow;
import java.util.ArrayList;
import java.util.List;
/**
- * Controls a list of {@link ContactListFilter}'s.
+ * Stores the {@link ContactListFilter} selected by the user and saves it to
+ * {@link SharedPreferences} if necessary.
*/
-// TODO: Remove the extra functionality dealing with loading and displaying a list of filters in
-// the action bar.
-public class ContactListFilterController
- implements LoaderCallbacks<List<ContactListFilter>>, OnClickListener, OnItemClickListener {
+public class ContactListFilterController {
public interface ContactListFilterListener {
- void onContactListFiltersLoaded();
void onContactListFilterChanged();
- void onContactListFilterCustomizationRequest();
}
private Context mContext;
- private LoaderManager mLoaderManager;
- private boolean mEnabled = true;
private List<ContactListFilterListener> mListeners = new ArrayList<ContactListFilterListener>();
- private ListPopupWindow mPopup;
- private int mPopupWidth = -1;
- private List<ContactListFilter> mCachedFilters;
- private SparseArray<ContactListFilter> mFilters;
- private int mNextFilterId = 1;
- private View mAnchor;
- private FilterListAdapter mFilterListAdapter;
private ContactListFilter mFilter;
- private boolean mFiltersLoaded;
- private int mAccountCount;
+
+ private boolean mIsInitialized;
public ContactListFilterController(Activity activity) {
mContext = activity;
- mLoaderManager = activity.getLoaderManager();
}
- public void setEnabled(boolean flag) {
- mEnabled = flag;
+ public void onStart() {
+ if (mFilter == null) {
+ mFilter = ContactListFilter.restoreFromPreferences(getSharedPreferences());
+ mIsInitialized = true;
+ }
+ }
+
+ public boolean isInitialized() {
+ return mIsInitialized;
}
public void addListener(ContactListFilterListener listener) {
@@ -90,157 +66,10 @@
return mFilter;
}
- public int getFilterCount() {
- return mFilters != null ? mFilters.size() : 0;
- }
-
- public boolean isLoaded() {
- return mFiltersLoaded;
- }
-
- public void onStart() {
- if (mFilter == null) {
- mFilter = ContactListFilter.restoreFromPreferences(getSharedPreferences());
- }
- }
-
private SharedPreferences getSharedPreferences() {
return PreferenceManager.getDefaultSharedPreferences(mContext);
}
- @Override
- public ContactListFilterLoader onCreateLoader(int id, Bundle args) {
- return new ContactListFilterLoader(mContext);
- }
-
- @Override
- public void onLoadFinished(
- Loader<List<ContactListFilter>> loader, List<ContactListFilter> filters) {
- int count = filters.size();
- if (mCachedFilters != null && mCachedFilters.size() == count) {
- boolean changed = false;
- for (int i = 0; i < filters.size(); i++) {
- ContactListFilter filter1 = mCachedFilters.get(i);
- ContactListFilter filter2 = filters.get(i);
- if (!filter1.equals(filter2)) {
- changed = true;
- break;
- }
-
- // Group title is intentionally not included in the "equals" algorithm for
- // ContactListFilter, because we want stability of filter identity
- // across label changes. However, here we do care about the label changes.
- if (filter1.filterType == ContactListFilter.FILTER_TYPE_GROUP &&
- !TextUtils.equals(filter1.title, filter2.title)) {
- changed = true;
- break;
- }
- }
-
- if (!changed) {
- return;
- }
- }
-
- mCachedFilters = filters;
-
- if (mFilters == null) {
- mFilters = new SparseArray<ContactListFilter>(filters.size());
- } else {
- mFilters.clear();
- }
-
- boolean filterValid = mFilter != null && !mFilter.isValidationRequired();
-
- mAccountCount = 0;
- for (int index = 0; index < count; index++) {
- if (filters.get(index).filterType == ContactListFilter.FILTER_TYPE_ACCOUNT) {
- mAccountCount++;
- }
- }
-
- if (mAccountCount != 1) {
- mFilters.append(mNextFilterId++, ContactListFilter.createFilterWithType(
- ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS));
- mFilters.append(mNextFilterId++, ContactListFilter.createFilterWithType(
- ContactListFilter.FILTER_TYPE_STARRED));
- }
-
- for (int index = 0; index < count; index++) {
- ContactListFilter filter = filters.get(index);
-
- boolean firstAndOnly = mAccountCount == 1
- && filter.filterType == ContactListFilter.FILTER_TYPE_ACCOUNT;
-
- // If we only have one account, don't show it as "account", instead show it as "all"
- if (firstAndOnly) {
- filter = ContactListFilter.createFilterWithType(
- ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS);
- }
-
- mFilters.append(mNextFilterId++, filter);
-
- if (filter.equals(mFilter)) {
- // Refresh the filter in case the title got changed
- mFilter = filter;
- filterValid = true;
- }
-
- if (firstAndOnly) {
- mFilters.append(mNextFilterId++, ContactListFilter.createFilterWithType(
- ContactListFilter.FILTER_TYPE_STARRED));
- }
- }
-
- if (mAccountCount > 0) {
- mFilters.append(mNextFilterId++, ContactListFilter.createFilterWithType(
- ContactListFilter.FILTER_TYPE_CUSTOM));
- }
-
- boolean filterChanged = false;
- if (mFilter == null || !filterValid) {
- filterChanged = mFilter != null;
- mFilter = getDefaultFilter();
- }
-
- if (mFilterListAdapter == null) {
- mFilterListAdapter = new FilterListAdapter();
- } else {
- mFilterListAdapter.notifyDataSetChanged();
- }
-
- mFiltersLoaded = true;
- notifyContacListFiltersLoaded();
-
- if (filterChanged) {
- notifyContactListFilterChanged();
- }
- }
-
- public void onLoaderReset(Loader<List<ContactListFilter>> loader) {
- }
-
- private void setContactListFilter(int filterId) {
- ContactListFilter filter;
- if (filterId == ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS) {
- filter = ContactListFilter.createFilterWithType(
- ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS);
- } else if (filterId == ContactListFilter.FILTER_TYPE_CUSTOM) {
- filter = ContactListFilter.createFilterWithType(
- ContactListFilter.FILTER_TYPE_CUSTOM);
- } else if (filterId == ContactListFilter.FILTER_TYPE_STARRED) {
- filter = ContactListFilter.createFilterWithType(
- ContactListFilter.FILTER_TYPE_STARRED);
- } else {
- filter = mFilters.get(filterId);
- if (filter == null) {
- filter = getDefaultFilter();
- }
- }
-
- setContactListFilter(filter, true);
- }
-
public void setContactListFilter(ContactListFilter filter, boolean persistent) {
if (!filter.equals(mFilter)) {
mFilter = filter;
@@ -253,59 +82,9 @@
}
}
- @Override
- public void onClick(View v) {
- if (!mFiltersLoaded || !mEnabled) {
- return;
- }
-
- if (mPopupWidth == -1) {
- TypedArray a = mContext.obtainStyledAttributes(null, R.styleable.ContactBrowser);
- mPopupWidth = a.getDimensionPixelSize(
- R.styleable.ContactBrowser_contact_filter_popup_width, -1);
- a.recycle();
-
- if (mPopupWidth == -1) {
- mPopupWidth = mAnchor.getWidth();
- }
- }
-
- mPopup = new ListPopupWindow(mContext, null);
- mPopup.setWidth(mPopupWidth);
- mPopup.setAdapter(mFilterListAdapter);
- mPopup.setAnchorView(mAnchor);
- mPopup.setOnItemClickListener(this);
- mPopup.setModal(true);
- mPopup.show();
- }
-
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- mPopup.dismiss();
- if (mFilters.get((int) id).filterType == ContactListFilter.FILTER_TYPE_CUSTOM) {
- notifyContactListFilterCustomizationRequest();
- } else {
- setContactListFilter((int) id);
- }
- }
-
public void selectCustomFilter() {
- mFilter = ContactListFilter.createFilterWithType(ContactListFilter.FILTER_TYPE_CUSTOM);
- notifyContactListFilterChanged();
- }
-
- public int getAccountCount() {
- return mAccountCount;
- }
-
- private ContactListFilter getDefaultFilter() {
- return mFilters.size() > 0 ? mFilters.valueAt(0) : null;
- }
-
- private void notifyContacListFiltersLoaded() {
- for (ContactListFilterListener listener : mListeners) {
- listener.onContactListFiltersLoaded();
- }
+ setContactListFilter(ContactListFilter.createFilterWithType(
+ ContactListFilter.FILTER_TYPE_CUSTOM), true);
}
private void notifyContactListFilterChanged() {
@@ -314,48 +93,4 @@
}
}
- private void notifyContactListFilterCustomizationRequest() {
- for (ContactListFilterListener listener : mListeners) {
- listener.onContactListFilterCustomizationRequest();
- }
- }
-
- private class FilterListAdapter extends BaseAdapter {
- private LayoutInflater mLayoutInflater;
-
- public FilterListAdapter() {
- mLayoutInflater = LayoutInflater.from(mContext);
- }
-
- @Override
- public int getCount() {
- return mFilters.size();
- }
-
- @Override
- public long getItemId(int position) {
- return mFilters.keyAt(position);
- }
-
- @Override
- public Object getItem(int position) {
- return mFilters.valueAt(position);
- }
-
- public View getView(int position, View convertView, ViewGroup parent) {
- ContactListFilterView view;
- if (convertView != null) {
- view = (ContactListFilterView) convertView;
- } else {
- view = (ContactListFilterView) mLayoutInflater.inflate(
- R.layout.filter_spinner_item, parent, false);
- }
- view.setSingleAccount(mAccountCount == 1);
- ContactListFilter filter = mFilters.valueAt(position);
- view.setContactListFilter(filter);
- view.setActivated(filter.equals(mFilter));
- view.bindView(true);
- return view;
- }
- }
}
diff --git a/src/com/android/contacts/list/ContactListFilterLoader.java b/src/com/android/contacts/list/ContactListFilterLoader.java
deleted file mode 100644
index 07c11bc..0000000
--- a/src/com/android/contacts/list/ContactListFilterLoader.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * 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.model.AccountType;
-import com.android.contacts.model.AccountTypeManager;
-
-import android.accounts.Account;
-import android.content.AsyncTaskLoader;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.database.Cursor;
-import android.graphics.drawable.Drawable;
-import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.Groups;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * A loader for the data needed for the group selector.
- */
-public class ContactListFilterLoader extends AsyncTaskLoader<List<ContactListFilter>> {
-
- private static final class GroupQuery {
- public static final String[] COLUMNS = {
- Groups._ID,
- Groups.ACCOUNT_TYPE,
- Groups.ACCOUNT_NAME,
- Groups.TITLE,
- Groups.AUTO_ADD,
- Groups.SOURCE_ID,
- Groups.GROUP_IS_READ_ONLY,
- };
-
- public static final int ID = 0;
- public static final int ACCOUNT_TYPE = 1;
- public static final int ACCOUNT_NAME = 2;
- public static final int TITLE = 3;
- public static final int IS_DEFAULT_GROUP = 4; // Using the AUTO_ADD group as default
- public static final int SOURCE_ID = 5;
- public static final int GROUP_IS_READ_ONLY = 6;
-
- public static final String SELECTION =
- Groups.DELETED + "=0" +
- " AND " + Groups.FAVORITES + "=0" +
- " AND " + Groups.ACCOUNT_TYPE + " NOT NULL" +
- " AND " + Groups.ACCOUNT_NAME + " NOT NULL";
- }
-
- private boolean mStopped;
- private ForceLoadContentObserver mObserver;
- private ArrayList<ContactListFilter> mResults;
-
- public ContactListFilterLoader(Context context) {
- super(context);
- }
-
- @Override
- public List<ContactListFilter> loadInBackground() {
-
- ArrayList<ContactListFilter> results = new ArrayList<ContactListFilter>();
- Context context = getContext();
- final AccountTypeManager accountTypes = AccountTypeManager.getInstance(context);
- ArrayList<Account> accounts = accountTypes.getAccounts(false);
- for (Account account : accounts) {
- AccountType accountType = accountTypes.getAccountType(account.type);
- Drawable icon = accountType != null ? accountType.getDisplayIcon(getContext()) : null;
- results.add(ContactListFilter.createAccountFilter(account.type, account.name, icon,
- account.name));
- }
-
- ContentResolver resolver = context.getContentResolver();
-
- Cursor cursor = resolver.query(
- Groups.CONTENT_URI, GroupQuery.COLUMNS, GroupQuery.SELECTION, null, null);
- try {
- while (cursor.moveToNext()) {
- long groupId = cursor.getLong(GroupQuery.ID);
- String groupSourceId = cursor.getString(GroupQuery.SOURCE_ID);
- boolean groupReadOnly = cursor.getInt(GroupQuery.GROUP_IS_READ_ONLY) != 0;
- String accountType = cursor.getString(GroupQuery.ACCOUNT_TYPE);
- String accountName = cursor.getString(GroupQuery.ACCOUNT_NAME);
- boolean defaultGroup = false;
- if (!cursor.isNull(GroupQuery.IS_DEFAULT_GROUP)) {
- defaultGroup = cursor.getInt(GroupQuery.IS_DEFAULT_GROUP) != 0;
- }
- if (defaultGroup) {
- // Find the filter for this account and set the default group ID
- for (ContactListFilter filter : results) {
- if (filter.accountName.equals(accountName)
- && filter.accountType.equals(accountType)) {
- filter.groupId = groupId;
- filter.groupSourceId = groupSourceId;
- break;
- }
- }
- } else {
- String title = cursor.getString(GroupQuery.TITLE);
- results.add(ContactListFilter.createGroupFilter(accountType, accountName,
- groupId, groupSourceId, groupReadOnly, title));
- }
- }
- } finally {
- cursor.close();
- }
-
- Collections.sort(results);
-
- mResults = results;
- return results;
- }
-
- /* Runs on the UI thread */
- @Override
- public void deliverResult(List<ContactListFilter> results) {
- if (!mStopped) {
- super.deliverResult(results);
- }
- }
-
- @Override
- protected void onStartLoading() {
- if (mObserver == null) {
- mObserver = new ForceLoadContentObserver();
- getContext().getContentResolver().registerContentObserver(
- Contacts.CONTENT_URI, true, mObserver);
- }
-
- mStopped = false;
-
- if (mResults != null) {
- deliverResult(mResults);
- } else {
- forceLoad();
- }
- }
-
- @Override
- protected void onStopLoading() {
- if (mObserver != null) {
- getContext().getContentResolver().unregisterContentObserver(mObserver);
- mObserver = null;
- }
-
- mResults = null;
-
- // Attempt to cancel the current load task if possible.
- cancelLoad();
-
- // Make sure that any outstanding loads clean themselves up properly
- mStopped = true;
- }
-
- @Override
- protected void onReset() {
- stopLoading();
- }
-}
diff --git a/src/com/android/contacts/list/CustomContactListFilterActivity.java b/src/com/android/contacts/list/CustomContactListFilterActivity.java
index dae7233..0f6aaad 100644
--- a/src/com/android/contacts/list/CustomContactListFilterActivity.java
+++ b/src/com/android/contacts/list/CustomContactListFilterActivity.java
@@ -23,10 +23,8 @@
import com.android.contacts.model.AccountTypeManager;
import com.android.contacts.model.EntityDelta.ValuesDelta;
import com.android.contacts.model.GoogleAccountType;
-import com.android.contacts.preference.ContactsPreferences;
import com.android.contacts.util.EmptyService;
import com.android.contacts.util.LocalizedNameResolver;
-import com.android.contacts.util.PhoneCapabilityTester;
import com.android.contacts.util.WeakAsyncTask;
import com.google.android.collect.Lists;
@@ -46,7 +44,6 @@
import android.content.Loader;
import android.content.OperationApplicationException;
import android.content.SharedPreferences;
-import android.content.SharedPreferences.Editor;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
@@ -62,7 +59,6 @@
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.AdapterView;
import android.widget.BaseExpandableListAdapter;
import android.widget.CheckBox;
import android.widget.ExpandableListAdapter;
@@ -80,8 +76,7 @@
* select which ones they want to be visible.
*/
public class CustomContactListFilterActivity extends ContactsActivity
- implements AdapterView.OnItemClickListener, View.OnClickListener,
- ExpandableListView.OnChildClickListener,
+ implements View.OnClickListener, ExpandableListView.OnChildClickListener,
LoaderCallbacks<CustomContactListFilterActivity.AccountSet>
{
private static final String TAG = "CustomContactListFilterActivity";
@@ -93,11 +88,6 @@
private SharedPreferences mPrefs;
- private CheckBox mDisplayPhones;
-
- private View mHeaderPhones;
- private View mHeaderSeparator;
-
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
@@ -111,50 +101,14 @@
final LayoutInflater inflater = getLayoutInflater();
- createWithPhonesOnlyPreferenceView(inflater);
- createDisplayGroupHeader(inflater);
-
- if (mHeaderPhones != null) {
- mList.addHeaderView(mHeaderPhones, null, true);
- mList.addHeaderView(mHeaderSeparator, null, false);
- }
-
findViewById(R.id.btn_done).setOnClickListener(this);
findViewById(R.id.btn_discard).setOnClickListener(this);
- // Catch clicks on the header views
- mList.setOnItemClickListener(this);
mList.setOnCreateContextMenuListener(this);
mList.setAdapter(mAdapter);
}
- private void createWithPhonesOnlyPreferenceView(LayoutInflater inflater) {
- boolean optionSelected = mPrefs.getBoolean(ContactsPreferences.PREF_DISPLAY_ONLY_PHONES,
- ContactsPreferences.PREF_DISPLAY_ONLY_PHONES_DEFAULT);
-
- if (!optionSelected && !PhoneCapabilityTester.isPhone(this)) {
- return;
- }
-
- // Add the "Only contacts with phones" header modifier.
- mHeaderPhones = inflater.inflate(R.layout.contact_list_filter_phones_only, mList, false);
- mHeaderPhones.setId(R.id.header_phones);
- mDisplayPhones = (CheckBox) mHeaderPhones.findViewById(android.R.id.checkbox);
- mDisplayPhones.setChecked(optionSelected);
- final TextView text1 = (TextView) mHeaderPhones.findViewById(android.R.id.text1);
- text1.setText(R.string.showFilterPhones);
- final TextView text2 = (TextView) mHeaderPhones.findViewById(android.R.id.text2);
- text2.setText(R.string.showFilterPhonesDescrip);
- }
-
- private void createDisplayGroupHeader(LayoutInflater inflater) {
- // Add the separator before showing the detailed group list.
- mHeaderSeparator = inflater.inflate(R.layout.list_separator, mList, false);
- final TextView text1 = (TextView) mHeaderSeparator;
- text1.setText(R.string.headerContactGroups);
- }
-
public static class CustomFilterConfigurationLoader extends AsyncTaskLoader<AccountSet> {
private AccountSet mAccountSet;
@@ -696,18 +650,6 @@
}
}
- /**
- * Handle any clicks on header views added to our {@link #mAdapter}, which
- * are usually the global modifier checkboxes.
- */
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- Log.d(TAG, "OnItemClick, position=" + position + ", id=" + id);
- if (view == mHeaderPhones) {
- mDisplayPhones.toggle();
- return;
- }
- }
-
/** {@inheritDoc} */
public void onClick(View view) {
switch (view.getId()) {
@@ -723,21 +665,6 @@
}
/**
- * Assign a specific value to {@link ContactsPreferences#PREF_DISPLAY_ONLY_PHONES}, refreshing
- * the visible list as needed.
- */
- protected void setDisplayOnlyPhones(boolean displayOnlyPhones) {
- mDisplayPhones.setChecked(displayOnlyPhones);
-
- Editor editor = mPrefs.edit();
- editor.putBoolean(ContactsPreferences.PREF_DISPLAY_ONLY_PHONES, displayOnlyPhones);
- editor.apply();
-
- mAdapter.setChildDescripWithPhones(displayOnlyPhones);
- mAdapter.notifyDataSetChanged();
- }
-
- /**
* Handle any clicks on {@link ExpandableListAdapter} children, which
* usually mean toggling its visible state.
*/
@@ -880,10 +807,6 @@
return;
}
- if (mDisplayPhones != null) {
- setDisplayOnlyPhones(mDisplayPhones.isChecked());
- }
-
setResult(RESULT_OK);
final ArrayList<ContentProviderOperation> diff = mAdapter.mAccounts.buildDiff();
diff --git a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
index f95c4af..88531e1 100644
--- a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
+++ b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
@@ -34,6 +34,7 @@
private View mCounterHeaderView;
private View mSearchHeaderView;
+ private TextView mAccountFilterHeaderView;
public DefaultContactBrowseListFragment() {
setPhotoLoaderEnabled(true);
@@ -63,6 +64,8 @@
protected void onCreateView(LayoutInflater inflater, ViewGroup container) {
super.onCreateView(inflater, container);
+ mAccountFilterHeaderView = (TextView) getView().findViewById(R.id.account_filter_header);
+
// Putting the header view inside a container will allow us to make
// it invisible later. See checkHeaderViewVisibility()
FrameLayout headerContainer = new FrameLayout(inflater.getContext());
@@ -92,6 +95,19 @@
}
@Override
+ public void setFilter(ContactListFilter filter) {
+ super.setFilter(filter);
+ if (filter != null && filter.filterType != ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS &&
+ filter.filterType != ContactListFilter.FILTER_TYPE_CUSTOM) {
+ mAccountFilterHeaderView.setText(getContext().getString(
+ R.string.listAllContactsInAccount, filter.accountName));
+ mAccountFilterHeaderView.setVisibility(View.VISIBLE);
+ } else {
+ mAccountFilterHeaderView.setVisibility(View.GONE);
+ }
+ }
+
+ @Override
protected void showCount(int partitionIndex, Cursor data) {
if (!isSearchMode() && data != null) {
int count = data.getCount();
diff --git a/tests/src/com/android/contacts/activities/CallLogActivityTests.java b/tests/src/com/android/contacts/activities/CallLogActivityTests.java
index adc1838..6421a9e 100644
--- a/tests/src/com/android/contacts/activities/CallLogActivityTests.java
+++ b/tests/src/com/android/contacts/activities/CallLogActivityTests.java
@@ -113,6 +113,7 @@
// Do not process requests for details during tests. This would start a background thread,
// which makes the tests flaky.
mAdapter.disableRequestProcessingForTest();
+ mAdapter.stopRequestProcessing();
mParentView = new FrameLayout(mActivity);
mCursor = new MatrixCursor(CALL_LOG_PROJECTION);
buildIconMap();