Merge "Add account header to label view."
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 72c6481..ed94546 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -16,8 +16,8 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.contacts"
-    android:versionCode="10503"
-    android:versionName="1.5.3">
+    android:versionCode="10504"
+    android:versionName="1.5.4">
 
     <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="23" />
     <original-package android:name="com.android.contacts" />
diff --git a/res/drawable-v21/drawer_item_background.xml b/res/drawable-v21/drawer_item_background.xml
new file mode 100644
index 0000000..cfc7761
--- /dev/null
+++ b/res/drawable-v21/drawer_item_background.xml
@@ -0,0 +1,27 @@
+<?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
+  -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+    android:color="@color/nav_item_selected_background">
+  <item>
+    <selector>
+      <item android:drawable="@color/nav_item_selected_background" android:state_checked="true"/>
+      <item android:drawable="@android:color/transparent"/>
+    </selector>
+  </item>
+</ripple>
\ No newline at end of file
diff --git a/res/drawable/drawer_item_background.xml b/res/drawable/drawer_item_background.xml
new file mode 100644
index 0000000..3ffe041
--- /dev/null
+++ b/res/drawable/drawer_item_background.xml
@@ -0,0 +1,22 @@
+<?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
+  -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+        <item android:state_checked="true" android:drawable="@color/nav_item_selected_background"/>
+        <item android:drawable="@android:color/transparent" />
+</selector>
\ No newline at end of file
diff --git a/res/layout/contacts_drawer_activity.xml b/res/layout/contacts_drawer_activity.xml
index 008d4f5..ad68e84 100644
--- a/res/layout/contacts_drawer_activity.xml
+++ b/res/layout/contacts_drawer_activity.xml
@@ -57,6 +57,7 @@
         android:layout_height="match_parent"
         android:layout_gravity="start"
         android:fitsSystemWindows="true"
+        app:itemBackground="@drawable/drawer_item_background"
         app:headerLayout="@layout/nav_header_main"
         app:menu="@menu/activity_main_drawer"/>
 
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 6a91140..8fa0e0d 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -21,6 +21,8 @@
 
     <color name="action_bar_background">#0288d1</color>
 
+    <color name="nav_item_selected_background">#0f000000</color>
+
     <color name="background_social_updates">#ffeeeeee</color>
 
     <color name="action_bar_button_text_color">#FFFFFF</color>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index aaf4202..12471ef 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -59,6 +59,9 @@
     <!-- Activity title when the user is selecting a contact.  [CHAR LIMIT=128] -->
     <string name="contactPickerActivityTitle">Choose a contact</string>
 
+    <!-- Activity title when the user is selecting a new label member. [CHAR LIMIT=128] -->
+    <string name="groupMemberPickerActivityTitle">Select</string>
+
     <!-- Entry that prompts user to select a newly created contact.  [CHAR LIMIT=30] -->
     <string name="header_entry_contact_list_adapter_header_title">Create new contact</string>
 
diff --git a/src/com/android/contacts/ContactsDrawerActivity.java b/src/com/android/contacts/ContactsDrawerActivity.java
index 888db49..a8c8956 100644
--- a/src/com/android/contacts/ContactsDrawerActivity.java
+++ b/src/com/android/contacts/ContactsDrawerActivity.java
@@ -49,6 +49,7 @@
 import com.android.contacts.common.util.ViewUtil;
 import com.android.contacts.editor.ContactEditorFragment;
 import com.android.contacts.group.GroupListItem;
+import com.android.contacts.group.GroupMetadata;
 import com.android.contacts.group.GroupUtil;
 import com.android.contacts.group.GroupsFragment;
 import com.android.contacts.group.GroupsFragment.GroupsListener;
@@ -59,7 +60,11 @@
 import com.android.contactsbind.Assistants;
 import com.android.contactsbind.HelpUtils;
 
+import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
 
 /**
  * A common superclass for Contacts activities with a navigation drawer.
@@ -81,6 +86,13 @@
     protected GroupsFragment mGroupsFragment;
     protected AccountFiltersFragment mAccountFiltersFragment;
 
+    // Checkable menu item lookup maps. Every map declared here should be added to
+    // clearCheckedMenus() so that they can be cleared.
+    // TODO find a better way to handle selected menu item state, when swicthing to fragments.
+    protected Map<Long, MenuItem> mGroupMenuMap = new HashMap<>();
+    protected Map<ContactListFilter, MenuItem> mFilterMenuMap = new HashMap<>();
+    protected Map<Integer, MenuItem> mIdMenuMap = new HashMap<>();
+
     @Override
     protected void onCreate(Bundle savedState) {
         super.onCreate(savedState);
@@ -109,6 +121,10 @@
         mNavigationView.setNavigationItemSelectedListener(this);
 
         final Menu menu = mNavigationView.getMenu();
+
+        final MenuItem allContacts = menu.findItem(R.id.nav_all_contacts);
+        mIdMenuMap.put(R.id.nav_all_contacts, allContacts);
+
         final boolean showBlockedNumbers = PhoneCapabilityTester.isPhone(this)
                 && ContactsUtils.FLAG_N_FEATURE
                 && BlockedNumberContractCompat.canCurrentUserBlockNumbers(this);
@@ -119,6 +135,9 @@
 
         if (Assistants.getDuplicatesActivityIntent(this) == null) {
             menu.removeItem(R.id.nav_find_duplicates);
+        } else {
+            final MenuItem findDup = menu.findItem(R.id.nav_find_duplicates);
+            mIdMenuMap.put(R.id.nav_find_duplicates, findDup);
         }
 
         if (!HelpUtils.isHelpAndFeedbackAvailable()) {
@@ -126,6 +145,19 @@
         }
 
         loadGroupsAndFilters();
+
+        if (isDuplicatesActivity()) {
+            clearCheckedMenus();
+            mIdMenuMap.get(R.id.nav_find_duplicates).setCheckable(true);
+            mIdMenuMap.get(R.id.nav_find_duplicates).setChecked(true);
+        }
+    }
+
+    /**
+     * Returns true if child class is DuplicatesActivity
+     */
+    protected boolean isDuplicatesActivity() {
+        return false;
     }
 
     // Set up fragment manager to load groups and filters.
@@ -174,6 +206,7 @@
         final MenuItem groupsMenuItem = menu.findItem(R.id.nav_groups);
         final SubMenu subMenu = groupsMenuItem.getSubMenu();
         subMenu.removeGroup(R.id.nav_groups_items);
+        mGroupMenuMap = new HashMap<>();
 
         if (groupListItems != null) {
             // Add each group
@@ -184,6 +217,7 @@
                 final String title = groupListItem.getTitle();
                 final MenuItem menuItem =
                         subMenu.add(R.id.nav_groups_items, Menu.NONE, Menu.NONE, title);
+                mGroupMenuMap.put(groupListItem.getGroupId(), menuItem);
                 menuItem.setIcon(R.drawable.ic_menu_label);
                 menuItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
                     @Override
@@ -211,6 +245,27 @@
                 return true;
             }
         });
+
+        if (getGroupMetadata() != null) {
+            updateGroupMenu(getGroupMetadata());
+        }
+    }
+
+    protected void updateGroupMenu(GroupMetadata groupMetadata) {
+        clearCheckedMenus();
+        if (groupMetadata != null && mGroupMenuMap != null
+                && mGroupMenuMap.get(groupMetadata.groupId) != null) {
+            mGroupMenuMap.get(groupMetadata.groupId).setCheckable(true);
+            mGroupMenuMap.get(groupMetadata.groupId).setChecked(true);
+        }
+    }
+
+    /**
+     * Returns group metadata if the child class is {@link GroupMembersActivity}, and null
+     * otherwise.
+     */
+    protected GroupMetadata getGroupMetadata() {
+        return null;
     }
 
     protected void onGroupMenuItemClicked(long groupId) {
@@ -229,6 +284,7 @@
         final MenuItem filtersMenuItem = menu.findItem(R.id.nav_filters);
         final SubMenu subMenu = filtersMenuItem.getSubMenu();
         subMenu.removeGroup(R.id.nav_filters_items);
+        mFilterMenuMap = new HashMap<>();
 
         if (accountFilterItems == null || accountFilterItems.size() < 2) {
             return;
@@ -239,6 +295,7 @@
             final String accountName = filter.accountName;
             final MenuItem menuItem = subMenu.add(R.id.nav_filters_items, Menu.NONE, Menu.NONE,
                     accountName);
+            mFilterMenuMap.put(filter, menuItem);
             final Intent intent = new Intent();
             intent.putExtra(AccountFilterUtil.EXTRA_CONTACT_LIST_FILTER, filter);
             menuItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@@ -257,10 +314,36 @@
             // Get rid of the default memu item overlay and show original account icons.
             menuItem.getIcon().setColorFilter(Color.TRANSPARENT, PorterDuff.Mode.SRC_ATOP);
         }
+
+        if (getContactListFilter() != null) {
+            updateFilterMenu(getContactListFilter());
+        }
+    }
+
+    protected void updateFilterMenu(ContactListFilter filter) {
+        clearCheckedMenus();
+        if (filter.filterType == ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS) {
+            if (mIdMenuMap != null && mIdMenuMap.get(R.id.nav_all_contacts) != null) {
+                mIdMenuMap.get(R.id.nav_all_contacts).setCheckable(true);
+                mIdMenuMap.get(R.id.nav_all_contacts).setChecked(true);
+            }
+        } else {
+            if (mFilterMenuMap != null && mFilterMenuMap.get(filter) != null) {
+                mFilterMenuMap.get(filter).setCheckable(true);
+                mFilterMenuMap.get(filter).setChecked(true);
+            }
+        }
     }
 
     /**
-     * @return true if the child activity should finish after launching another activity.
+     * Returns the current filter if the child class is {@link PeopleActivity}, and null otherwise.
+     */
+    protected ContactListFilter getContactListFilter() {
+        return null;
+    }
+
+    /**
+     * Returns true if the child activity should finish after launching another activity.
      */
     protected abstract boolean shouldFinish();
 
@@ -318,4 +401,18 @@
         return ContactListFilter.createFilterWithType(ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS);
     }
 
+    private void clearCheckedMenus() {
+        clearCheckedMenu(mFilterMenuMap);
+        clearCheckedMenu(mGroupMenuMap);
+        clearCheckedMenu(mIdMenuMap);
+    }
+
+    private void clearCheckedMenu(Map<?, MenuItem> map) {
+        final Iterator it = map.entrySet().iterator();
+        while (it.hasNext()) {
+            Entry pair = (Entry)it.next();
+            map.get(pair.getKey()).setCheckable(false);
+            map.get(pair.getKey()).setChecked(false);
+        }
+    }
 }
diff --git a/src/com/android/contacts/activities/ContactSelectionActivity.java b/src/com/android/contacts/activities/ContactSelectionActivity.java
index e314984..71ab0e7 100644
--- a/src/com/android/contacts/activities/ContactSelectionActivity.java
+++ b/src/com/android/contacts/activities/ContactSelectionActivity.java
@@ -242,7 +242,7 @@
                 break;
             }
             case ContactsRequest.ACTION_PICK_GROUP_MEMBERS: {
-                titleResId = R.string.contactPickerActivityTitle;
+                titleResId = R.string.groupMemberPickerActivityTitle;
                 break;
             }
         }
diff --git a/src/com/android/contacts/activities/GroupMembersActivity.java b/src/com/android/contacts/activities/GroupMembersActivity.java
index 05902da..0577ae7 100644
--- a/src/com/android/contacts/activities/GroupMembersActivity.java
+++ b/src/com/android/contacts/activities/GroupMembersActivity.java
@@ -381,6 +381,10 @@
         finish();
     }
 
+    public boolean isEditMode() {
+        return mIsEditMode;
+    }
+
     @Override
     public boolean onCreateOptionsMenu(Menu menu) {
         if (mGroupMetadata == null) {
@@ -398,7 +402,7 @@
         final boolean isGroupEditable = mGroupMetadata != null && mGroupMetadata.editable;
         final boolean isGroupReadOnly = mGroupMetadata != null && mGroupMetadata.readOnly;
 
-        setVisible(menu, R.id.menu_add, isGroupEditable && !isSelectionMode);
+        setVisible(menu, R.id.menu_add, isGroupEditable && mIsEditMode);
         setVisible(menu, R.id.menu_rename_group, !isGroupReadOnly && !isSelectionMode);
         setVisible(menu, R.id.menu_delete_group, !isGroupReadOnly && !isSelectionMode);
         setVisible(menu, R.id.menu_edit_group, isGroupEditable && !mIsEditMode && !isSelectionMode);
@@ -666,11 +670,14 @@
         }
     }
 
-    // GroupsMembersListFragment callbacks
+    // GroupMembersFragment callbacks
 
     @Override
     public void onGroupMetadataLoaded(GroupMetadata groupMetadata) {
         mGroupMetadata = groupMetadata;
+
+        updateGroupMenu(mGroupMetadata);
+
         if (!mIsInsertAction) {
             setActionBarTitle(mGroupMetadata.groupName);
         }
@@ -690,6 +697,11 @@
     }
 
     @Override
+    protected GroupMetadata getGroupMetadata() {
+        return mGroupMetadata;
+    }
+
+    @Override
     public void onGroupMemberListItemClicked(int position, Uri contactLookupUri) {
         final int count = mMembersFragment.getAdapter().getCount();
         Logger.logListEvent(ListEvent.ActionType.CLICK, ListEvent.ListType.GROUP, count,
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index 5e882f8..c03d62e 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -1392,6 +1392,9 @@
         final int listType =  filter.filterType == ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS
                 ? ListEvent.ListType.ALL_CONTACTS : ListEvent.ListType.ACCOUNT;
         mAllFragment.setListType(listType);
+
+        updateFilterMenu(filter);
+
         if (getSupportActionBar() != null) {
             final String actionBarTitle = TextUtils.isEmpty(filter.accountName) ?
                     getString(R.string.contactsList) : filter.accountName;
@@ -1413,4 +1416,9 @@
     protected boolean shouldFinish() {
         return false;
     }
+
+    @Override
+    protected ContactListFilter getContactListFilter() {
+        return mContactListFilterController.getFilter();
+    }
 }
diff --git a/src/com/android/contacts/group/GroupMembersFragment.java b/src/com/android/contacts/group/GroupMembersFragment.java
index 5ccfa24..98d66b4 100644
--- a/src/com/android/contacts/group/GroupMembersFragment.java
+++ b/src/com/android/contacts/group/GroupMembersFragment.java
@@ -15,6 +15,7 @@
  */
 package com.android.contacts.group;
 
+import android.app.Activity;
 import android.app.LoaderManager.LoaderCallbacks;
 import android.content.CursorLoader;
 import android.content.Loader;
@@ -31,6 +32,7 @@
 
 import com.android.contacts.GroupMetaDataLoader;
 import com.android.contacts.R;
+import com.android.contacts.activities.GroupMembersActivity;
 import com.android.contacts.common.list.ContactsSectionIndexer;
 import com.android.contacts.common.logging.ListEvent.ListType;
 import com.android.contacts.common.model.AccountTypeManager;
@@ -363,4 +365,15 @@
             }
         }
     }
+
+    @Override
+    protected boolean onItemLongClick(int position, long id) {
+        final Activity activity = getActivity();
+        if (activity != null && activity instanceof GroupMembersActivity) {
+            if (((GroupMembersActivity) activity).isEditMode()) {
+                return true;
+            }
+        }
+        return super.onItemLongClick(position, id);
+    }
 }
diff --git a/src/com/android/contacts/list/GroupMemberPickerFragment.java b/src/com/android/contacts/list/GroupMemberPickerFragment.java
index 03454a4..f4dde36 100644
--- a/src/com/android/contacts/list/GroupMemberPickerFragment.java
+++ b/src/com/android/contacts/list/GroupMemberPickerFragment.java
@@ -281,7 +281,7 @@
         // Added in ContactSelectionActivity but we must account for selection mode
         setVisible(menu, R.id.menu_search, !isSearchMode && !isSelectionMode);
 
-        setVisible(menu, R.id.menu_done, !isSearchMode && isSelectionMode &&
+        setVisible(menu, R.id.menu_done, isSelectionMode &&
                 getAdapter().getSelectedContactIds().size() > 0);
         setVisible(menu, R.id.menu_select, !isSearchMode && !isSelectionMode);
     }