Merge "Exercise EXTRA_CALL_TYPE_FILTER in Contacts test app"
diff --git a/res/drawable-hdpi/ic_add_to_circles_black_24.png b/res/drawable-hdpi/ic_add_to_circles_black_24.png
new file mode 100644
index 0000000..6eb1fcc
--- /dev/null
+++ b/res/drawable-hdpi/ic_add_to_circles_black_24.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_google_plus_24dp.png b/res/drawable-hdpi/ic_google_plus_24dp.png
new file mode 100644
index 0000000..af17f2b
--- /dev/null
+++ b/res/drawable-hdpi/ic_google_plus_24dp.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_hangout_24dp.png b/res/drawable-hdpi/ic_hangout_24dp.png
new file mode 100644
index 0000000..496a2a0
--- /dev/null
+++ b/res/drawable-hdpi/ic_hangout_24dp.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_hangout_video_24dp.png b/res/drawable-hdpi/ic_hangout_video_24dp.png
new file mode 100644
index 0000000..0825a15
--- /dev/null
+++ b/res/drawable-hdpi/ic_hangout_video_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_add_to_circles_black_24.png b/res/drawable-mdpi/ic_add_to_circles_black_24.png
new file mode 100644
index 0000000..fbffc97
--- /dev/null
+++ b/res/drawable-mdpi/ic_add_to_circles_black_24.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_google_plus_24dp.png b/res/drawable-mdpi/ic_google_plus_24dp.png
new file mode 100644
index 0000000..d8eacf0
--- /dev/null
+++ b/res/drawable-mdpi/ic_google_plus_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_hangout_24dp.png b/res/drawable-mdpi/ic_hangout_24dp.png
new file mode 100644
index 0000000..1b0acfd
--- /dev/null
+++ b/res/drawable-mdpi/ic_hangout_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_hangout_video_24dp.png b/res/drawable-mdpi/ic_hangout_video_24dp.png
new file mode 100644
index 0000000..b54b1cb
--- /dev/null
+++ b/res/drawable-mdpi/ic_hangout_video_24dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_add_to_circles_black_24.png b/res/drawable-xhdpi/ic_add_to_circles_black_24.png
new file mode 100644
index 0000000..79116b5
--- /dev/null
+++ b/res/drawable-xhdpi/ic_add_to_circles_black_24.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_google_plus_24dp.png b/res/drawable-xhdpi/ic_google_plus_24dp.png
new file mode 100644
index 0000000..ea352d3
--- /dev/null
+++ b/res/drawable-xhdpi/ic_google_plus_24dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_hangout_24dp.png b/res/drawable-xhdpi/ic_hangout_24dp.png
new file mode 100644
index 0000000..0cd7795
--- /dev/null
+++ b/res/drawable-xhdpi/ic_hangout_24dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_hangout_video_24dp.png b/res/drawable-xhdpi/ic_hangout_video_24dp.png
new file mode 100644
index 0000000..97b984c
--- /dev/null
+++ b/res/drawable-xhdpi/ic_hangout_video_24dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_add_to_circles_black_24.png b/res/drawable-xxhdpi/ic_add_to_circles_black_24.png
new file mode 100644
index 0000000..23a2084
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_add_to_circles_black_24.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_google_plus_24dp.png b/res/drawable-xxhdpi/ic_google_plus_24dp.png
new file mode 100644
index 0000000..933cd62
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_google_plus_24dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_hangout_24dp.png b/res/drawable-xxhdpi/ic_hangout_24dp.png
new file mode 100644
index 0000000..16858d1
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_hangout_24dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_hangout_video_24dp.png b/res/drawable-xxhdpi/ic_hangout_video_24dp.png
new file mode 100644
index 0000000..4183c76
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_hangout_video_24dp.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_google_plus_24dp.png b/res/drawable-xxxhdpi/ic_google_plus_24dp.png
new file mode 100644
index 0000000..dcd6c97
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_google_plus_24dp.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_hangout_24dp.png b/res/drawable-xxxhdpi/ic_hangout_24dp.png
new file mode 100644
index 0000000..4bfdb0d
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_hangout_24dp.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_hangout_video_24dp.png b/res/drawable-xxxhdpi/ic_hangout_video_24dp.png
new file mode 100644
index 0000000..f1be2e7
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_hangout_video_24dp.png
Binary files differ
diff --git a/res/layout-sw600dp/contact_picker.xml b/res/layout-sw600dp/contact_picker.xml
deleted file mode 100644
index 558c604..0000000
--- a/res/layout-sw600dp/contact_picker.xml
+++ /dev/null
@@ -1,79 +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.
--->
-
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/ContactPickerLayout"
-    android:orientation="vertical"
-    android:layout_height="match_parent">
-    <!-- Right bound should be aligned to ListView's right edge. -->
-    <!--
-      The SearchView should have a max width to prevent the dialog from resizing to the
-      full screen width of the device. The precise value of the max width is not as important
-      because the SearchView can take on a smaller width than the max width, so in some cases it
-      will take on the automatically computed width of a dialog (based on the dialog contents)
-      from the framework.
-    -->
-    <view
-        class="android.widget.SearchView"
-        android:id="@+id/search_view"
-        android:layout_width="match_parent"
-        android:maxWidth="@dimen/contact_picker_search_view_max_width"
-        android:layout_height="wrap_content"
-        android:layout_marginLeft="0dip"
-        android:layout_marginRight="@dimen/list_visible_scrollbar_padding"
-        android:layout_marginStart="0dip"
-        android:layout_marginEnd="@dimen/list_visible_scrollbar_padding"
-        android:paddingRight="0dip"
-        android:paddingEnd="0dip"
-        android:iconifiedByDefault="false" />
-    <!--
-      This will contain an appropriate contacts list. Add a min height to prevent
-      the dialog from resizing too much when the search results change. The activity dialog
-      is wrap content for height in the framework, so there is no way around this.
-    -->
-    <FrameLayout
-        android:id="@+id/list_container"
-        android:layout_width="match_parent"
-        android:minHeight="@dimen/contact_picker_contact_list_min_height"
-        android:layout_height="0dip"
-        android:layout_weight="1" />
-
-    <!-- This should look like a menu on the split action bar. -->
-    <LinearLayout
-        android:id="@+id/new_contact"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:minHeight="48dip"
-        android:background="@drawable/gray_action_bar_background"
-        android:paddingLeft="16dip"
-        android:paddingRight="16dip"
-        android:paddingStart="16dip"
-        android:paddingEnd="16dip">
-        <TextView
-            android:id="@android:id/title"
-            android:layout_width="0dip"
-            android:layout_height="wrap_content"
-            android:layout_weight="1"
-            android:layout_gravity="center"
-            android:gravity="center"
-            android:duplicateParentState="true"
-            android:textAppearance="?android:attr/textAppearanceMedium"
-            android:textColor="@color/action_bar_button_text_color"
-            style="@android:style/Widget.Holo.Light.ActionBar.TabText"
-            android:text="@string/pickerNewContactText"/>
-    </LinearLayout>
-</LinearLayout>
diff --git a/res/layout/contact_picker.xml b/res/layout/contact_picker.xml
index 2752b0c..b6741cf 100644
--- a/res/layout/contact_picker.xml
+++ b/res/layout/contact_picker.xml
@@ -14,26 +14,16 @@
      limitations under the License.
 -->
 
-<view
+<RelativeLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    class="com.android.contacts.widget.FullHeightLinearLayout"
     style="@style/ContactPickerLayout"
-    android:orientation="vertical"
-    android:layout_height="match_parent">
-    <view
-        class="android.widget.SearchView"
-        android:id="@+id/search_view"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginLeft="0dip"
-        android:layout_marginRight="32dip"
-        android:layout_marginStart="0dip"
-        android:layout_marginEnd="32dip"
-        android:iconifiedByDefault="false" />
-    <!-- will contain an appropriate contacts list -->
+    android:layout_height="match_parent"
+    android:layout_width="match_parent">
+
     <FrameLayout
         android:id="@+id/list_container"
         android:layout_width="match_parent"
-        android:layout_height="0dip"
-        android:layout_weight="1" />
-</view>
+        android:layout_height="match_parent" />
+
+    <include layout="@layout/floating_action_button" />
+</RelativeLayout>
diff --git a/res/layout/expanding_entry_card_item.xml b/res/layout/expanding_entry_card_item.xml
index 46fc8cb..99738a6 100644
--- a/res/layout/expanding_entry_card_item.xml
+++ b/res/layout/expanding_entry_card_item.xml
@@ -26,11 +26,12 @@
 
     <ImageView
         android:id="@+id/icon"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
+        android:layout_width="@dimen/expanding_entry_card_item_icon_height"
+        android:layout_height="@dimen/expanding_entry_card_item_icon_width"
         android:layout_alignParentStart="true"
         android:layout_alignParentTop="true"
-        android:layout_marginEnd="@dimen/expanding_entry_card_item_image_spacing" />
+        android:layout_marginEnd="@dimen/expanding_entry_card_item_image_spacing"
+        android:scaleType="fitCenter" />
 
     <TextView
         android:id="@+id/header"
diff --git a/res/layout/floating_action_button.xml b/res/layout/floating_action_button.xml
new file mode 100644
index 0000000..dd41dbe
--- /dev/null
+++ b/res/layout/floating_action_button.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<!-- This expects to be included inside a RelativeLayout -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/floating_action_button_container"
+    android:layout_width="@dimen/floating_action_button_width"
+    android:layout_height="@dimen/floating_action_button_height"
+    android:layout_marginEnd="@dimen/floating_action_button_margin_right"
+    android:layout_marginBottom="@dimen/floating_action_button_margin_bottom"
+    android:layout_alignParentEnd="true"
+    android:layout_alignParentBottom="true">
+
+    <ImageButton
+        android:id="@+id/floating_action_button"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@drawable/floating_action_button"
+        android:contentDescription="@string/action_menu_add_new_contact_button"
+        android:src="@drawable/ic_person_add_24dp"/>
+</FrameLayout>
\ No newline at end of file
diff --git a/res/layout/people_activity.xml b/res/layout/people_activity.xml
index bcdf08f..6b65945 100644
--- a/res/layout/people_activity.xml
+++ b/res/layout/people_activity.xml
@@ -43,21 +43,5 @@
             android:layout_width="match_parent" />
     </FrameLayout>
 
-    <FrameLayout
-        android:id="@+id/floating_action_button_container"
-        android:layout_width="@dimen/floating_action_button_width"
-        android:layout_height="@dimen/floating_action_button_height"
-        android:layout_marginRight="@dimen/floating_action_button_margin_right"
-        android:layout_marginBottom="@dimen/floating_action_button_margin_bottom"
-        android:layout_alignParentRight="true"
-        android:layout_alignParentBottom="true">
-
-        <ImageButton
-            android:id="@+id/floating_action_button"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:background="@drawable/floating_action_button"
-            android:contentDescription="@string/action_menu_add_new_contact_button"
-            android:src="@drawable/ic_person_add_24dp"/>
-    </FrameLayout>
+    <include layout="@layout/floating_action_button" />
 </RelativeLayout>
diff --git a/res/menu-sw600dp/people_options.xml b/res/menu-sw600dp/people_options.xml
deleted file mode 100644
index 931b456..0000000
--- a/res/menu-sw600dp/people_options.xml
+++ /dev/null
@@ -1,63 +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.
--->
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
-    <item
-        android:id="@+id/menu_search"
-        android:icon="@drawable/ic_ab_search"
-        android:title="@string/menu_search"
-        android:showAsAction="ifRoom" />
-
-    <!-- Added orderInCategory to keep the following buttons at the end of the menu
-         Buttons will be added in the order added/inflated. Ordered buttons will be added
-         at the end according to the orderInCategory. This setup insures that the buttons below
-         will be the last buttons in the menu regardless of how many buttons are added
-    -->
-    <item
-        android:id="@+id/menu_contacts_filter"
-        android:orderInCategory="1"
-        android:title="@string/menu_contacts_filter" />
-
-    <item
-        android:id="@+id/menu_import_export"
-        android:orderInCategory="2"
-        android:title="@string/menu_import_export" />
-
-    <item
-        android:id="@+id/menu_clear_frequents"
-        android:orderInCategory="3"
-        android:title="@string/menu_clear_frequents" />
-
-    <item
-        android:id="@+id/menu_accounts"
-        android:orderInCategory="4"
-        android:title="@string/menu_accounts" />
-
-    <item
-        android:id="@+id/menu_settings"
-        android:orderInCategory="5"
-        android:title="@string/menu_settings" />
-
-    <item
-        android:id="@+id/menu_help"
-        android:orderInCategory="6"
-        android:title="@string/menu_help" />
-
-    <item
-        android:id="@+id/export_database"
-        android:title="@string/menu_export_database"
-        android:visible="false"
-        android:showAsAction="never" />
-</menu>
diff --git a/res/menu-sw600dp/view_contact.xml b/res/menu-sw600dp/view_contact.xml
deleted file mode 100644
index 5437dec..0000000
--- a/res/menu-sw600dp/view_contact.xml
+++ /dev/null
@@ -1,38 +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.
--->
-
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
-    <item
-        android:id="@+id/menu_edit"
-        android:icon="@drawable/ic_menu_compose_holo_light"
-        android:title="@string/menu_editContact"
-        android:alphabeticShortcut="e"
-        android:showAsAction="always"/>
-
-    <item
-        android:id="@+id/menu_share"
-        android:title="@string/menu_share"
-        android:alphabeticShortcut="s" />
-
-    <item
-        android:id="@+id/menu_delete"
-        android:title="@string/menu_deleteContact" />
-
-    <item
-        android:id="@+id/menu_create_contact_shortcut"
-        android:title="@string/menu_create_contact_shortcut" />
-
-</menu>
diff --git a/res/menu-sw600dp/view_group.xml b/res/menu-sw600dp/view_group.xml
deleted file mode 100644
index b61588c..0000000
--- a/res/menu-sw600dp/view_group.xml
+++ /dev/null
@@ -1,28 +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.
--->
-
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
-    <item
-        android:id="@+id/menu_edit_group"
-        android:icon="@drawable/ic_menu_compose_holo_light"
-        android:title="@string/menu_editGroup"
-        android:alphabeticShortcut="e"
-        android:showAsAction="always" />
-
-    <item
-        android:id="@+id/menu_delete_group"
-        android:title="@string/menu_deleteGroup" />
-</menu>
diff --git a/res/menu/contact_picker_options.xml b/res/menu/contact_picker_options.xml
deleted file mode 100644
index 89196ba..0000000
--- a/res/menu/contact_picker_options.xml
+++ /dev/null
@@ -1,22 +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.
--->
-<!-- Used with DialtactsActivity's search mode. -->
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
-    <item
-        android:id="@+id/create_new_contact"
-        android:title="@string/pickerNewContactText"
-        android:showAsAction="ifRoom" />
-</menu>
diff --git a/res/menu/people_options.xml b/res/menu/people_options.xml
index 4aae1a1..a7802f0 100644
--- a/res/menu/people_options.xml
+++ b/res/menu/people_options.xml
@@ -17,6 +17,7 @@
     <item
         android:id="@+id/menu_search"
         android:icon="@drawable/ic_ab_search"
+        android:title="@string/menu_search"
         android:showAsAction="ifRoom" />
 
     <item
diff --git a/res/menu/quickcontact.xml b/res/menu/quickcontact.xml
index 34a6a10..13caa59 100644
--- a/res/menu/quickcontact.xml
+++ b/res/menu/quickcontact.xml
@@ -15,13 +15,14 @@
 -->
 
 <menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <!-- Icon and titles are set in code for menu_star and menu_edit -->
+
     <item
         android:id="@+id/menu_star"
         android:showAsAction="always" />
 
     <item
         android:id="@+id/menu_edit"
-        android:icon="@drawable/ic_create_24dp"
         android:showAsAction="always" />
 
     <item
diff --git a/res/values-sw600dp-land/donottranslate_config.xml b/res/values-sw600dp-land/donottranslate_config.xml
deleted file mode 100644
index fe09771..0000000
--- a/res/values-sw600dp-land/donottranslate_config.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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.
-*/
--->
-
-<resources>
-    <bool name="config_browse_list_show_images">true</bool>
-    <bool name="config_use_two_panes_in_favorites">true</bool>
-    <bool name="config_browse_list_reverse_images">false</bool>
-</resources>
diff --git a/res/values-sw600dp/donottranslate_config.xml b/res/values-sw600dp/donottranslate_config.xml
deleted file mode 100644
index bbf37c1..0000000
--- a/res/values-sw600dp/donottranslate_config.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 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.
-*/
--->
-
-<resources>
-    <bool name="config_use_two_panes">true</bool>
-    <bool name="config_use_two_panes_in_favorites">false</bool>
-    <bool name="show_home_icon">true</bool>
-    <bool name="config_browse_list_show_images">false</bool>
-    <bool name="config_browse_list_reverse_images">false</bool>
-</resources>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index a04e9cd..b44f34b 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -60,4 +60,8 @@
 
     <!-- Background color of pinned header items. -->
     <color name="list_item_pinned_header_color">#f5f5f5</color>
+
+    <!-- The default color used for tinting photos when no color can be extracted via Palette,
+         this is Blue Grey 500 -->
+    <color name="quickcontact_default_photo_tint_color">#607D8B</color>
 </resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index ce04992..0e296fe 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -186,4 +186,6 @@
 
     <dimen name="people_activity_card_elevation">2dp</dimen>
 
+    <dimen name="expanding_entry_card_item_icon_height">24dp</dimen>
+    <dimen name="expanding_entry_card_item_icon_width">24dp</dimen>
 </resources>
diff --git a/res/values/donottranslate_config.xml b/res/values/donottranslate_config.xml
index 0d09967..5fc4f89 100644
--- a/res/values/donottranslate_config.xml
+++ b/res/values/donottranslate_config.xml
@@ -19,25 +19,9 @@
 
 <resources>
 
-    <!-- Flag indicating whether to show images in browse list -->
-    <bool name="config_browse_list_show_images">true</bool>
-
-    <!-- Whether to show images in the reverse from the default position in the browse list. -->
-    <bool name="config_browse_list_reverse_images">false</bool>
-
     <!-- If true, phonetic name is included in the contact editor by default -->
     <bool name="config_editor_include_phonetic_name">false</bool>
 
-    <!-- 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, Contacts uses two panes in the favorites view, one for starred and one for
-          frequently contacted.  If false, only one list is shown with starred on top and frequently
-          contacted listed below. Note: This should not be true if config_use_two_panes is
-          false. -->
-    <bool name="config_use_two_panes_in_favorites">false</bool>
-
     <!-- If true, the "home" icon on the action bar will be shown. -->
     <bool name="show_home_icon">false</bool>
 
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 9bd4621..085cacf 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -326,6 +326,9 @@
     <!-- The menu item to share the currently viewed contact [CHAR LIMIT=30] -->
     <string name="menu_share">Share</string>
 
+    <!-- The menu item to add the the currently viewed contact to your contacts [CHAR LIMIT=30] -->
+    <string name="menu_add_contact">Add to contacts</string>
+
     <!-- Dialog title when picking the application to share a contact with. -->
     <string name="share_via">Share contact via</string>
 
@@ -715,4 +718,7 @@
     <!-- Header for the Relation entry [CHAR LIMIT=40] -->
     <string name="header_relation_entry">Relation</string>
 
+    <!-- Content description for directions secondary button [CHAR LIMIT=NONE] -->
+    <string name="content_description_directions">directions to location</string>
+
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 5823ed7..57c9358 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -111,6 +111,11 @@
         <item name="android:icon">@android:color/transparent</item>
     </style>
 
+    <style name="ContactsPickerActionBarStyle" parent="@style/ContactsActionBarStyle">
+        <!-- when first loading, don't show title or up button -->
+        <item name="android:displayOptions"></item>
+    </style>
+
     <!-- Styling for tabs. -->
     <style name="ContactsActionBarTabStyle" parent="@android:style/Widget.Material.Light.ActionBar.TabView">
         <item name="android:background">@drawable/action_bar_tab</item>
@@ -163,7 +168,9 @@
         <item name="android:listSelector">?android:attr/listChoiceBackgroundIndicator</item>
     </style>
 
-    <style name="ContactPickerTheme" parent="@style/PeopleTheme" />
+    <style name="ContactPickerTheme" parent="@style/PeopleTheme" >
+        <item name="android:actionBarStyle">@style/ContactsPickerActionBarStyle</item>
+    </style>
 
     <style name="ContactPickerLayout" parent="ContactPickerTheme">
         <item name="android:layout_width">match_parent</item>
diff --git a/src/com/android/contacts/NfcHandler.java b/src/com/android/contacts/NfcHandler.java
index 3cd4b08..07b3f06 100644
--- a/src/com/android/contacts/NfcHandler.java
+++ b/src/com/android/contacts/NfcHandler.java
@@ -18,6 +18,7 @@
 
 import android.app.Activity;
 import android.content.ContentResolver;
+import android.content.Context;
 import android.net.Uri;
 import android.nfc.NdefMessage;
 import android.nfc.NdefRecord;
@@ -27,8 +28,6 @@
 import android.provider.ContactsContract.Profile;
 import android.util.Log;
 
-import com.android.contacts.detail.ContactDetailFragment;
-
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -45,27 +44,28 @@
 
     private static final String TAG = "ContactNfcHandler";
     private static final String PROFILE_LOOKUP_KEY = "profile";
-    private final ContactDetailFragment mContactFragment;
+    private final Context mContext;
+    private final Uri mContactUri;
 
-    public static void register(Activity activity, ContactDetailFragment contactFragment) {
+    /* Register NFC handler. This should be called in activities' onCreate(), or similar methods */
+    public static void register(Activity activity, Uri contactUri) {
         NfcAdapter adapter = NfcAdapter.getDefaultAdapter(activity.getApplicationContext());
         if (adapter == null) {
             return;  // NFC not available on this device
         }
-        adapter.setNdefPushMessageCallback(new NfcHandler(contactFragment), activity);
+        adapter.setNdefPushMessageCallback(new NfcHandler(activity, contactUri), activity);
     }
 
-    public NfcHandler(ContactDetailFragment contactFragment) {
-        mContactFragment = contactFragment;
+    public NfcHandler(Context context, Uri contactUri) {
+        mContext = context;
+        mContactUri = contactUri;
     }
 
     @Override
     public NdefMessage createNdefMessage(NfcEvent event) {
-        // Get the current contact URI
-        Uri contactUri = mContactFragment.getUri();
-        ContentResolver resolver = mContactFragment.getActivity().getContentResolver();
-        if (contactUri != null) {
-            final String lookupKey = Uri.encode(contactUri.getPathSegments().get(2));
+        ContentResolver resolver = mContext.getContentResolver();
+        if (mContactUri != null) {
+            final String lookupKey = Uri.encode(mContactUri.getPathSegments().get(2));
             final Uri shareUri;
             // TODO find out where to get this constant from, or find another way
             // of determining this.
diff --git a/src/com/android/contacts/activities/ContactSelectionActivity.java b/src/com/android/contacts/activities/ContactSelectionActivity.java
index 0c784cb..4375cb7 100644
--- a/src/com/android/contacts/activities/ContactSelectionActivity.java
+++ b/src/com/android/contacts/activities/ContactSelectionActivity.java
@@ -30,13 +30,12 @@
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.View.OnFocusChangeListener;
 import android.view.inputmethod.InputMethodManager;
+import android.widget.ImageButton;
 import android.widget.SearchView;
 import android.widget.SearchView.OnCloseListener;
 import android.widget.SearchView.OnQueryTextListener;
@@ -45,6 +44,7 @@
 import com.android.contacts.ContactsActivity;
 import com.android.contacts.R;
 import com.android.contacts.common.list.ContactEntryListFragment;
+import com.android.contacts.common.util.ViewUtil;
 import com.android.contacts.list.ContactPickerFragment;
 import com.android.contacts.list.ContactsIntentResolver;
 import com.android.contacts.list.ContactsRequest;
@@ -75,9 +75,6 @@
     private static final String KEY_ACTION_CODE = "actionCode";
     private static final int DEFAULT_DIRECTORY_RESULT_LIMIT = 20;
 
-    // Delay to allow the UI to settle before making search view visible
-    private static final int FOCUS_DELAY = 200;
-
     private ContactsIntentResolver mIntentResolver;
     protected ContactEntryListFragment<?> mListFragment;
 
@@ -85,10 +82,6 @@
 
     private ContactsRequest mRequest;
     private SearchView mSearchView;
-    /**
-     * Can be null. If null, the "Create New Contact" button should be on the menu.
-     */
-    private View mCreateNewContactButton;
 
     public ContactSelectionActivity() {
         mIntentResolver = new ContactsIntentResolver(this);
@@ -137,14 +130,16 @@
 
         prepareSearchViewAndActionBar();
 
-        mCreateNewContactButton = findViewById(R.id.new_contact);
-        if (mCreateNewContactButton != null) {
-            if (shouldShowCreateNewContactButton()) {
-                mCreateNewContactButton.setVisibility(View.VISIBLE);
-                mCreateNewContactButton.setOnClickListener(this);
-            } else {
-                mCreateNewContactButton.setVisibility(View.GONE);
-            }
+        // Configure action button
+        final View floatingActionButtonContainer = findViewById(
+                R.id.floating_action_button_container);
+        if (shouldShowCreateNewContactButton()) {
+            ViewUtil.setupFloatingActionButton(floatingActionButtonContainer, getResources());
+            final ImageButton floatingActionButton
+                    = (ImageButton) findViewById(R.id.floating_action_button);
+            floatingActionButton.setOnClickListener(this);
+        } else {
+            floatingActionButtonContainer.setVisibility(View.GONE);
         }
     }
 
@@ -169,67 +164,33 @@
             return;
         }
 
-        // If ActionBar is available, show SearchView on it. If not, show SearchView inside the
-        // Activity's layout.
         final ActionBar actionBar = getActionBar();
-        if (actionBar != null) {
-            final View searchViewOnLayout = findViewById(R.id.search_view);
-            if (searchViewOnLayout != null) {
-                searchViewOnLayout.setVisibility(View.GONE);
-            }
+        final View searchViewContainer = LayoutInflater.from(actionBar.getThemedContext())
+                .inflate(R.layout.custom_action_bar, null);
+        mSearchView = (SearchView) searchViewContainer.findViewById(R.id.search_view);
 
-            final View searchViewContainer = LayoutInflater.from(actionBar.getThemedContext())
-                    .inflate(R.layout.custom_action_bar, null);
-            mSearchView = (SearchView) searchViewContainer.findViewById(R.id.search_view);
+        // In order to make the SearchView look like "shown via search menu", we need to
+        // manually setup its state. See also DialtactsActivity.java and ActionBarAdapter.java.
+        mSearchView.setIconifiedByDefault(true);
+        mSearchView.setQueryHint(getString(R.string.hint_findContacts));
+        mSearchView.setIconified(false);
 
-            // In order to make the SearchView look like "shown via search menu", we need to
-            // manually setup its state. See also DialtactsActivity.java and ActionBarAdapter.java.
-            mSearchView.setIconifiedByDefault(true);
-            mSearchView.setQueryHint(getString(R.string.hint_findContacts));
-            mSearchView.setIconified(false);
+        mSearchView.setOnQueryTextListener(this);
+        mSearchView.setOnCloseListener(this);
+        mSearchView.setOnQueryTextFocusChangeListener(this);
 
-            mSearchView.setOnQueryTextListener(this);
-            mSearchView.setOnCloseListener(this);
-            mSearchView.setOnQueryTextFocusChangeListener(this);
-
-            actionBar.setCustomView(searchViewContainer,
-                    new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
-            actionBar.setDisplayShowCustomEnabled(true);
-            actionBar.setDisplayShowHomeEnabled(true);
-            actionBar.setDisplayHomeAsUpEnabled(true);
-        } else {
-            mSearchView = (SearchView) findViewById(R.id.search_view);
-            mSearchView.setQueryHint(getString(R.string.hint_findContacts));
-            mSearchView.setOnQueryTextListener(this);
-
-            // This is a hack to prevent the search view from grabbing focus
-            // at this point.  If search view were visible, it would always grabs focus
-            // because it is the first focusable widget in the window.
-            mSearchView.setVisibility(View.INVISIBLE);
-            mSearchView.postDelayed(new Runnable() {
-                @Override
-                public void run() {
-                    mSearchView.setVisibility(View.VISIBLE);
-                }
-            }, FOCUS_DELAY);
-        }
+        actionBar.setCustomView(searchViewContainer,
+                new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
+        actionBar.setDisplayShowCustomEnabled(true);
+        actionBar.setDisplayShowHomeEnabled(true);
+        actionBar.setDisplayHomeAsUpEnabled(true);
+        actionBar.setDisplayShowTitleEnabled(false);
 
         // Clear focus and suppress keyboard show-up.
         mSearchView.clearFocus();
     }
 
     @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        // If we want "Create New Contact" button but there's no such a button in the layout,
-        // try showing a menu for it.
-        if (shouldShowCreateNewContactButton() && mCreateNewContactButton == null) {
-            MenuInflater inflater = getMenuInflater();
-            inflater.inflate(R.menu.contact_picker_options, menu);
-        }
-        return true;
-    }
-
-    @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         switch (item.getItemId()) {
             case android.R.id.home:
@@ -237,10 +198,6 @@
                 setResult(RESULT_CANCELED);
                 finish();
                 return true;
-            case R.id.create_new_contact: {
-                startCreateNewContactActivity();
-                return true;
-            }
         }
         return super.onOptionsItemSelected(item);
     }
@@ -601,7 +558,7 @@
     @Override
     public void onClick(View view) {
         switch (view.getId()) {
-            case R.id.new_contact: {
+            case R.id.floating_action_button: {
                 startCreateNewContactActivity();
                 break;
             }
diff --git a/src/com/android/contacts/detail/ContactDetailLayoutController.java b/src/com/android/contacts/detail/ContactDetailLayoutController.java
index 098d950..d563baf 100644
--- a/src/com/android/contacts/detail/ContactDetailLayoutController.java
+++ b/src/com/android/contacts/detail/ContactDetailLayoutController.java
@@ -23,7 +23,6 @@
 import android.view.View;
 import android.view.ViewPropertyAnimator;
 
-import com.android.contacts.NfcHandler;
 import com.android.contacts.R.id;
 import com.android.contacts.activities.ContactDetailActivity.FragmentKeyListener;
 import com.android.contacts.common.model.Contact;
@@ -73,7 +72,6 @@
                 .findFragmentById(id.contact_detail_about_fragment);
 
         mDetailFragment.setListener(mContactDetailFragmentListener);
-        NfcHandler.register(mActivity, mDetailFragment);
 
         if (savedState != null) {
             mContactUri = savedState.getParcelable(KEY_CONTACT_URI);
diff --git a/src/com/android/contacts/interactions/CalendarInteractionsLoader.java b/src/com/android/contacts/interactions/CalendarInteractionsLoader.java
index 941698c..7d7a8f2 100644
--- a/src/com/android/contacts/interactions/CalendarInteractionsLoader.java
+++ b/src/com/android/contacts/interactions/CalendarInteractionsLoader.java
@@ -45,9 +45,6 @@
             long numberFutureMillisecondToSearchLocalCalendar,
             long numberPastMillisecondToSearchLocalCalendar) {
         super(context);
-        for (String address: emailAddresses) {
-            Log.v(TAG, address);
-        }
         mEmailAddresses = emailAddresses;
         mMaxFutureToRetrieve = maxFutureToRetrieve;
         mMaxPastToRetrieve = maxPastToRetrieve;
diff --git a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
index 3154f8a..335a564 100644
--- a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
+++ b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
@@ -100,14 +100,11 @@
     protected ContactListAdapter createListAdapter() {
         DefaultContactListAdapter adapter = new DefaultContactListAdapter(getContext());
         adapter.setSectionHeaderDisplayEnabled(isSectionHeaderDisplayEnabled());
-        boolean showPhoto = getResources().getBoolean(R.bool.config_browse_list_show_images);
         mContactAllListShowCardFrame = getResources().getBoolean(
                 R.bool.contact_all_list_show_card_frame);
-        adapter.setDisplayPhotos(showPhoto);
-        if (showPhoto) {
-            boolean reverse = getResources().getBoolean(R.bool.config_browse_list_reverse_images);
-            adapter.setPhotoPosition(ContactListItemView.getDefaultPhotoPosition(reverse));
-        }
+        adapter.setDisplayPhotos(true);
+        adapter.setPhotoPosition(
+                ContactListItemView.getDefaultPhotoPosition(/* opposite = */ false));
         return adapter;
     }
 
diff --git a/src/com/android/contacts/quickcontact/ExpandingEntryCardView.java b/src/com/android/contacts/quickcontact/ExpandingEntryCardView.java
index 1a4051e..2b2f032 100644
--- a/src/com/android/contacts/quickcontact/ExpandingEntryCardView.java
+++ b/src/com/android/contacts/quickcontact/ExpandingEntryCardView.java
@@ -131,8 +131,10 @@
     private boolean mIsExpanded = false;
     private int mCollapsedEntriesCount;
     private ExpandingEntryCardViewListener mListener;
-    private List<Entry> mEntries;
-    private List<View> mEntryViews;
+    private List<List<Entry>> mEntries;
+    private int mNumEntries = 0;
+    private boolean mAllEntriesInflated = false;
+    private List<List<View>> mEntryViews;
     private LinearLayout mEntriesViewGroup;
     private final Drawable mCollapseArrowDrawable;
     private final Drawable mExpandArrowDrawable;
@@ -179,21 +181,31 @@
      *
      * @param entries The Entry list to display.
      */
-    public void initialize(List<Entry> entries, int numInitialVisibleEntries,
+    public void initialize(List<List<Entry>> entries, int numInitialVisibleEntries,
             boolean isExpanded, ExpandingEntryCardViewListener listener) {
         LayoutInflater layoutInflater = LayoutInflater.from(getContext());
         mIsExpanded = isExpanded;
+        mEntryViews = new ArrayList<List<View>>(entries.size());
         mEntries = entries;
-        mEntryViews = new ArrayList<View>(entries.size());
-        mCollapsedEntriesCount = Math.min(numInitialVisibleEntries, entries.size());
+        for (List<Entry> entryList : mEntries) {
+            mNumEntries += entryList.size();
+            mEntryViews.add(new ArrayList<View>());
+        }
+        mCollapsedEntriesCount = Math.min(numInitialVisibleEntries, mNumEntries);
+        // Only show the head of each entry list if the initial visible number falls between the
+        // number of lists and the total number of entries
+        if (mCollapsedEntriesCount > mEntries.size()) {
+            mCollapsedEntriesCount = mEntries.size();
+        }
         mListener = listener;
 
         if (mIsExpanded) {
             updateExpandCollapseButton(getCollapseButtonText());
+            inflateAllEntries(layoutInflater);
         } else {
             updateExpandCollapseButton(getExpandButtonText());
+            inflateInitialEntries(layoutInflater);
         }
-        inflateViewsIfNeeded(layoutInflater);
         insertEntriesIntoViewGroup();
         applyColor();
     }
@@ -229,17 +241,21 @@
 
     private void insertEntriesIntoViewGroup() {
         mEntriesViewGroup.removeAllViews();
-        for (int i = 0; i < mCollapsedEntriesCount; ++i) {
-            addEntry(mEntryViews.get(i));
-        }
+
         if (mIsExpanded) {
-            for (int i = mCollapsedEntriesCount; i < mEntryViews.size(); ++i) {
-                addEntry(mEntryViews.get(i));
+            for (List<View> viewList : mEntryViews) {
+                for (View view : viewList) {
+                    addEntry(view);
+                }
+            }
+        } else {
+            for (int i = 0; i < mCollapsedEntriesCount; i++) {
+                addEntry(mEntryViews.get(i).get(0));
             }
         }
 
         removeView(mExpandCollapseButton);
-        if (mCollapsedEntriesCount < mEntries.size()
+        if (mCollapsedEntriesCount < mNumEntries
                 && mExpandCollapseButton.getParent() == null) {
             addView(mExpandCollapseButton, -1);
         }
@@ -290,16 +306,37 @@
     }
 
     /**
-     * Lazily inflate the number of views currently needed, and bind data from
-     * mEntries into these views.
+     * Inflates the initial entries to be shown.
      */
-    private void inflateViewsIfNeeded(LayoutInflater layoutInflater) {
-        final int viewsToInflate = mIsExpanded ?  mEntries.size() : mCollapsedEntriesCount;
-        for (int i = mEntryViews.size(); i < viewsToInflate; i++) {
-            mEntryViews.add(createEntryView(layoutInflater, mEntries.get(i)));
+    private void inflateInitialEntries(LayoutInflater layoutInflater) {
+        // If the number of collapsed entries equals total entries, inflate all
+        if (mCollapsedEntriesCount == mNumEntries) {
+            inflateAllEntries(layoutInflater);
+        } else {
+            // Otherwise inflate the top entry from each list
+            for (int i = 0; i < mCollapsedEntriesCount; i++) {
+                mEntryViews.get(i).add(createEntryView(layoutInflater, mEntries.get(i).get(0)));
+            }
         }
     }
 
+    /**
+     * Inflates all entries.
+     */
+    private void inflateAllEntries(LayoutInflater layoutInflater) {
+        if (mAllEntriesInflated) {
+            return;
+        }
+        for (int i = 0; i < mEntries.size(); i++) {
+            List<Entry> entryList = mEntries.get(i);
+            List<View> viewList = mEntryViews.get(i);
+            for (int j = viewList.size(); j < entryList.size(); j++) {
+                viewList.add(createEntryView(layoutInflater, entryList.get(j)));
+            }
+        }
+        mAllEntriesInflated = true;
+    }
+
     public void setColorAndFilter(int color, ColorFilter colorFilter) {
         mThemeColor = color;
         mThemeColorFilter = colorFilter;
@@ -323,10 +360,12 @@
 
             // Entry icons
             if (mEntries != null) {
-                for (Entry entry : mEntries) {
-                    Drawable icon = entry.getIcon();
-                    if (icon != null) {
-                        icon.setColorFilter(mThemeColorFilter);
+                for (List<Entry> entryList : mEntries) {
+                    for (Entry entry : entryList) {
+                        Drawable icon = entry.getIcon();
+                        if (icon != null) {
+                            icon.setColorFilter(mThemeColorFilter);
+                        }
                     }
                 }
             }
@@ -412,7 +451,7 @@
 
         mIsExpanded = true;
         // In order to insert new entries, we may need to inflate them for the first time
-        inflateViewsIfNeeded(LayoutInflater.from(getContext()));
+        inflateAllEntries(LayoutInflater.from(getContext()));
         insertEntriesIntoViewGroup();
         updateExpandCollapseButton(getCollapseButtonText());
 
@@ -447,7 +486,7 @@
         if (mCollapsedEntriesCount == 0) {
             return 0;
         }
-        final View bottomCollapsedView = mEntryViews.get(mCollapsedEntriesCount - 1);
+        final View bottomCollapsedView = mEntryViews.get(mCollapsedEntriesCount - 1).get(0);
         return bottomCollapsedView.getTop() + bottomCollapsedView.getHeight();
     }
 
diff --git a/src/com/android/contacts/quickcontact/QuickContactActivity.java b/src/com/android/contacts/quickcontact/QuickContactActivity.java
index 19c8126..0ef16d9 100644
--- a/src/com/android/contacts/quickcontact/QuickContactActivity.java
+++ b/src/com/android/contacts/quickcontact/QuickContactActivity.java
@@ -60,6 +60,7 @@
 import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
 import android.provider.ContactsContract.CommonDataKinds.Website;
 import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Data;
 import android.provider.ContactsContract.DisplayNameSources;
 import android.provider.ContactsContract.DataUsageFeedback;
 import android.provider.ContactsContract.QuickContact;
@@ -80,6 +81,7 @@
 
 import com.android.contacts.ContactSaveService;
 import com.android.contacts.ContactsActivity;
+import com.android.contacts.NfcHandler;
 import com.android.contacts.R;
 import com.android.contacts.common.CallUtil;
 import com.android.contacts.common.Collapser;
@@ -109,6 +111,8 @@
 import com.android.contacts.common.model.dataitem.StructuredPostalDataItem;
 import com.android.contacts.common.model.dataitem.WebsiteDataItem;
 import com.android.contacts.common.util.DateUtils;
+import com.android.contacts.common.util.MaterialColorMapUtils;
+import com.android.contacts.common.util.MaterialColorMapUtils.MaterialPalette;
 import com.android.contacts.detail.ContactDetailDisplayUtils;
 import com.android.contacts.interactions.CalendarInteractionsLoader;
 import com.android.contacts.interactions.CallLogInteractionsLoader;
@@ -123,7 +127,7 @@
 import com.android.contacts.util.StructuredPostalUtils;
 import com.android.contacts.widget.MultiShrinkScroller;
 import com.android.contacts.widget.MultiShrinkScroller.MultiShrinkScrollerListener;
-import com.google.common.annotations.VisibleForTesting;
+
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Lists;
 
@@ -134,10 +138,8 @@
 import java.util.Comparator;
 import java.util.Date;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 /**
  * Mostly translucent {@link Activity} that shows QuickContact dialog. It loads
@@ -159,7 +161,6 @@
 
     private static final int ANIMATION_STATUS_BAR_COLOR_CHANGE_DURATION = 150;
     private static final int REQUEST_CODE_CONTACT_EDITOR_ACTIVITY = 1;
-    private static final float SYSTEM_BAR_BRIGHTNESS_FACTOR = 0.7f;
     private static final int SCRIM_COLOR = Color.argb(0xB2, 0, 0, 0);
     private static final String SCHEME_SMSTO = "smsto";
     private static final String MIMETYPE_SMS = "vnd.android-dir/mms-sms";
@@ -171,6 +172,13 @@
     @SuppressWarnings("deprecation")
     private static final String LEGACY_AUTHORITY = android.provider.Contacts.AUTHORITY;
 
+    private static final String MIMETYPE_GPLUS_PROFILE =
+            "vnd.android.cursor.item/vnd.googleplus.profile";
+    private static final String INTENT_DATA_GPLUS_PROFILE_ADD_TO_CIRCLE = "Add to circle";
+    private static final String MIMETYPE_HANGOUTS =
+            "vnd.android.cursor.item/vnd.googleplus.profile.comm";
+    private static final String INTENT_DATA_HANGOUTS_VIDEO = "Start video call";
+
     private Uri mLookupUri;
     private String[] mExcludeMimes;
     private int mExtraMode;
@@ -285,7 +293,8 @@
             // so the exact usage type is not necessary in all cases
             String usageType = DataUsageFeedback.USAGE_TYPE_CALL;
 
-            if (intent.getData().getScheme().equals(SCHEME_SMSTO) ||
+            final String scheme = intent.getData().getScheme();
+            if ((scheme != null && scheme.equals(SCHEME_SMSTO)) ||
                     (intent.getType() != null && intent.getType().equals(MIMETYPE_SMS))) {
                 usageType = DataUsageFeedback.USAGE_TYPE_SHORT_TEXT;
             }
@@ -565,7 +574,7 @@
                             // header tint before the MultiShrinkScroller has been measured will
                             // cause incorrect tinting calculations.
                             if (color != 0) {
-                                setThemeColor(color);
+                                setThemeColor(MaterialColorMapUtils.calculateSecondaryColor(color));
                             }
                         }
                     });
@@ -626,6 +635,8 @@
                 getLoaderManager().destroyLoader(interactionLoaderId);
             }
         }
+
+        NfcHandler.register(this, mLookupUri);
     }
 
     private void runEntranceAnimation() {
@@ -777,46 +788,21 @@
     private void populateContactAndAboutCard() {
         Trace.beginSection("bind contact card");
 
-        final List<Entry> contactCardEntries = new ArrayList<>();
-        final List<Entry> aboutCardEntries = new ArrayList<>();
+        final List<List<Entry>> contactCardEntries = new ArrayList<>();
+        final List<List<Entry>> aboutCardEntries = new ArrayList<>();
 
-        int topContactIndex = 0;
         for (int i = 0; i < mDataItemsList.size(); ++i) {
             final List<DataItem> dataItemsByMimeType = mDataItemsList.get(i);
             final DataItem topDataItem = dataItemsByMimeType.get(0);
             if (ABOUT_CARD_MIMETYPES.contains(topDataItem.getMimeType())) {
-                aboutCardEntries.addAll(dataItemsToEntries(mDataItemsList.get(i)));
+                List<Entry> aboutEntries = dataItemsToEntries(mDataItemsList.get(i));
+                if (aboutEntries.size() > 0) {
+                    aboutCardEntries.add(aboutEntries);
+                }
             } else {
-                // Add most used to the top of the contact card
-                final Entry topEntry = dataItemToEntry(topDataItem);
-                if (topEntry != null) {
-                    contactCardEntries.add(topContactIndex++, dataItemToEntry(topDataItem));
-                }
-                // TODO merge SMS into secondary action
-                if (topDataItem instanceof PhoneDataItem) {
-                    final PhoneDataItem phone = (PhoneDataItem) topDataItem;
-                    Intent smsIntent = null;
-                    if (mSmsComponent != null) {
-                        smsIntent = new Intent(Intent.ACTION_SENDTO,
-                                Uri.fromParts(CallUtil.SCHEME_SMSTO, phone.getNumber(), null));
-                        smsIntent.setComponent(mSmsComponent);
-                    }
-                    final int dataId = phone.getId() > Integer.MAX_VALUE ?
-                            -1 : (int) phone.getId();
-                    contactCardEntries.add(topContactIndex++,
-                            new Entry(dataId,
-                                    getResources().getDrawable(R.drawable.ic_message_24dp),
-                                    getResources().getString(R.string.send_message),
-                                    /* subHeader = */ null,
-                                    /* text = */ phone.buildDataString(
-                                            this, topDataItem.getDataKind()),
-                                            smsIntent,
-                                            /* isEditable = */ false));
-                }
-                // Add the rest of the entries to the bottom of the card
-                if (dataItemsByMimeType.size() > 1) {
-                    contactCardEntries.addAll(dataItemsToEntries(
-                            dataItemsByMimeType.subList(1, dataItemsByMimeType.size())));
+                List<Entry> contactEntries = dataItemsToEntries(mDataItemsList.get(i));
+                if (contactEntries.size() > 0) {
+                    contactCardEntries.add(contactEntries);
                 }
             }
         }
@@ -1071,9 +1057,39 @@
             header = dataItem.buildDataStringForDisplay(this, kind);
             text = kind.typeColumn;
             intent = new Intent(Intent.ACTION_VIEW);
-            intent.setDataAndType(Uri.parse(dataItem.buildDataString(this, kind)),
-                    dataItem.getMimeType());
-            icon = ResolveCache.getInstance(this).getIcon(dataItem.getMimeType(), intent);
+            final Uri uri = ContentUris.withAppendedId(Data.CONTENT_URI, dataItem.getId());
+            intent.setDataAndType(uri, dataItem.getMimeType());
+
+            if (intent != null) {
+                final String mimetype = intent.getType();
+
+                // Attempt to use known icons for known 3p types. Otherwise default to ResolveCache
+                switch (mimetype) {
+                    case MIMETYPE_GPLUS_PROFILE:
+                        if (INTENT_DATA_GPLUS_PROFILE_ADD_TO_CIRCLE.equals(
+                                intent.getDataString())) {
+                            icon = getResources().getDrawable(
+                                    R.drawable.ic_add_to_circles_black_24);
+                        } else {
+                            icon = getResources().getDrawable(R.drawable.ic_google_plus_24dp);
+                        }
+                        break;
+                    case MIMETYPE_HANGOUTS:
+                        if (INTENT_DATA_HANGOUTS_VIDEO.equals(intent.getDataString())) {
+                            icon = getResources().getDrawable(R.drawable.ic_hangout_video_24dp);
+                        } else {
+                            icon = getResources().getDrawable(R.drawable.ic_hangout_24dp);
+                        }
+                        break;
+                    default:
+                        icon = ResolveCache.getInstance(this).getIcon(
+                                dataItem.getMimeType(), intent);
+                        // Call mutate to create a new Drawable.ConstantState for color filtering
+                        if (icon != null) {
+                            icon.mutate();
+                        }
+                }
+            }
         }
 
         if (intent != null) {
@@ -1103,6 +1119,26 @@
             if (entry != null) {
                 entries.add(entry);
             }
+            // TODO merge secondary intents
+            if (dataItem instanceof PhoneDataItem) {
+                final PhoneDataItem phone = (PhoneDataItem) dataItem;
+                Intent smsIntent = null;
+                if (mSmsComponent != null) {
+                    smsIntent = new Intent(Intent.ACTION_SENDTO,
+                            Uri.fromParts(CallUtil.SCHEME_SMSTO, phone.getNumber(), null));
+                    smsIntent.setComponent(mSmsComponent);
+                }
+                final int dataId = dataItem.getId() > Integer.MAX_VALUE ?
+                        -1 : (int) dataItem.getId();
+                entries.add(new Entry(dataId,
+                        getResources().getDrawable(R.drawable.ic_message_24dp),
+                        getResources().getString(R.string.send_message),
+                        /* subHeader = */ null,
+                        /* text = */ phone.buildDataString(this,
+                                dataItem.getDataKind()),
+                        smsIntent,
+                        /* isEditable = */ false));
+            }
         }
         return entries;
     }
@@ -1117,22 +1153,29 @@
             return;
         }
         final Drawable imageViewDrawable = mPhotoView.getDrawable();
-        new AsyncTask<Void, Void, Integer>() {
+        new AsyncTask<Void, Void, MaterialPalette>() {
             @Override
-            protected Integer doInBackground(Void... params) {
+            protected MaterialPalette doInBackground(Void... params) {
+
                 if (imageViewDrawable instanceof BitmapDrawable) {
                     final Bitmap bitmap = ((BitmapDrawable) imageViewDrawable).getBitmap();
-                    return colorFromBitmap(bitmap);
+                    final int primaryColor = colorFromBitmap(bitmap);
+                    if (primaryColor != 0) {
+                        return MaterialColorMapUtils.calculatePrimaryAndSecondaryColor(
+                                primaryColor);
+                    }
                 }
                 if (imageViewDrawable instanceof LetterTileDrawable) {
-                    return ((LetterTileDrawable) imageViewDrawable).getColor();
+                    final int primaryColor = ((LetterTileDrawable) imageViewDrawable).getColor();
+                    return MaterialColorMapUtils.calculateSecondaryColor(primaryColor);
                 }
-                return 0;
+                return MaterialColorMapUtils.calculatePrimaryAndSecondaryColor(
+                        getResources().getColor(R.color.quickcontact_default_photo_tint_color));
             }
 
             @Override
-            protected void onPostExecute(Integer color) {
-                super.onPostExecute(color);
+            protected void onPostExecute(MaterialPalette palette) {
+                super.onPostExecute(palette);
                 if (mHasComputedThemeColor) {
                     // If we had previously computed a theme color from the contact photo,
                     // then do not update the theme color. Changing the theme color several
@@ -1145,7 +1188,7 @@
                 // color needs to be extracted
                 if (imageViewDrawable == mPhotoView.getDrawable()) {
                     mHasComputedThemeColor = true;
-                    setThemeColor(color);
+                    setThemeColor(palette);
                 }
             }
         }.execute();
@@ -1175,27 +1218,18 @@
         }.execute();
     }
 
-    private void setThemeColor(int color) {
+    private void setThemeColor(MaterialPalette palette) {
         // If the color is invalid, use the predefined default
-        if (color == 0) {
-            color = getResources().getColor(R.color.actionbar_background_color);
-        }
-        mScroller.setHeaderTintColor(color);
-
-        // Create a darker version of the actionbar color. HSV is device dependent
-        // and not perceptually-linear. Therefore, we can't say mStatusBarColor is
-        // 70% as bright as the action bar color. We can only say: it is a bit darker.
-        final float hsvComponents[] = new float[3];
-        Color.colorToHSV(color, hsvComponents);
-        hsvComponents[2] *= SYSTEM_BAR_BRIGHTNESS_FACTOR;
-        mStatusBarColor = Color.HSVToColor(hsvComponents);
+        final int primaryColor = palette.mPrimaryColor;
+        mScroller.setHeaderTintColor(primaryColor);
+        mStatusBarColor = palette.mSecondaryColor;
         updateStatusBarColor();
 
         mColorFilter =
-                new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP);
-        mContactCard.setColorAndFilter(color, mColorFilter);
-        mRecentCard.setColorAndFilter(color, mColorFilter);
-        mAboutCard.setColorAndFilter(color, mColorFilter);
+                new PorterDuffColorFilter(primaryColor, PorterDuff.Mode.SRC_ATOP);
+        mContactCard.setColorAndFilter(primaryColor, mColorFilter);
+        mRecentCard.setColorAndFilter(primaryColor, mColorFilter);
+        mAboutCard.setColorAndFilter(primaryColor, mColorFilter);
     }
 
     private void updateStatusBarColor() {
@@ -1328,9 +1362,14 @@
                     break;
                 case LOADER_CALENDAR_ID:
                     Log.v(TAG, "LOADER_CALENDAR_ID");
+                    final String[] emailsArray = args.getStringArray(KEY_LOADER_EXTRA_EMAILS);
+                    List<String> emailsList = null;
+                    if (emailsArray != null) {
+                        emailsList = Arrays.asList(args.getStringArray(KEY_LOADER_EXTRA_EMAILS));
+                    }
                     loader = new CalendarInteractionsLoader(
                             QuickContactActivity.this,
-                            Arrays.asList(args.getStringArray(KEY_LOADER_EXTRA_EMAILS)),
+                            emailsList,
                             MAX_FUTURE_CALENDAR_RETRIEVE,
                             MAX_PAST_CALENDAR_RETRIEVE,
                             FUTURE_MILLISECOND_TO_SEARCH_LOCAL_CALENDAR,
@@ -1386,8 +1425,11 @@
             }
         });
 
+
+        List<List<Entry>> interactionsWrapper = new ArrayList<>();
+        interactionsWrapper.add(contactInteractionsToEntries(allInteractions));
         if (allInteractions.size() > 0) {
-            mRecentCard.initialize(contactInteractionsToEntries(allInteractions),
+            mRecentCard.initialize(interactionsWrapper,
                     /* numInitialVisibleEntries = */ MIN_NUM_COLLAPSED_RECENT_ENTRIES_SHOWN,
                     /* isExpanded = */ false, mExpandingEntryCardViewListener);
             mRecentCard.setVisibility(View.VISIBLE);
@@ -1468,6 +1510,7 @@
             return uri;
         }
     }
+
     private void shareContact() {
         final String lookupKey = mContactData.getLookupKey();
         Uri shareUri = Uri.withAppendedPath(Contacts.CONTENT_VCARD_URI, lookupKey);
@@ -1538,8 +1581,10 @@
             if (DirectoryContactUtil.isDirectoryContact(mContactData) || InvisibleContactUtil
                     .isInvisibleAndAddable(mContactData, this)) {
                 editMenuItem.setIcon(R.drawable.ic_person_add_tinted_24dp);
+                editMenuItem.setTitle(R.string.menu_add_contact);
             } else if (isContactEditable()) {
                 editMenuItem.setIcon(R.drawable.ic_create_24dp);
+                editMenuItem.setTitle(R.string.menu_editContact);
             } else {
                 editMenuItem.setVisible(false);
             }