Merge "Follow up to EditSchema parser"
diff --git a/res/drawable-hdpi/ic_launcher_folder_live_contacts.png b/res/drawable-hdpi/ic_launcher_folder_live_contacts.png
deleted file mode 100644
index 84babe2..0000000
--- a/res/drawable-hdpi/ic_launcher_folder_live_contacts.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_folder_live_contacts_phone.png b/res/drawable-hdpi/ic_launcher_folder_live_contacts_phone.png
deleted file mode 100644
index 004e849..0000000
--- a/res/drawable-hdpi/ic_launcher_folder_live_contacts_phone.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_folder_live_contacts_starred.png b/res/drawable-hdpi/ic_launcher_folder_live_contacts_starred.png
deleted file mode 100644
index 73b4fa5..0000000
--- a/res/drawable-hdpi/ic_launcher_folder_live_contacts_starred.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_see_contacts_holo_dark.png b/res/drawable-hdpi/ic_see_contacts_holo_dark.png
deleted file mode 100644
index 8e2182f..0000000
--- a/res/drawable-hdpi/ic_see_contacts_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_unheard_voicemail_holo_dark.png b/res/drawable-hdpi/ic_unheard_voicemail_holo_dark.png
deleted file mode 100644
index 4f48e77..0000000
--- a/res/drawable-hdpi/ic_unheard_voicemail_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_folder_live_contacts.png b/res/drawable-mdpi/ic_launcher_folder_live_contacts.png
deleted file mode 100644
index d49cc7b..0000000
--- a/res/drawable-mdpi/ic_launcher_folder_live_contacts.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_folder_live_contacts_phone.png b/res/drawable-mdpi/ic_launcher_folder_live_contacts_phone.png
deleted file mode 100644
index 0127f84..0000000
--- a/res/drawable-mdpi/ic_launcher_folder_live_contacts_phone.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_folder_live_contacts_starred.png b/res/drawable-mdpi/ic_launcher_folder_live_contacts_starred.png
deleted file mode 100644
index 8d56b31..0000000
--- a/res/drawable-mdpi/ic_launcher_folder_live_contacts_starred.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_see_contacts_holo_dark.png b/res/drawable-mdpi/ic_see_contacts_holo_dark.png
deleted file mode 100644
index ef1d2df..0000000
--- a/res/drawable-mdpi/ic_see_contacts_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_unheard_voicemail_holo_dark.png b/res/drawable-mdpi/ic_unheard_voicemail_holo_dark.png
deleted file mode 100644
index 8992be2..0000000
--- a/res/drawable-mdpi/ic_unheard_voicemail_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_folder_live_contacts.png b/res/drawable-xhdpi/ic_launcher_folder_live_contacts.png
deleted file mode 100644
index 99bb9f8..0000000
--- a/res/drawable-xhdpi/ic_launcher_folder_live_contacts.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_folder_live_contacts_phone.png b/res/drawable-xhdpi/ic_launcher_folder_live_contacts_phone.png
deleted file mode 100644
index fd416b8..0000000
--- a/res/drawable-xhdpi/ic_launcher_folder_live_contacts_phone.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_folder_live_contacts_starred.png b/res/drawable-xhdpi/ic_launcher_folder_live_contacts_starred.png
deleted file mode 100644
index ff9e326..0000000
--- a/res/drawable-xhdpi/ic_launcher_folder_live_contacts_starred.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_see_contacts_holo_dark.png b/res/drawable-xhdpi/ic_see_contacts_holo_dark.png
deleted file mode 100644
index 279fff9..0000000
--- a/res/drawable-xhdpi/ic_see_contacts_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_unheard_voicemail_holo_dark.png b/res/drawable-xhdpi/ic_unheard_voicemail_holo_dark.png
deleted file mode 100644
index 75e771c..0000000
--- a/res/drawable-xhdpi/ic_unheard_voicemail_holo_dark.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable/quickcontact_list_item_background.xml b/res/drawable/quickcontact_list_item_background.xml
deleted file mode 100644
index afb3947..0000000
--- a/res/drawable/quickcontact_list_item_background.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item
- android:state_window_focused="false"
- android:drawable="@drawable/list_background_holo" />
- <item
- android:state_focused="true"
- android:state_pressed="true"
- android:drawable="@drawable/list_pressed_holo" />
- <item
- android:state_focused="false"
- android:state_pressed="true"
- android:drawable="@drawable/list_pressed_holo" />
- <item
- android:state_focused="true"
- android:drawable="@drawable/list_focused_holo" />
- <item
- android:drawable="@color/quickcontact_list_background" />
-</selector>
diff --git a/res/layout-sw580dp-w1000dp/group_detail_fragment.xml b/res/layout-sw580dp-w1000dp/group_detail_fragment.xml
index 45419a8..3011d69 100644
--- a/res/layout-sw580dp-w1000dp/group_detail_fragment.xml
+++ b/res/layout-sw580dp-w1000dp/group_detail_fragment.xml
@@ -81,4 +81,7 @@
android:fadingEdge="none"
android:divider="@null" />
+ <include
+ layout="@layout/group_detail_fragment_empty_view"/>
+
</LinearLayout>
\ No newline at end of file
diff --git a/res/layout-sw580dp/group_detail_fragment.xml b/res/layout-sw580dp/group_detail_fragment.xml
index fbe695b..ec65582 100644
--- a/res/layout-sw580dp/group_detail_fragment.xml
+++ b/res/layout-sw580dp/group_detail_fragment.xml
@@ -61,4 +61,7 @@
android:fadingEdge="none"
android:divider="@null" />
+ <include
+ layout="@layout/group_detail_fragment_empty_view"/>
+
</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/group_detail_fragment.xml b/res/layout/group_detail_fragment.xml
index 2b020c9..735b29d 100644
--- a/res/layout/group_detail_fragment.xml
+++ b/res/layout/group_detail_fragment.xml
@@ -43,6 +43,9 @@
android:scrollbarStyle="outsideOverlay"
android:divider="@null"/>
+ <include
+ layout="@layout/group_detail_fragment_empty_view"/>
+
<!--
Shadow overlay over the list of group members (since we have a fake stacked
action bar)
diff --git a/res/layout/group_detail_fragment_empty_view.xml b/res/layout/group_detail_fragment_empty_view.xml
new file mode 100644
index 0000000..89a6cf8
--- /dev/null
+++ b/res/layout/group_detail_fragment_empty_view.xml
@@ -0,0 +1,41 @@
+<?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:id="@android:id/empty"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:paddingTop="24dip"
+ android:visibility="gone">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal"
+ android:text="@string/emptyGroup"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textColor="?android:attr/textColorSecondary"/>
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal"
+ android:text="@string/addPeopleToGroup"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorSecondary"/>
+
+</LinearLayout>
diff --git a/res/layout/join_contact_picker_show_all.xml b/res/layout/join_contact_picker_show_all.xml
deleted file mode 100644
index d332649..0000000
--- a/res/layout/join_contact_picker_show_all.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- * Copyright 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:orientation="vertical">
-
- <View
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="?android:attr/dividerHorizontal" />
-
- <TextView
- android:id="@+id/text"
- android:layout_height="48dip"
- android:layout_width="match_parent"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="?android:attr/textColorSecondary"
- android:gravity="center_vertical"
- android:text="@string/showAllContactsJoinItem" />
-
- <View
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="?android:attr/dividerHorizontal" />
-</LinearLayout>
diff --git a/res/layout/status_bar_ongoing_event_progress_bar.xml b/res/layout/status_bar_ongoing_event_progress_bar.xml
deleted file mode 100644
index e3edf95..0000000
--- a/res/layout/status_bar_ongoing_event_progress_bar.xml
+++ /dev/null
@@ -1,94 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- * Copyright 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.
- /
-TODO: This is copied from DownloadProvider, and looks similar to Bluetooth's.
- It might be better to have this in framework.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:background="@android:drawable/status_bar_item_app_background"
- >
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal"
- >
- <LinearLayout
- android:layout_width="40dp"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:paddingTop="8dp"
- android:focusable="true"
- >
- <ImageView
- android:id="@+id/status_icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:src="@android:drawable/sym_def_app_icon"
- />
- <TextView android:id="@+id/status_progress_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textColor="#ff000000"
- android:singleLine="true"
- android:textSize="14sp"
- android:layout_gravity="center_horizontal" />
- </LinearLayout>
-
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:focusable="true">
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:focusable="true"
- android:layout_alignParentTop="true"
- android:paddingTop="10dp">
- <TextView android:id="@+id/status_description"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textColor="?android:attr/textColorPrimary"
- android:singleLine="true"
- android:textSize="18sp"
- android:paddingLeft="5dp" />
- </LinearLayout>
- <ProgressBar
- android:id="@+id/status_progress_bar"
- style="?android:attr/progressBarStyleHorizontal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:paddingBottom="8dp"
- android:paddingRight="25dp" />
- </RelativeLayout>
- </LinearLayout>
-
- <ImageView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:src="@android:drawable/divider_horizontal_bright"
- />
-</LinearLayout>
-
diff --git a/res/values/strings.xml b/res/values/strings.xml
index accab64..a5e125d 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -269,6 +269,12 @@
<!-- 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 text displayed when there are no members in the group while displaying the group detail page [CHAR LIMIT=40] -->
+ <string name="emptyGroup">No people in this group.</string>
+
+ <!-- The text displayed to instruct users to add members to a group (when viewing a group detail page for a group with no members) [CHAR LIMIT=50] -->
+ <string name="addPeopleToGroup">To add some, edit the group.</string>
+
<!-- Displayed in a spinner dialog after the user creates a contact and it's being saved to the database -->
<string name="savingContact">Saving contact\u2026</string>
diff --git a/src/com/android/contacts/CallDetailActivity.java b/src/com/android/contacts/CallDetailActivity.java
index 541b7bf..caa8bce 100644
--- a/src/com/android/contacts/CallDetailActivity.java
+++ b/src/com/android/contacts/CallDetailActivity.java
@@ -294,7 +294,8 @@
public Void doInBackground(Void... params) {
ContentValues values = new ContentValues();
values.put(Voicemails.IS_READ, true);
- getContentResolver().update(voicemailUri, values, null, null);
+ getContentResolver().update(voicemailUri, values,
+ Voicemails.IS_READ + " = 0", null);
return null;
}
});
diff --git a/src/com/android/contacts/ContactLoader.java b/src/com/android/contacts/ContactLoader.java
index c9fbeae..c711b6c 100644
--- a/src/com/android/contacts/ContactLoader.java
+++ b/src/com/android/contacts/ContactLoader.java
@@ -19,6 +19,7 @@
import com.android.contacts.model.AccountType;
import com.android.contacts.model.AccountTypeManager;
import com.android.contacts.model.AccountTypeWithDataSet;
+import com.android.contacts.util.ContactLoaderUtils;
import com.android.contacts.util.DataStatus;
import com.android.contacts.util.StreamItemEntry;
import com.android.contacts.util.StreamItemPhotoEntry;
@@ -681,7 +682,8 @@
protected Result doInBackground(Void... args) {
try {
final ContentResolver resolver = getContext().getContentResolver();
- final Uri uriCurrentFormat = ensureIsContactUri(resolver, mLookupUri);
+ final Uri uriCurrentFormat = ContactLoaderUtils.ensureIsContactUri(
+ resolver, mLookupUri);
Result result = loadContactEntity(resolver, uriCurrentFormat);
if (!result.isNotFound()) {
if (result.isDirectoryEntry()) {
@@ -706,47 +708,6 @@
}
}
- /**
- * Transforms the given Uri and returns a Lookup-Uri that represents the contact.
- * For legacy contacts, a raw-contact lookup is performed.
- * @param resolver
- */
- private Uri ensureIsContactUri(final ContentResolver resolver, final Uri uri) {
- if (uri == null) throw new IllegalArgumentException("uri must not be null");
-
- final String authority = uri.getAuthority();
-
- // Current Style Uri?
- if (ContactsContract.AUTHORITY.equals(authority)) {
- final String type = resolver.getType(uri);
- // Contact-Uri? Good, return it
- if (Contacts.CONTENT_ITEM_TYPE.equals(type)) {
- return uri;
- }
-
- // RawContact-Uri? Transform it to ContactUri
- if (RawContacts.CONTENT_ITEM_TYPE.equals(type)) {
- final long rawContactId = ContentUris.parseId(uri);
- return RawContacts.getContactLookupUri(getContext().getContentResolver(),
- ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId));
- }
-
- // Anything else? We don't know what this is
- throw new IllegalArgumentException("uri format is unknown");
- }
-
- // Legacy Style? Convert to RawContact
- final String OBSOLETE_AUTHORITY = "contacts";
- if (OBSOLETE_AUTHORITY.equals(authority)) {
- // Legacy Format. Convert to RawContact-Uri and then lookup the contact
- final long rawContactId = ContentUris.parseId(uri);
- return RawContacts.getContactLookupUri(resolver,
- ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId));
- }
-
- throw new IllegalArgumentException("uri authority is unknown");
- }
-
private Result loadContactEntity(ContentResolver resolver, Uri contactUri) {
Uri entityUri = Uri.withAppendedPath(contactUri, Contacts.Entity.CONTENT_DIRECTORY);
Cursor cursor = resolver.query(entityUri, ContactQuery.COLUMNS, null, null,
diff --git a/src/com/android/contacts/activities/ActionBarAdapter.java b/src/com/android/contacts/activities/ActionBarAdapter.java
index 6d55184..77caaf7 100644
--- a/src/com/android/contacts/activities/ActionBarAdapter.java
+++ b/src/com/android/contacts/activities/ActionBarAdapter.java
@@ -75,6 +75,7 @@
private final MyTabListener mTabListener = new MyTabListener();
private boolean mShowHomeIcon;
+ private boolean mShowTabsAsText;
public enum TabState {
GROUPS,
@@ -98,7 +99,8 @@
private static final TabState DEFAULT_TAB = TabState.ALL;
private TabState mCurrentTab = DEFAULT_TAB;
- public ActionBarAdapter(Context context, Listener listener, ActionBar actionBar) {
+ public ActionBarAdapter(Context context, Listener listener, ActionBar actionBar,
+ boolean isUsingTwoPanes) {
mContext = context;
mListener = listener;
mActionBar = actionBar;
@@ -106,6 +108,9 @@
mShowHomeIcon = mContext.getResources().getBoolean(R.bool.show_home_icon);
+ // On wide screens, show the tabs as text (instead of icons)
+ mShowTabsAsText = isUsingTwoPanes;
+
// Set up search view.
View customSearchView = LayoutInflater.from(mActionBar.getThemedContext()).inflate(
R.layout.custom_action_bar, null);
@@ -153,12 +158,16 @@
mListener = listener;
}
- private void addTab(TabState tabState, int icon, int contentDescription) {
+ private void addTab(TabState tabState, int icon, int description) {
final Tab tab = mActionBar.newTab();
tab.setTag(tabState);
- tab.setIcon(icon);
- tab.setContentDescription(contentDescription);
tab.setTabListener(mTabListener);
+ if (mShowTabsAsText) {
+ tab.setText(description);
+ } else {
+ tab.setIcon(icon);
+ tab.setContentDescription(description);
+ }
mActionBar.addTab(tab);
}
@@ -211,14 +220,16 @@
return mCurrentTab;
}
+ /**
+ * @return Whether in search mode, i.e. if the search view is visible/expanded.
+ *
+ * Note even if the action bar is in search mode, if the query is empty, the search fragment
+ * will not be in search mode.
+ */
public boolean isSearchMode() {
return mSearchMode;
}
- public boolean shouldShowSearchResult() {
- return mSearchMode && !TextUtils.isEmpty(mQueryString);
- }
-
public void setSearchMode(boolean flag) {
if (mSearchMode != flag) {
mSearchMode = flag;
@@ -235,7 +246,7 @@
}
public String getQueryString() {
- return mQueryString;
+ return mSearchMode ? mQueryString : null;
}
public void setQueryString(String query) {
diff --git a/src/com/android/contacts/activities/ContactSelectionActivity.java b/src/com/android/contacts/activities/ContactSelectionActivity.java
index 6305d8e..e68c7bc 100644
--- a/src/com/android/contacts/activities/ContactSelectionActivity.java
+++ b/src/com/android/contacts/activities/ContactSelectionActivity.java
@@ -327,7 +327,6 @@
case ContactsRequest.ACTION_PICK_CONTACT: {
ContactPickerFragment fragment = new ContactPickerFragment();
- fragment.setSearchMode(mRequest.isSearchMode());
fragment.setIncludeProfile(mRequest.shouldIncludeProfile());
mListFragment = fragment;
break;
@@ -341,8 +340,6 @@
case ContactsRequest.ACTION_CREATE_SHORTCUT_CONTACT: {
ContactPickerFragment fragment = new ContactPickerFragment();
- fragment.setSearchMode(mRequest.isSearchMode());
- fragment.setQueryString(mRequest.getQueryString(), false);
fragment.setShortcutRequested(true);
mListFragment = fragment;
break;
@@ -362,7 +359,6 @@
case ContactsRequest.ACTION_CREATE_SHORTCUT_CALL: {
PhoneNumberPickerFragment fragment = new PhoneNumberPickerFragment();
fragment.setShortcutAction(Intent.ACTION_CALL);
- fragment.setSearchMode(mRequest.isSearchMode());
mListFragment = fragment;
break;
@@ -387,9 +383,6 @@
}
mListFragment.setLegacyCompatibilityMode(mRequest.isLegacyCompatibilityMode());
- mListFragment.setContactsRequest(mRequest);
- mListFragment.setSearchMode(mRequest.isSearchMode());
- mListFragment.setQueryString(mRequest.getQueryString(), false);
mListFragment.setDirectoryResultLimit(DEFAULT_DIRECTORY_RESULT_LIMIT);
getFragmentManager().beginTransaction()
@@ -537,7 +530,6 @@
@Override
public boolean onQueryTextChange(String newText) {
mListFragment.setQueryString(newText, true);
- mListFragment.setSearchMode(!TextUtils.isEmpty(newText));
return false;
}
diff --git a/src/com/android/contacts/activities/DialtactsActivity.java b/src/com/android/contacts/activities/DialtactsActivity.java
index 571a988..15724c1 100644
--- a/src/com/android/contacts/activities/DialtactsActivity.java
+++ b/src/com/android/contacts/activities/DialtactsActivity.java
@@ -363,7 +363,6 @@
public boolean onQueryTextChange(String newText) {
// Show search result with non-empty text. Show a bare list otherwise.
mSearchFragment.setQueryString(newText, true);
- mSearchFragment.setSearchMode(!TextUtils.isEmpty(newText));
return true;
}
};
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index b68f566..6f4089c 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -317,7 +317,8 @@
final FragmentTransaction transaction = fragmentManager.beginTransaction();
// Prepare the fragments which are used both on 1-pane and on 2-pane.
- if (PhoneCapabilityTester.isUsingTwoPanes(this)) {
+ boolean isUsingTwoPanes = PhoneCapabilityTester.isUsingTwoPanes(this);
+ if (isUsingTwoPanes) {
mFavoritesFragment = getFragment(R.id.favorites_fragment);
mAllFragment = getFragment(R.id.all_fragment);
mGroupsFragment = getFragment(R.id.groups_fragment);
@@ -367,7 +368,7 @@
transaction.hide(mAllFragment);
transaction.hide(mGroupsFragment);
- if (PhoneCapabilityTester.isUsingTwoPanes(this)) {
+ if (isUsingTwoPanes) {
// Prepare 2-pane only fragments/views...
// Container views for fragments
@@ -410,7 +411,7 @@
}
// Configure action bar
- mActionBarAdapter = new ActionBarAdapter(this, this, getActionBar());
+ mActionBarAdapter = new ActionBarAdapter(this, this, getActionBar(), isUsingTwoPanes);
mActionBarAdapter.initialize(savedState, mRequest);
invalidateOptionsMenuIfNeeded();
@@ -566,12 +567,12 @@
invalidateOptionsMenu();
break;
case STOP_SEARCH_MODE:
- clearSearch();
+ setQueryTextToFragment("");
updateFragmentsVisibility();
invalidateOptionsMenu();
break;
case CHANGE_SEARCH_QUERY:
- loadSearch(mActionBarAdapter.getQueryString());
+ setQueryTextToFragment(mActionBarAdapter.getQueryString());
break;
default:
throw new IllegalStateException("Unkonwn ActionBarAdapter action: " + action);
@@ -842,26 +843,19 @@
}
}
- private void clearSearch() {
- loadSearch("");
- }
-
- private void loadSearch(String query) {
- configureFragments(false /* from request */);
+ private void setQueryTextToFragment(String query) {
mAllFragment.setQueryString(query, true);
+ mAllFragment.setVisibleScrollbarEnabled(!mAllFragment.isSearchMode());
}
private void configureContactListFragmentForRequest() {
- mAllFragment.setContactsRequest(mRequest);
-
Uri contactUri = mRequest.getContactUri();
if (contactUri != null) {
mAllFragment.setSelectedContactUri(contactUri);
}
mAllFragment.setFilter(mContactListFilterController.getFilter());
- mAllFragment.setSearchMode(mActionBarAdapter.isSearchMode());
- mAllFragment.setQueryString(mActionBarAdapter.getQueryString(), false);
+ setQueryTextToFragment(mActionBarAdapter.getQueryString());
if (mRequest.isDirectorySearchEnabled()) {
mAllFragment.setDirectorySearchMode(DirectoryListLoader.SEARCH_MODE_DEFAULT);
@@ -874,11 +868,7 @@
// Filter may be changed when this Activity is in background.
mAllFragment.setFilter(mContactListFilterController.getFilter());
- final boolean showSearchResult = mActionBarAdapter.shouldShowSearchResult();
- mAllFragment.setSearchMode(showSearchResult);
-
final boolean useTwoPane = PhoneCapabilityTester.isUsingTwoPanes(this);
- mAllFragment.setVisibleScrollbarEnabled(!showSearchResult);
mAllFragment.setVerticalScrollbarPosition(
useTwoPane
? View.SCROLLBAR_POSITION_LEFT
diff --git a/src/com/android/contacts/detail/ContactDetailLayoutController.java b/src/com/android/contacts/detail/ContactDetailLayoutController.java
index 4b31a6e..2bcd1a0 100644
--- a/src/com/android/contacts/detail/ContactDetailLayoutController.java
+++ b/src/com/android/contacts/detail/ContactDetailLayoutController.java
@@ -324,7 +324,7 @@
// Update ViewPager to disable swipe so that it only shows the detail fragment
// and switch to the detail fragment
mViewPagerAdapter.enableSwipe(false);
- mViewPager.setCurrentItem(0);
+ mViewPager.setCurrentItem(0, false /* smooth transition */);
break;
case FRAGMENT_CAROUSEL: {
// Disable swipe so only the detail fragment shows
diff --git a/src/com/android/contacts/group/GroupDetailFragment.java b/src/com/android/contacts/group/GroupDetailFragment.java
index d4f6e29..b3472ab 100644
--- a/src/com/android/contacts/group/GroupDetailFragment.java
+++ b/src/com/android/contacts/group/GroupDetailFragment.java
@@ -98,6 +98,7 @@
private TextView mGroupTitle;
private TextView mGroupSize;
private ListView mMemberListView;
+ private View mEmptyView;
private Listener mListener;
@@ -149,6 +150,7 @@
mGroupSize = (TextView) mRootView.findViewById(R.id.group_size);
mGroupSourceViewContainer = (ViewGroup) mRootView.findViewById(
R.id.group_source_view_container);
+ mEmptyView = mRootView.findViewById(android.R.id.empty);
mMemberListView = (ListView) mRootView.findViewById(android.R.id.list);
mMemberListView.setAdapter(mAdapter);
@@ -258,6 +260,7 @@
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
updateSize(data.getCount());
mAdapter.setContactCursor(data);
+ mMemberListView.setEmptyView(mEmptyView);
}
@Override
diff --git a/src/com/android/contacts/list/ContactBrowseListFragment.java b/src/com/android/contacts/list/ContactBrowseListFragment.java
index 2d5fed1..061646e 100644
--- a/src/com/android/contacts/list/ContactBrowseListFragment.java
+++ b/src/com/android/contacts/list/ContactBrowseListFragment.java
@@ -17,10 +17,10 @@
import com.android.common.widget.CompositeCursorAdapter.Partition;
import com.android.contacts.R;
+import com.android.contacts.util.ContactLoaderUtils;
import com.android.contacts.widget.AutoScrollListView;
import android.app.Activity;
-import android.content.AsyncQueryHandler;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Loader;
@@ -28,6 +28,7 @@
import android.content.SharedPreferences.Editor;
import android.database.Cursor;
import android.net.Uri;
+import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -92,51 +93,64 @@
private String mPersistentSelectionPrefix = PERSISTENT_SELECTION_PREFIX;
protected OnContactBrowserActionListener mListener;
+ private ContactLookupTask mContactLookupTask;
- /**
- * Refreshes a contact URI: it may have changed as a result of aggregation
- * activity.
- */
- private class ContactUriQueryHandler extends AsyncQueryHandler {
+ private final class ContactLookupTask extends AsyncTask<Void, Void, Uri> {
- public ContactUriQueryHandler(ContentResolver cr) {
- super(cr);
- }
+ private final Uri mUri;
+ private boolean mIsCancelled;
- public void runQuery() {
- startQuery(0, mSelectedContactUri, mSelectedContactUri,
- new String[] { Contacts._ID, Contacts.LOOKUP_KEY }, null, null, null);
+ public ContactLookupTask(Uri uri) {
+ mUri = uri;
}
@Override
- protected void onQueryComplete(int token, Object cookie, Cursor data) {
- long contactId = 0;
- String lookupKey = null;
- if (data != null) {
- if (data.moveToFirst()) {
- contactId = data.getLong(0);
- lookupKey = data.getString(1);
- }
- data.close();
- }
+ protected Uri doInBackground(Void... args) {
+ Cursor cursor = null;
+ try {
+ final ContentResolver resolver = getContext().getContentResolver();
+ final Uri uriCurrentFormat = ContactLoaderUtils.ensureIsContactUri(resolver, mUri);
+ cursor = resolver.query(uriCurrentFormat,
+ new String[] { Contacts._ID, Contacts.LOOKUP_KEY }, null, null, null);
- if (!cookie.equals(mSelectedContactUri)) {
+ if (cursor != null && cursor.moveToFirst()) {
+ final long contactId = cursor.getLong(0);
+ final String lookupKey = cursor.getString(1);
+ if (contactId != 0 && !TextUtils.isEmpty(lookupKey)) {
+ return Contacts.getLookupUri(contactId, lookupKey);
+ }
+ }
+
+ Log.e(TAG, "Error: No contact ID or lookup key for contact " + mUri);
+ return null;
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ }
+
+ public void cancel() {
+ super.cancel(true);
+ // Use a flag to keep track of whether the {@link AsyncTask} was cancelled or not in
+ // order to ensure onPostExecute() is not executed after the cancel request. The flag is
+ // necessary because {@link AsyncTask} still calls onPostExecute() if the cancel request
+ // came after the worker thread was finished.
+ mIsCancelled = true;
+ }
+
+ @Override
+ protected void onPostExecute(Uri uri) {
+ // Make sure the {@link Fragment} is at least still attached to the {@link Activity}
+ // before continuing.
+ if (mIsCancelled || !isAdded() || uri == null) {
return;
}
-
- Uri uri;
- if (contactId != 0 && lookupKey != null) {
- uri = Contacts.getLookupUri(contactId, lookupKey);
- } else {
- uri = null;
- }
-
- onContactUriQueryFinished(uri);
+ mSelectedContactUri = uri;
+ onContactUriQueryFinished(mSelectedContactUri);
}
}
- private ContactUriQueryHandler mQueryHandler;
-
private boolean mDelaySelection;
private Handler getHandler() {
@@ -158,14 +172,13 @@
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
- mQueryHandler = new ContactUriQueryHandler(activity.getContentResolver());
mPrefs = PreferenceManager.getDefaultSharedPreferences(activity);
restoreFilter();
restoreSelectedUri(false);
}
@Override
- public void setSearchMode(boolean flag) {
+ protected void setSearchMode(boolean flag) {
if (isSearchMode() != flag) {
if (!flag) {
restoreSelectedUri(true);
@@ -228,12 +241,10 @@
}
protected void refreshSelectedContactUri() {
- if (mQueryHandler == null) {
- return;
+ if (mContactLookupTask != null) {
+ mContactLookupTask.cancel();
}
- mQueryHandler.cancelOperation(0);
-
if (!isSelectionVisible()) {
return;
}
@@ -249,7 +260,8 @@
&& mSelectedContactDirectoryId != Directory.LOCAL_INVISIBLE) {
onContactUriQueryFinished(mSelectedContactUri);
} else {
- mQueryHandler.runQuery();
+ mContactLookupTask = new ContactLookupTask(mSelectedContactUri);
+ mContactLookupTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
}
}
diff --git a/src/com/android/contacts/list/ContactEntryListFragment.java b/src/com/android/contacts/list/ContactEntryListFragment.java
index 91c582c..8b9aaf5 100644
--- a/src/com/android/contacts/list/ContactEntryListFragment.java
+++ b/src/com/android/contacts/list/ContactEntryListFragment.java
@@ -108,7 +108,6 @@
private String mQueryString;
private int mDirectorySearchMode = DirectoryListLoader.SEARCH_MODE_NONE;
private boolean mSelectionVisible;
- private ContactsRequest mRequest;
private boolean mLegacyCompatibility;
private boolean mEnabled = true;
@@ -249,7 +248,6 @@
outState.putBoolean(KEY_LEGACY_COMPATIBILITY, mLegacyCompatibility);
outState.putString(KEY_QUERY_STRING, mQueryString);
outState.putInt(KEY_DIRECTORY_RESULT_LIMIT, mDirectoryResultLimit);
- outState.putParcelable(KEY_REQUEST, mRequest);
outState.putBoolean(KEY_DARK_THEME, mDarkTheme);
if (mListView != null) {
@@ -282,27 +280,12 @@
mLegacyCompatibility = savedState.getBoolean(KEY_LEGACY_COMPATIBILITY);
mQueryString = savedState.getString(KEY_QUERY_STRING);
mDirectoryResultLimit = savedState.getInt(KEY_DIRECTORY_RESULT_LIMIT);
- mRequest = savedState.getParcelable(KEY_REQUEST);
mDarkTheme = savedState.getBoolean(KEY_DARK_THEME);
// Retrieve list state. This will be applied in onLoadFinished
mListState = savedState.getParcelable(KEY_LIST_STATE);
}
- /**
- * Returns the parsed intent that started the activity hosting this fragment.
- */
- public ContactsRequest getContactsRequest() {
- return mRequest;
- }
-
- /**
- * Sets a parsed intent that started the activity hosting this fragment.
- */
- public void setContactsRequest(ContactsRequest request) {
- mRequest = request;
- }
-
@Override
public void onStart() {
super.onStart();
@@ -608,7 +591,14 @@
}
}
- public void setSearchMode(boolean flag) {
+ /**
+ * Enter/exit search mode. By design, a fragment enters search mode only when it has a
+ * non-empty query text, so the mode must be tightly related to the current query.
+ * For this reason this method must only be called by {@link #setQueryString}.
+ *
+ * Also note this method doesn't call {@link #reloadData()}; {@link #setQueryString} does it.
+ */
+ protected void setSearchMode(boolean flag) {
if (mSearchMode != flag) {
mSearchMode = flag;
setSectionHeaderDisplayEnabled(!mSearchMode);
@@ -632,7 +622,6 @@
}
}
mAdapter.configureDefaultPartition(false, flag);
- reloadData();
}
if (mListView != null) {
@@ -641,17 +630,22 @@
}
}
- public boolean isSearchMode() {
+ public final boolean isSearchMode() {
return mSearchMode;
}
- public String getQueryString() {
+ public final String getQueryString() {
return mQueryString;
}
public void setQueryString(String queryString, boolean delaySelection) {
+ // Normalize the empty query.
+ if (TextUtils.isEmpty(queryString)) queryString = null;
+
if (!TextUtils.equals(mQueryString, queryString)) {
mQueryString = queryString;
+ setSearchMode(!TextUtils.isEmpty(mQueryString));
+
if (mAdapter != null) {
mAdapter.setQueryString(queryString);
reloadData();
diff --git a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
index 30c3c48..a6700b5 100644
--- a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
+++ b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
@@ -120,7 +120,7 @@
}
@Override
- public void setSearchMode(boolean flag) {
+ protected void setSearchMode(boolean flag) {
super.setSearchMode(flag);
checkHeaderViewVisibility();
}
diff --git a/src/com/android/contacts/list/PhoneFavoriteMergedAdapter.java b/src/com/android/contacts/list/PhoneFavoriteMergedAdapter.java
index f817b4c..0df4b3d 100644
--- a/src/com/android/contacts/list/PhoneFavoriteMergedAdapter.java
+++ b/src/com/android/contacts/list/PhoneFavoriteMergedAdapter.java
@@ -186,7 +186,7 @@
} else if (position == contactTileAdapterCount) {
return mAccountFilterHeaderContainer.isEnabled();
} else {
- final int localPosition = position - contactTileAdapterCount + 1;
+ final int localPosition = position - contactTileAdapterCount - 1;
return mContactEntryListAdapter.isEnabled(localPosition);
}
}
diff --git a/src/com/android/contacts/list/PhoneNumberPickerFragment.java b/src/com/android/contacts/list/PhoneNumberPickerFragment.java
index 64d5f13..602b06a 100644
--- a/src/com/android/contacts/list/PhoneNumberPickerFragment.java
+++ b/src/com/android/contacts/list/PhoneNumberPickerFragment.java
@@ -104,7 +104,7 @@
}
@Override
- public void setSearchMode(boolean flag) {
+ protected void setSearchMode(boolean flag) {
super.setSearchMode(flag);
updateFilterHeaderView();
}
diff --git a/src/com/android/contacts/util/ContactLoaderUtils.java b/src/com/android/contacts/util/ContactLoaderUtils.java
new file mode 100644
index 0000000..91c683f
--- /dev/null
+++ b/src/com/android/contacts/util/ContactLoaderUtils.java
@@ -0,0 +1,78 @@
+/*
+ * 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.util;
+
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.net.Uri;
+import android.provider.Contacts;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.RawContacts;
+
+/**
+ * Utility methods for the {@link ContactLoader}.
+ */
+public final class ContactLoaderUtils {
+
+ /** Static helper, not instantiable. */
+ private ContactLoaderUtils() {}
+
+ /**
+ * Transforms the given Uri and returns a Lookup-Uri that represents the contact.
+ * For legacy contacts, a raw-contact lookup is performed. An {@link IllegalArgumentException}
+ * can be thrown if the URI is null or the authority is not recognized.
+ *
+ * Do not call from the UI thread.
+ */
+ @SuppressWarnings("deprecation")
+ public static Uri ensureIsContactUri(final ContentResolver resolver, final Uri uri)
+ throws IllegalArgumentException {
+ if (uri == null) throw new IllegalArgumentException("uri must not be null");
+
+ final String authority = uri.getAuthority();
+
+ // Current Style Uri?
+ if (ContactsContract.AUTHORITY.equals(authority)) {
+ final String type = resolver.getType(uri);
+ // Contact-Uri? Good, return it
+ if (ContactsContract.Contacts.CONTENT_ITEM_TYPE.equals(type)) {
+ return uri;
+ }
+
+ // RawContact-Uri? Transform it to ContactUri
+ if (RawContacts.CONTENT_ITEM_TYPE.equals(type)) {
+ final long rawContactId = ContentUris.parseId(uri);
+ return RawContacts.getContactLookupUri(resolver,
+ ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId));
+ }
+
+ // Anything else? We don't know what this is
+ throw new IllegalArgumentException("uri format is unknown");
+ }
+
+ // Legacy Style? Convert to RawContact
+ final String OBSOLETE_AUTHORITY = Contacts.AUTHORITY;
+ if (OBSOLETE_AUTHORITY.equals(authority)) {
+ // Legacy Format. Convert to RawContact-Uri and then lookup the contact
+ final long rawContactId = ContentUris.parseId(uri);
+ return RawContacts.getContactLookupUri(resolver,
+ ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId));
+ }
+
+ throw new IllegalArgumentException("uri authority is unknown");
+ }
+}
diff --git a/src/com/android/contacts/vcard/NotificationImportExportListener.java b/src/com/android/contacts/vcard/NotificationImportExportListener.java
index fb83cec..06cf73f 100644
--- a/src/com/android/contacts/vcard/NotificationImportExportListener.java
+++ b/src/com/android/contacts/vcard/NotificationImportExportListener.java
@@ -197,30 +197,6 @@
/* package */ static Notification constructProgressNotification(
Context context, int type, String description, String tickerText,
int jobId, String displayName, int totalCount, int currentCount) {
- final RemoteViews remoteViews =
- new RemoteViews(context.getPackageName(),
- R.layout.status_bar_ongoing_event_progress_bar);
- remoteViews.setTextViewText(R.id.status_description, description);
- remoteViews.setProgressBar(R.id.status_progress_bar, totalCount, currentCount,
- totalCount == -1);
- final String percentage;
- if (totalCount > 0) {
- percentage = context.getString(R.string.percentage,
- String.valueOf(currentCount * 100/totalCount));
- } else {
- percentage = "";
- }
- remoteViews.setTextViewText(R.id.status_progress_text, percentage);
- final int icon = (type == VCardService.TYPE_IMPORT ? android.R.drawable.stat_sys_download :
- android.R.drawable.stat_sys_upload);
- remoteViews.setImageViewResource(R.id.status_icon, icon);
-
- final Notification notification = new Notification();
- notification.icon = icon;
- notification.tickerText = tickerText;
- notification.contentView = remoteViews;
- notification.flags |= Notification.FLAG_ONGOING_EVENT;
-
// Note: We cannot use extra values here (like setIntExtra()), as PendingIntent doesn't
// preserve them across multiple Notifications. PendingIntent preserves the first extras
// (when flag is not set), or update them when PendingIntent#getActivity() is called
@@ -238,8 +214,20 @@
.appendQueryParameter(CancelActivity.TYPE, String.valueOf(type)).build();
intent.setData(uri);
- notification.contentIntent = PendingIntent.getActivity(context, 0, intent, 0);
- return notification;
+ final Notification.Builder builder = new Notification.Builder(context);
+ builder.setOngoing(true)
+ .setProgress(totalCount, currentCount, totalCount == - 1)
+ .setTicker(tickerText)
+ .setContentTitle(description)
+ .setSmallIcon(type == VCardService.TYPE_IMPORT
+ ? android.R.drawable.stat_sys_download
+ : android.R.drawable.stat_sys_upload)
+ .setContentIntent(PendingIntent.getActivity(context, 0, intent, 0));
+ if (totalCount > 0) {
+ builder.setContentText(context.getString(R.string.percentage,
+ String.valueOf(currentCount * 100 / totalCount)));
+ }
+ return builder.getNotification();
}
/**