Show count of contacts in account and group view
* Change contact list item height from 64dp to 56dp per b/29831679.
* Move name view in contact list item up by 2dp, per UX.
* Change the top padding to 8dp per b/29831679.
* Show the header in: account view, group member view and group member
picker view.
* Set top padding for list view only when there's no account header.
* Change action bar title to "From <account>" in account view.
* Override onScrollListener to hide and show header divider.
Bug 29190106
Bug 29831679
Change-Id: I36a2083c91b6b052bf887a8e7c639085d2bf4691
diff --git a/res/drawable/account_header_background.xml b/res/drawable/account_header_background.xml
new file mode 100644
index 0000000..af72c6d
--- /dev/null
+++ b/res/drawable/account_header_background.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2016 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
+ -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item>
+ <shape android:shape="rectangle">
+ <solid android:color="@color/list_item_account_header_border_color" />
+ </shape>
+ </item>
+ <item android:bottom="1dp">
+ <shape android:shape="rectangle">
+ <solid android:color="@color/background_primary" />
+ </shape>
+ </item>
+</layer-list>
\ No newline at end of file
diff --git a/res/values/colors.xml b/res/values/colors.xml
index d71363d..ee4f55a 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -60,6 +60,9 @@
<!-- Background color of pinned header items. -->
<color name="list_item_pinned_header_color">@color/background_primary</color>
+ <!-- 8% black. -->
+ <color name="list_item_account_header_border_color">#15000000</color>
+
<!-- Color of the mime-type icons inside the editor. 50% black. -->
<color name="editor_icon_color">#7f7f7f</color>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index dc263fc..2badc01 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -260,7 +260,9 @@
@dimen/contact_browser_list_item_photo_size) / 2 or greater. Otherwise, this padding
will never take affect inside list items. As a result, the padding at the very top
of ListView's will not match the padding inside list items -->
- <dimen name="contact_browser_list_item_padding_top_or_bottom">12dp</dimen>
+ <dimen name="contact_browser_list_item_padding_top_or_bottom">8dp</dimen>
+
+ <dimen name="contact_browser_list_item_height">56dp</dimen>
<!-- Ideal item width in photo picker -->
<dimen name="photo_picker_item_ideal_width">135dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index b765585..06e4ad7 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -206,6 +206,18 @@
<item quantity="other">Contacts deleted</item>
</plurals>
+ <!-- List header indicating the number of contacts in the list [CHAR LIMIT=30] -->
+ <plurals name="contacts_count">
+ <item quantity="one">1 contact</item>
+ <item quantity="other"><xliff:g id="count">%d</xliff:g> contacts</item>
+ </plurals>
+
+ <!-- Activity title indicating contacts are from a Google account [CHAR LIMIT=30] -->
+ <string name="title_from_google">From Google</string>
+
+ <!-- Activity title indicating contacts are from a specific account [CHAR LIMIT=15] -->
+ <string name="title_from_other_accounts">From <xliff:g id="account">%s</xliff:g></string>
+
<!-- Menu item that opens the Options activity for a given contact [CHAR LIMIT=15] -->
<string name="menu_set_ring_tone">Set ringtone</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 04252238..50d53dc 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -59,7 +59,7 @@
<item name="android:colorPrimary">@color/primary_color</item>
<item name="android:colorAccent">@color/primary_color</item>
<item name="android:alertDialogTheme">@style/ContactsAlertDialogTheme</item>
- <item name="list_item_height">?android:attr/listPreferredItemHeight</item>
+ <item name="list_item_height">@dimen/contact_browser_list_item_height</item>
<item name="activated_background">@drawable/list_item_activated_background</item>
<item name="section_header_background">@drawable/list_title_holo</item>
<item name="list_section_header_height">24dip</item>
@@ -91,6 +91,7 @@
<item name="contact_browser_list_padding_right">0dip</item>
<item name="contact_browser_background">@color/background_primary</item>
<item name="list_item_text_indent">@dimen/contact_browser_list_item_text_indent</item>
+ <item name="list_item_text_offset_top">-2dp</item>
<!-- Favorites -->
<item name="favorites_padding_bottom">0dip</item>
</style>
@@ -134,7 +135,7 @@
<item name="colorAccent">@color/primary_color</item>
<item name="android:alertDialogTheme">@style/ContactsAlertDialogThemeAppCompat</item>
<item name="alertDialogTheme">@style/ContactsAlertDialogThemeAppCompat</item>
- <item name="list_item_height">?android:attr/listPreferredItemHeight</item>
+ <item name="list_item_height">@dimen/contact_browser_list_item_height</item>
<item name="activated_background">@drawable/list_item_activated_background</item>
<item name="section_header_background">@drawable/list_title_holo</item>
<item name="list_section_header_height">24dip</item>
@@ -169,6 +170,7 @@
<item name="contact_browser_list_padding_right">0dip</item>
<item name="contact_browser_background">@color/background_primary</item>
<item name="list_item_text_indent">@dimen/contact_browser_list_item_text_indent</item>
+ <item name="list_item_text_offset_top">-2dp</item>
<!-- Favorites -->
<item name="favorites_padding_bottom">0dip</item>
<item name="drawerArrowStyle">@style/DrawerArrowStyle</item>
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index bde88f3..bad1dde 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -68,6 +68,7 @@
import com.android.contacts.common.logging.ScreenEvent.ScreenType;
import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.android.contacts.common.model.account.GoogleAccountType;
import com.android.contacts.common.util.Constants;
import com.android.contacts.common.util.ImplicitIntentsUtil;
import com.android.contacts.common.widget.FloatingActionButtonController;
@@ -1398,11 +1399,11 @@
updateFilterMenu(filter);
if (getSupportActionBar() != null) {
- String actionBarTitle = null;
+ String actionBarTitle;
if (filter.filterType == ContactListFilter.FILTER_TYPE_DEVICE_CONTACTS) {
actionBarTitle = getString(R.string.account_phone);
} else if (!TextUtils.isEmpty(filter.accountName)) {
- actionBarTitle = filter.accountName;
+ actionBarTitle = getActionBarTitleForAccount(filter);
} else {
actionBarTitle = getString(R.string.contactsList);
}
@@ -1410,6 +1411,13 @@
}
}
+ private String getActionBarTitleForAccount(ContactListFilter filter) {
+ if (GoogleAccountType.ACCOUNT_TYPE.equals(filter.accountType)) {
+ return getString(R.string.title_from_google);
+ }
+ return getString(R.string.title_from_other_accounts, filter.accountName);
+ }
+
// Persist filter only when it's of the type FILTER_TYPE_ALL_ACCOUNTS.
private void persistFilterIfNeeded(ContactListFilter filter) {
mContactListFilterController.setContactListFilter(filter,
diff --git a/src/com/android/contacts/group/GroupMembersFragment.java b/src/com/android/contacts/group/GroupMembersFragment.java
index 0d880e5..266e5fc 100644
--- a/src/com/android/contacts/group/GroupMembersFragment.java
+++ b/src/com/android/contacts/group/GroupMembersFragment.java
@@ -37,7 +37,6 @@
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
-import android.widget.TextView;
import com.android.contacts.GroupMetaDataLoader;
import com.android.contacts.R;
@@ -47,6 +46,7 @@
import com.android.contacts.common.logging.ListEvent.ListType;
import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.account.AccountType;
+import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.contacts.group.GroupMembersAdapter.GroupMembersQuery;
import com.android.contacts.list.MultiSelectContactsListFragment;
@@ -293,16 +293,13 @@
R.id.account_filter_header_container);
final View emptyGroupView = getView().findViewById(R.id.empty_group);
if (memberCount > 0) {
- accountFilterContainer.setVisibility(View.VISIBLE);
-
- final TextView accountFilterHeader = (TextView) accountFilterContainer.findViewById(
- R.id.account_filter_header);
- accountFilterHeader.setText(mGroupMetadata.accountName);
- accountFilterHeader.setAllCaps(false);
-
+ final AccountWithDataSet accountWithDataSet = new AccountWithDataSet(
+ mGroupMetadata.accountName, mGroupMetadata.accountType, mGroupMetadata.dataSet);
+ bindListHeader(getContext(), getListView(), accountFilterContainer,
+ accountWithDataSet, memberCount);
emptyGroupView.setVisibility(View.GONE);
} else {
- accountFilterContainer.setVisibility(View.GONE);
+ hideHeaderAndAddPadding(getContext(), getListView(), accountFilterContainer);
emptyGroupView.setVisibility(View.VISIBLE);
}
}
diff --git a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
index 6134047..fd6c0c0 100644
--- a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
+++ b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
@@ -17,22 +17,25 @@
import android.content.Context;
import android.content.CursorLoader;
+import android.content.Loader;
+import android.database.Cursor;
import android.net.Uri;
-import android.provider.ContactsContract.Contacts;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.widget.FrameLayout;
-import android.widget.ListView;
import android.widget.TextView;
import com.android.contacts.R;
import com.android.contacts.common.list.ContactListAdapter;
+import com.android.contacts.common.list.ContactListFilter;
+import com.android.contacts.common.list.ContactListFilterController;
import com.android.contacts.common.list.ContactListItemView;
import com.android.contacts.common.list.DefaultContactListAdapter;
import com.android.contacts.common.list.FavoritesAndContactsLoader;
+import com.android.contacts.common.model.account.AccountWithDataSet;
/**
* Fragment containing a contact list used for browsing (as compared to
@@ -59,6 +62,29 @@
}
@Override
+ public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
+ bindListHeader(data.getCount());
+ super.onLoadFinished(loader, data);
+ }
+
+ private void bindListHeader(int numberOfContacts) {
+ final View accountFilterContainer = getView().findViewById(
+ R.id.account_filter_header_container);
+ final ContactListFilterController contactListFilterController =
+ ContactListFilterController.getInstance(getContext());
+ final ContactListFilter filter = contactListFilterController.getFilter();
+ if (!isSearchMode()
+ && filter.filterType != ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS) {
+ final AccountWithDataSet accountWithDataSet = new AccountWithDataSet(
+ filter.accountName, filter.accountType, filter.dataSet);
+ bindListHeader(getContext(), getListView(), accountFilterContainer,
+ accountWithDataSet, numberOfContacts);
+ } else {
+ hideHeaderAndAddPadding(getContext(), getListView(), accountFilterContainer);
+ }
+ }
+
+ @Override
protected void onItemClick(int position, long id) {
final Uri uri = getAdapter().getContactUri(position);
if (uri == null) {
diff --git a/src/com/android/contacts/list/GroupMemberPickerFragment.java b/src/com/android/contacts/list/GroupMemberPickerFragment.java
index f4dde36..d981de0 100644
--- a/src/com/android/contacts/list/GroupMemberPickerFragment.java
+++ b/src/com/android/contacts/list/GroupMemberPickerFragment.java
@@ -28,7 +28,6 @@
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.TextView;
import com.android.contacts.activities.ContactSelectionActivity;
import com.android.contacts.common.R;
@@ -36,6 +35,7 @@
import com.android.contacts.common.list.ContactListFilter;
import com.android.contacts.common.list.ContactsSectionIndexer;
import com.android.contacts.common.list.DefaultContactListAdapter;
+import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.contacts.group.GroupUtil;
import java.util.ArrayList;
@@ -229,16 +229,15 @@
// Wait until contacts are loaded before showing the scrollbar
setVisibleScrollbarEnabled(true);
- // Bind account filter header.
+ final FilterCursorWrapper cursorWrapper = new FilterCursorWrapper(data);
final View accountFilterContainer = getView().findViewById(
R.id.account_filter_header_container);
- accountFilterContainer.setVisibility(View.VISIBLE);
- final TextView accountFilterHeader = (TextView) accountFilterContainer.findViewById(
- R.id.account_filter_header);
- accountFilterHeader.setText(mAccountName);
- accountFilterHeader.setAllCaps(false);
+ final AccountWithDataSet accountWithDataSet = new AccountWithDataSet(mAccountName,
+ mAccountType, mAccountDataSet);
+ bindListHeader(getContext(), getListView(), accountFilterContainer,
+ accountWithDataSet, cursorWrapper.getCount());
- super.onLoadFinished(loader, new FilterCursorWrapper(data));
+ super.onLoadFinished(loader, cursorWrapper);
}
}
diff --git a/src/com/android/contacts/list/MultiSelectContactsListFragment.java b/src/com/android/contacts/list/MultiSelectContactsListFragment.java
index 682f39b..af403ca 100644
--- a/src/com/android/contacts/list/MultiSelectContactsListFragment.java
+++ b/src/com/android/contacts/list/MultiSelectContactsListFragment.java
@@ -16,18 +16,30 @@
package com.android.contacts.list;
+import com.android.contacts.R;
import com.android.contacts.common.list.ContactEntryListFragment;
import com.android.contacts.common.list.MultiSelectEntryContactListAdapter;
import com.android.contacts.common.list.MultiSelectEntryContactListAdapter.SelectedContactsListener;
import com.android.contacts.common.logging.ListEvent.ActionType;
import com.android.contacts.common.logging.Logger;
import com.android.contacts.common.logging.SearchState;
+import com.android.contacts.common.model.AccountTypeManager;
+import com.android.contacts.common.model.account.AccountType;
+import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.android.contacts.common.model.account.GoogleAccountType;
+import android.content.Context;
import android.database.Cursor;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.util.Log;
+import android.view.View;
import android.view.accessibility.AccessibilityEvent;
+import android.widget.AbsListView;
+import android.widget.ImageView;
+import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
@@ -269,4 +281,69 @@
}
return searchState;
}
+
+ @Override
+ public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
+ int totalItemCount) {
+ final View accountFilterContainer = getView().findViewById(
+ R.id.account_filter_header_container);
+ if (accountFilterContainer == null) {
+ return;
+ }
+ if (firstVisibleItem == 0) {
+ accountFilterContainer.setBackground(
+ new ColorDrawable(getResources().getColor(R.color.background_primary)));
+ } else {
+ accountFilterContainer.setBackground(
+ getResources().getDrawable(R.drawable.account_header_background));
+ }
+ }
+
+ /**
+ * Show account icon, count of contacts and account name in the header of the list.
+ */
+ protected void bindListHeader(Context context, View listView, View accountFilterContainer,
+ AccountWithDataSet accountWithDataSet, int memberCount) {
+ if (memberCount < 0) {
+ hideHeaderAndAddPadding(context, listView, accountFilterContainer);
+ return;
+ }
+
+ // Show header and remove top padding of the list
+ accountFilterContainer.setVisibility(View.VISIBLE);
+ listView.setPadding(0, 0, 0, 0);
+
+ // Set text of count of contacts and account name (if it's a Google account)
+ final TextView accountFilterHeader = (TextView) accountFilterContainer.findViewById(
+ R.id.account_filter_header);
+ final String headerText = String.format(context.getResources().getQuantityString(
+ R.plurals.contacts_count, memberCount), memberCount);
+ final StringBuilder sb = new StringBuilder(headerText);
+ if (GoogleAccountType.ACCOUNT_TYPE.equals(accountWithDataSet.type)) {
+ sb.append(" \u00B7 "); // Unicode character 'MIDDLE DOT'
+ sb.append(accountWithDataSet.name);
+ }
+ accountFilterHeader.setText(sb.toString());
+ accountFilterHeader.setAllCaps(false);
+
+ // Set icon of the account
+ final AccountTypeManager accountTypeManager = AccountTypeManager.getInstance(context);
+ final AccountType accountType = accountTypeManager.getAccountType(
+ accountWithDataSet.type, accountWithDataSet.dataSet);
+ final Drawable icon = accountType != null ? accountType.getDisplayIcon(context) : null;
+ final ImageView accountFilterHeaderIcon = (ImageView) accountFilterContainer
+ .findViewById(R.id.account_filter_icon);
+ accountFilterHeaderIcon.setImageDrawable(icon);
+ }
+
+ /**
+ * Hide header of list view and add padding to the top of list view.
+ */
+ protected void hideHeaderAndAddPadding(Context context, View listView,
+ View accountFilterContainer) {
+ accountFilterContainer.setVisibility(View.GONE);
+ listView.setPadding(0, context.getResources().getDimensionPixelSize(
+ R.dimen.contact_browser_list_item_padding_top_or_bottom), 0, 0);
+ }
+
}