Merge "Changing the call log collapse animation for previous item so it happens at the same time as the expansion of another row; this eliminates the need for calling notifyDataSetChanged on expand/collapse." into lmp-preview-dev
diff --git a/res/drawable-hdpi/ic_add_person_dk.png b/res/drawable-hdpi/ic_add_person_dk.png
deleted file mode 100644
index 7096ed2..0000000
--- a/res/drawable-hdpi/ic_add_person_dk.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_arrow_back_24dp.png b/res/drawable-hdpi/ic_arrow_back_24dp.png
new file mode 100644
index 0000000..86cb894
--- /dev/null
+++ b/res/drawable-hdpi/ic_arrow_back_24dp.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_back_arrow.png b/res/drawable-hdpi/ic_back_arrow.png
deleted file mode 100644
index aad4f36..0000000
--- a/res/drawable-hdpi/ic_back_arrow.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_phone_dk.png b/res/drawable-hdpi/ic_phone_dk.png
deleted file mode 100644
index 984d6fa..0000000
--- a/res/drawable-hdpi/ic_phone_dk.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_results_add_contact.png b/res/drawable-hdpi/ic_results_add_contact.png
new file mode 100644
index 0000000..472b281
--- /dev/null
+++ b/res/drawable-hdpi/ic_results_add_contact.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_results_phone.png b/res/drawable-hdpi/ic_results_phone.png
new file mode 100644
index 0000000..3a1a7a7
--- /dev/null
+++ b/res/drawable-hdpi/ic_results_phone.png
Binary files differ
diff --git a/res/drawable-hdpi/list_item_avatar_bg.png b/res/drawable-hdpi/list_item_avatar_bg.png
deleted file mode 100644
index 66e5f3e..0000000
--- a/res/drawable-hdpi/list_item_avatar_bg.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_add_person_dk.png b/res/drawable-mdpi/ic_add_person_dk.png
deleted file mode 100644
index 0e0aed0..0000000
--- a/res/drawable-mdpi/ic_add_person_dk.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_arrow_back_24dp.png b/res/drawable-mdpi/ic_arrow_back_24dp.png
new file mode 100644
index 0000000..dc81cd1
--- /dev/null
+++ b/res/drawable-mdpi/ic_arrow_back_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_back_arrow.png b/res/drawable-mdpi/ic_back_arrow.png
deleted file mode 100644
index 56eb887..0000000
--- a/res/drawable-mdpi/ic_back_arrow.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_phone_dk.png b/res/drawable-mdpi/ic_phone_dk.png
deleted file mode 100644
index c55571a..0000000
--- a/res/drawable-mdpi/ic_phone_dk.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_results_add_contact.png b/res/drawable-mdpi/ic_results_add_contact.png
new file mode 100644
index 0000000..d4d4759
--- /dev/null
+++ b/res/drawable-mdpi/ic_results_add_contact.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_results_phone.png b/res/drawable-mdpi/ic_results_phone.png
new file mode 100644
index 0000000..74ccf14
--- /dev/null
+++ b/res/drawable-mdpi/ic_results_phone.png
Binary files differ
diff --git a/res/drawable-mdpi/list_item_avatar_bg.png b/res/drawable-mdpi/list_item_avatar_bg.png
deleted file mode 100644
index 640eb3e..0000000
--- a/res/drawable-mdpi/list_item_avatar_bg.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_add_person_dk.png b/res/drawable-xhdpi/ic_add_person_dk.png
deleted file mode 100644
index 5211f5c..0000000
--- a/res/drawable-xhdpi/ic_add_person_dk.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_arrow_back_24dp.png b/res/drawable-xhdpi/ic_arrow_back_24dp.png
new file mode 100644
index 0000000..4f4fbaa
--- /dev/null
+++ b/res/drawable-xhdpi/ic_arrow_back_24dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_back_arrow.png b/res/drawable-xhdpi/ic_back_arrow.png
deleted file mode 100644
index 9d46e3d..0000000
--- a/res/drawable-xhdpi/ic_back_arrow.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_phone_dk.png b/res/drawable-xhdpi/ic_phone_dk.png
deleted file mode 100644
index 74a7032..0000000
--- a/res/drawable-xhdpi/ic_phone_dk.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_results_add_contact.png b/res/drawable-xhdpi/ic_results_add_contact.png
new file mode 100644
index 0000000..6be67e8
--- /dev/null
+++ b/res/drawable-xhdpi/ic_results_add_contact.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_results_phone.png b/res/drawable-xhdpi/ic_results_phone.png
new file mode 100644
index 0000000..0e24fa4
--- /dev/null
+++ b/res/drawable-xhdpi/ic_results_phone.png
Binary files differ
diff --git a/res/drawable-xhdpi/list_item_avatar_bg.png b/res/drawable-xhdpi/list_item_avatar_bg.png
deleted file mode 100644
index cac7fbd..0000000
--- a/res/drawable-xhdpi/list_item_avatar_bg.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_add_person_dk.png b/res/drawable-xxhdpi/ic_add_person_dk.png
deleted file mode 100644
index 54ca1f0..0000000
--- a/res/drawable-xxhdpi/ic_add_person_dk.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_arrow_back_24dp.png b/res/drawable-xxhdpi/ic_arrow_back_24dp.png
new file mode 100644
index 0000000..46e90f7
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_arrow_back_24dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_back_arrow.png b/res/drawable-xxhdpi/ic_back_arrow.png
deleted file mode 100644
index 66b6e35..0000000
--- a/res/drawable-xxhdpi/ic_back_arrow.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_phone_dk.png b/res/drawable-xxhdpi/ic_phone_dk.png
deleted file mode 100644
index de9387d..0000000
--- a/res/drawable-xxhdpi/ic_phone_dk.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_results_add_contact.png b/res/drawable-xxhdpi/ic_results_add_contact.png
new file mode 100644
index 0000000..3ba9093
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_results_add_contact.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_results_phone.png b/res/drawable-xxhdpi/ic_results_phone.png
new file mode 100644
index 0000000..9594619
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_results_phone.png
Binary files differ
diff --git a/res/drawable-xxhdpi/list_item_avatar_bg.png b/res/drawable-xxhdpi/list_item_avatar_bg.png
deleted file mode 100644
index fcfe2da..0000000
--- a/res/drawable-xxhdpi/list_item_avatar_bg.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable/ic_back_arrow.xml b/res/drawable/ic_back_arrow.xml
new file mode 100644
index 0000000..68a875d
--- /dev/null
+++ b/res/drawable/ic_back_arrow.xml
@@ -0,0 +1,20 @@
+<?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
+  -->
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/ic_arrow_back_24dp"
+        android:autoMirrored="true"
+        android:tint="@color/actionbar_icon_color" />
\ No newline at end of file
diff --git a/res/drawable/ic_search_add_contact.xml b/res/drawable/ic_search_add_contact.xml
new file mode 100644
index 0000000..2ec75b7
--- /dev/null
+++ b/res/drawable/ic_search_add_contact.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+    android:src="@drawable/ic_results_add_contact"
+    android:tint="@color/search_shortcut_icon_color" />
diff --git a/res/drawable/ic_search_phone.xml b/res/drawable/ic_search_phone.xml
new file mode 100644
index 0000000..ac90532
--- /dev/null
+++ b/res/drawable/ic_search_phone.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+    android:src="@drawable/ic_results_phone"
+    android:tint="@color/search_shortcut_icon_color" />
diff --git a/res/drawable/search_shortcut_background.xml b/res/drawable/search_shortcut_background.xml
new file mode 100644
index 0000000..52b5e3f
--- /dev/null
+++ b/res/drawable/search_shortcut_background.xml
@@ -0,0 +1,23 @@
+<?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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval" >
+    <size
+        android:height="@dimen/search_shortcut_radius"
+        android:width="@dimen/search_shortcut_radius" />
+    <solid android:color="@color/search_shortcut_background_color" />
+</shape>
\ No newline at end of file
diff --git a/res/layout/call_log_list_item.xml b/res/layout/call_log_list_item.xml
index bdf1477..9899424 100644
--- a/res/layout/call_log_list_item.xml
+++ b/res/layout/call_log_list_item.xml
@@ -28,7 +28,7 @@
         android:id="@+id/call_log_day_group_label"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginStart="@dimen/call_log_outer_margin"
+        android:layout_marginStart="@dimen/call_log_start_margin"
         android:layout_marginEnd="@dimen/call_log_outer_margin"
         android:textColor="?attr/call_log_secondary_text_color"
         android:textSize="@dimen/call_log_secondary_text_size"
@@ -52,7 +52,7 @@
             android:background="@drawable/call_log_background"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:paddingStart="@dimen/call_log_outer_margin"
+            android:paddingStart="@dimen/call_log_start_margin"
             android:paddingEnd="@dimen/call_log_outer_margin"
             android:paddingTop="@dimen/call_log_outer_margin"
             android:paddingBottom="@dimen/call_log_outer_margin"
@@ -75,7 +75,7 @@
                 android:layout_weight="1"
                 android:orientation="vertical"
                 android:gravity="center_vertical"
-                android:layout_marginStart="@dimen/call_log_inner_margin"
+                android:layout_marginStart="@dimen/call_log_start_margin"
                 >
                 <TextView
                     android:id="@+id/name"
diff --git a/res/layout/call_log_list_item_actions.xml b/res/layout/call_log_list_item_actions.xml
index 9ee9a0f..3a93575 100644
--- a/res/layout/call_log_list_item_actions.xml
+++ b/res/layout/call_log_list_item_actions.xml
@@ -24,7 +24,7 @@
         android:layout_width="match_parent"
         android:layout_height="@dimen/call_log_action_height"
         android:orientation="horizontal"
-        android:paddingLeft="@dimen/call_log_actions_left_padding"
+        android:paddingStart="@dimen/call_log_actions_left_padding"
         android:visibility="visible"
         android:importantForAccessibility="1"
         >
@@ -35,8 +35,8 @@
             android:gravity="center"
             android:layout_width="wrap_content"
             android:layout_height="match_parent"
-            android:paddingLeft="@dimen/call_log_action_horizontal_padding"
-            android:paddingRight="@dimen/call_log_action_horizontal_padding"
+            android:paddingStart="@dimen/call_log_action_horizontal_padding"
+            android:paddingEnd="@dimen/call_log_action_horizontal_padding"
             android:text="@string/call_log_action_call_back"
             android:textColor="@color/call_log_action_text"
             android:textSize="@dimen/call_log_secondary_text_size"
@@ -51,8 +51,8 @@
             android:gravity="center"
             android:layout_width="wrap_content"
             android:layout_height="match_parent"
-            android:paddingLeft="@dimen/call_log_action_horizontal_padding"
-            android:paddingRight="@dimen/call_log_action_horizontal_padding"
+            android:paddingStart="@dimen/call_log_action_horizontal_padding"
+            android:paddingEnd="@dimen/call_log_action_horizontal_padding"
             android:text="@string/call_log_action_voicemail"
             android:textColor="@color/call_log_action_text"
             android:textSize="@dimen/call_log_secondary_text_size"
@@ -67,8 +67,8 @@
             android:gravity="center"
             android:layout_width="wrap_content"
             android:layout_height="match_parent"
-            android:paddingLeft="@dimen/call_log_action_horizontal_padding"
-            android:paddingRight="@dimen/call_log_action_horizontal_padding"
+            android:paddingStart="@dimen/call_log_action_horizontal_padding"
+            android:paddingEnd="@dimen/call_log_action_horizontal_padding"
             android:text="@string/call_log_action_details"
             android:textColor="?attr/call_log_secondary_text_color"
             android:textSize="@dimen/call_log_secondary_text_size"
diff --git a/res/layout/lists_fragment.xml b/res/layout/lists_fragment.xml
index d75095a..7e15f84 100644
--- a/res/layout/lists_fragment.xml
+++ b/res/layout/lists_fragment.xml
@@ -24,7 +24,7 @@
         android:id="@+id/shortcut_card_list"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:paddingTop="?android:attr/actionBarSize"
+        android:paddingTop="@dimen/action_bar_height"
         android:background="@color/actionbar_background_color"
         android:clipToPadding="false"
         android:fadingEdge="none"
diff --git a/res/layout/speeddial_fragment.xml b/res/layout/speeddial_fragment.xml
index e8587fa..f025e61 100644
--- a/res/layout/speeddial_fragment.xml
+++ b/res/layout/speeddial_fragment.xml
@@ -40,7 +40,7 @@
             android:clipToPadding="false"
             android:fadingEdge="none"
             android:divider="@null"
-            android:paddingBottom="@dimen/floating_action_button_height"
+            android:paddingBottom="@dimen/floating_action_button_list_bottom_padding"
             android:nestedScrollingEnabled="true" />
     </FrameLayout>
 
diff --git a/res/values-land/styles.xml b/res/values-land/styles.xml
deleted file mode 100644
index 1388a17..0000000
--- a/res/values-land/styles.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-  Copyright (C) 2012 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>
-
-    <style name="FragmentActionBarPadding">
-        <item name="android:paddingBottom">0dp</item>
-    </style>
-</resources>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 5b708b6..d43f30a 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -47,6 +47,9 @@
     <!-- Background color of dialer list items (contacts, call log entries) -->
     <color name="background_dialer_list_items">#fbfbfb</color>
 
+    <color name="search_shortcut_background_color">#b6b6b6</color>
+    <color name="search_shortcut_icon_color">#f8f8f8</color>
+
     <!-- Dark variant of the action bar color. -->
     <color name="actionbar_background_color_dark">#008aa1</color>
 
@@ -64,6 +67,8 @@
     <!-- Color of the contact name in favorite tiles -->
     <color name="contact_tile_name_color">#ffffff</color>
 
+    <color name="contact_list_name_text_color">#4d4d4d</color>
+
     <!-- Undo dialogue color -->
     <color name="undo_dialogue_text_color">#4d4d4d</color>
 
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index f399e36..e884566 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -31,26 +31,20 @@
     <dimen name="call_log_icon_margin">4dip</dimen>
     <dimen name="call_log_inner_margin">8dip</dimen>
     <dimen name="call_log_outer_margin">8dp</dimen>
+    <dimen name="call_log_start_margin">16dp</dimen>
     <dimen name="call_log_indent_margin">24dip</dimen>
     <dimen name="call_log_list_item_height">56dip</dimen>
     <dimen name="call_log_list_contact_photo_size">40dip</dimen>
     <dimen name="call_detail_contact_name_margin">24dip</dimen>
     <dimen name="call_detail_button_spacing">2dip</dimen>
-    <!-- Defines the vertical margin for the vertical separator between
-         the main area of a call log entry and the secondary action button. -->
-    <dimen name="call_log_list_item_vertical_divider_margin">17dp</dimen>
-
-    <!-- Defines the width of the vertical separator between
-         the main area of a call log entry and the secondary action button. -->
-    <dimen name="call_log_list_item_vertical_divider_width">1dp</dimen>
 
     <!-- Match call_button_height to Phone's dimens/in_call_end_button_height -->
     <dimen name="call_button_height">74dp</dimen>
 
     <!-- Right margin of the floating action button -->
-    <dimen name="floating_action_button_margin_right">10dp</dimen>
+    <dimen name="floating_action_button_margin_right">16dp</dimen>
     <!-- Bottom margin of the floating action button -->
-    <dimen name="floating_action_button_margin_bottom">10dp</dimen>
+    <dimen name="floating_action_button_margin_bottom">16dp</dimen>
 
     <!-- Dimensions for speed dial tiles -->
     <dimen name="contact_tile_divider_width">1dp</dimen>
@@ -69,6 +63,8 @@
     <!-- Dimensions for most recent call shortcut cards -->
     <dimen name="recent_call_log_item_translation_z">5dp</dimen>
     <dimen name="recent_call_log_item_padding">8dp</dimen>
+    <!-- The maximum amount to clip on the left and right of the recent call shortcut card -->
+    <dimen name="recent_call_log_item_horizontal_clip_limit">20dp</dimen>
 
     <!-- Size of the star icon on the favorites tile. -->
     <dimen name="favorites_star_icon_size">12dp</dimen>
@@ -92,12 +88,16 @@
     <!-- Height of the all contacts Button in the favorites menu. -->
     <dimen name="favorites_menu_all_contacts_height">24dp</dimen>
 
+    <!-- Height of the actionBar - this is 8dps bigger than the platform standard to give more
+    room to the search box-->
+    <dimen name="action_bar_height">64dp</dimen>
+
     <!-- Margin to the left and right of the search box. -->
     <dimen name="search_margin_horizontal">7dp</dimen>
     <!-- Margin above the search box. -->
-    <dimen name="search_top_margin">4dp</dimen>
+    <dimen name="search_top_margin">8dp</dimen>
     <!-- Margin below the search box. -->
-    <dimen name="search_bottom_margin">4dp</dimen>
+    <dimen name="search_bottom_margin">8dp</dimen>
     <!-- Search box text size -->
     <dimen name="search_text_size">13.24sp</dimen>
     <!-- Search box interior padding - left -->
@@ -112,7 +112,7 @@
     <!-- Size of the icon (voice search, close search) in the search box. -->
     <dimen name="search_box_icon_size">28dp</dimen>
     <!-- Elevation of the search box -->
-    <dimen name="search_box_elevation">10dp</dimen>
+    <dimen name="search_box_elevation">5dp</dimen>
 
     <!-- Size of text in tabs. -->
     <dimen name="tab_height">43dp</dimen>
@@ -123,7 +123,7 @@
          to the right of the contact badge.  Adjust when any of the following change:
          call_log_action_horizontal_padding
          call_log_list_contact_photo_size  -->
-    <dimen name="call_log_actions_left_padding">48dp</dimen>
+    <dimen name="call_log_actions_left_padding">64dp</dimen>
     <!-- Text size for primary call log text -->
     <dimen name="call_log_primary_text_size">16sp</dimen>
     <!-- Text size for secondary call log text -->
@@ -134,4 +134,7 @@
     <dimen name="call_log_expanded_translation_z">4dp</dimen>
     <!-- Padding above call log day group headers. -->
     <dimen name="call_log_day_group_padding">16dp</dimen>
+
+    <!-- Size of icon for contacts number shortcuts -->
+    <dimen name="search_shortcut_radius">40dp</dimen>
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 659d5ab..e84f4b5 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -22,14 +22,10 @@
         <item name="android:windowActionBarOverlay">true</item>
         <item name="android:windowActionModeOverlay">true</item>
         <item name="android:actionBarStyle">@style/DialtactsActionBarStyle</item>
-        <!-- Style for the tabs (for the tabs) -->
-        <item name="android:actionBarTabStyle">@style/DialtactsActionBarTabStyle</item>
-        <!-- Style for the tab bar (for the divider between tabs) -->
-        <item name="android:actionBarTabBarStyle">@style/DialtactsActionBarTabBarStyle</item>
-        <!-- Style for the tab bar text (for text on tabs) -->
-        <item name="android:actionBarTabTextStyle">@style/DialtactsActionBarTabTextStyle</item>
         <!-- Style for the overflow button in the actionbar. -->
         <item name="android:actionOverflowButtonStyle">@style/DialtactsActionBarOverflow</item>
+        <!--  Drawable for the back button -->
+        <item name="android:homeAsUpIndicator">@drawable/ic_back_arrow</item>
         <item name="android:windowContentOverlay">@null</item>
         <!--  Searchbox Style -->
         <item name="android:editTextStyle">@style/DialtactsSearchboxStyle</item>
@@ -58,6 +54,7 @@
         <item name="contact_browser_list_padding_left">16dp</item>
         <item name="contact_browser_list_padding_right">0dp</item>
         <item name="contact_browser_background">@color/contact_list_background_color</item>
+        <item name="list_item_name_text_color">@color/contact_list_name_text_color</item>
         <item name="list_item_text_indent">@dimen/contact_browser_list_item_text_indent</item>
         <!-- CallLog -->
         <item name="call_log_primary_text_color">#000000</item>
@@ -72,7 +69,7 @@
         <item name="call_log_voicemail_status_action_text_color">#33b5e5</item>
             <!-- Favorites -->
         <item name="favorites_padding_bottom">?android:attr/actionBarSize</item>
-	<item name="android:colorPrimaryDark">@color/actionbar_background_color_dark</item>
+        <item name="android:colorPrimaryDark">@color/actionbar_background_color_dark</item>
     </style>
 
     <!-- Action bar overflow menu icon. -->
@@ -117,6 +114,7 @@
         <item name="android:background">@color/actionbar_background_color</item>
         <item name="android:backgroundStacked">#ffffff</item>
         <item name="android:titleTextStyle">@style/DialtactsActionBarTitleText</item>
+        <item name="android:height">@dimen/action_bar_height</item>
         <!-- Empty icon -->
         <item name="android:icon">@android:color/transparent</item>
     </style>
@@ -156,10 +154,6 @@
         <item name="android:overScrollMode">always</item>
     </style>
 
-    <style name="FragmentActionBarPadding">
-        <item name="android:paddingBottom">?android:attr/actionBarSize</item>
-    </style>
-
     <style name="DialtactsSearchboxStyle" parent="@android:style/Widget.EditText">
         <item name="android:background">@null</item>
         <item name="android:textColorHint">@color/searchbox_text_color</item>
diff --git a/src/com/android/dialer/DialtactsActivity.java b/src/com/android/dialer/DialtactsActivity.java
index 8445ff7..a593c14 100644
--- a/src/com/android/dialer/DialtactsActivity.java
+++ b/src/com/android/dialer/DialtactsActivity.java
@@ -20,7 +20,6 @@
 import android.app.ActionBar;
 import android.app.Activity;
 import android.app.Fragment;
-import android.app.FragmentManager;
 import android.app.FragmentTransaction;
 import android.content.ActivityNotFoundException;
 import android.content.Context;
@@ -85,6 +84,7 @@
 import com.android.dialer.list.RemoveView;
 import com.android.dialer.list.SearchFragment;
 import com.android.dialer.list.SmartDialSearchFragment;
+import com.android.dialer.widget.ActionBarController;
 import com.android.dialer.widget.SearchEditTextLayout;
 import com.android.dialer.widget.SearchEditTextLayout.OnBackButtonClickedListener;
 import com.android.dialerbind.DatabaseHelperManager;
@@ -102,10 +102,12 @@
         DialpadFragment.HostInterface,
         ListsFragment.HostInterface,
         SpeedDialFragment.HostInterface,
+        SearchFragment.HostInterface,
         OnDragDropListener,
         OnPhoneNumberPickerActionListener,
         PopupMenu.OnMenuItemClickListener,
-        ViewPager.OnPageChangeListener {
+        ViewPager.OnPageChangeListener,
+        ActionBarController.ActivityUi {
     private static final String TAG = "DialtactsActivity";
 
     public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -208,6 +210,7 @@
 
     private DialerDatabaseHelper mDialerDatabaseHelper;
     private DragDropController mDragDropController;
+    private ActionBarController mActionBarController;
 
     private class OptionsPopupMenu extends PopupMenu {
         public OptionsPopupMenu(Context context, View anchor) {
@@ -293,6 +296,7 @@
         @Override
         public void onClick(View v) {
             if (!isInSearchUi()) {
+                mActionBarController.onSearchBoxTapped();
                 enterSearchUi(false /* smartDialSearch */, mSearchView.getText().toString());
             }
         }
@@ -325,6 +329,9 @@
         actionBar.setDisplayShowCustomEnabled(true);
         actionBar.setBackgroundDrawable(null);
 
+        mActionBarController = new ActionBarController(this,
+                (SearchEditTextLayout) actionBar.getCustomView());
+
         mSearchEditTextLayout = (SearchEditTextLayout) actionBar.getCustomView();
         mSearchEditTextLayout.setPreImeKeyListener(mSearchEditTextLayoutListener);
 
@@ -346,10 +353,7 @@
         final OptionsPopupMenu optionsMenu = buildOptionsMenu(optionsMenuButton);
         optionsMenuButton.setOnTouchListener(optionsMenu.getDragToOpenListener());
 
-        final TypedArray styledAttributes = getTheme().obtainStyledAttributes(
-                new int[] { android.R.attr.actionBarSize });
-        mActionBarHeight = (int) styledAttributes.getDimension(0, 0);
-        styledAttributes.recycle();
+        mActionBarHeight = getResources().getDimensionPixelSize(R.dimen.action_bar_height);
 
         // Add the favorites fragment, and the dialpad fragment, but only if savedInstanceState
         // is null. Otherwise the fragment manager takes care of recreating these fragments.
@@ -363,6 +367,7 @@
             mInRegularSearch = savedInstanceState.getBoolean(KEY_IN_REGULAR_SEARCH_UI);
             mInDialpadSearch = savedInstanceState.getBoolean(KEY_IN_DIALPAD_SEARCH_UI);
             mFirstLaunch = savedInstanceState.getBoolean(KEY_FIRST_LAUNCH);
+            mActionBarController.restoreInstanceState(savedInstanceState);
         }
 
         parentLayout = (RelativeLayout) findViewById(R.id.dialtacts_mainlayout);
@@ -426,6 +431,7 @@
         outState.putBoolean(KEY_IN_REGULAR_SEARCH_UI, mInRegularSearch);
         outState.putBoolean(KEY_IN_DIALPAD_SEARCH_UI, mInDialpadSearch);
         outState.putBoolean(KEY_FIRST_LAUNCH, mFirstLaunch);
+        mActionBarController.saveInstanceState(outState);
     }
 
     @Override
@@ -563,6 +569,8 @@
         ft.show(mDialpadFragment);
         ft.commit();
 
+        mActionBarController.onDialpadUp();
+
         if (!isInSearchUi()) {
             enterSearchUi(true /* isSmartDial */, mSearchQuery);
         }
@@ -581,7 +589,6 @@
         }
 
         updateSearchFragmentPosition();
-        getActionBar().hide();
     }
 
     /**
@@ -617,7 +624,7 @@
             commitDialpadFragmentHide();
         }
 
-        mListsFragment.maybeShowActionBar();
+        mActionBarController.onDialpadDown();
 
         if (isInSearchUi()) {
             if (TextUtils.isEmpty(mSearchQuery)) {
@@ -649,10 +656,21 @@
         }
     }
 
-    private boolean isInSearchUi() {
+    @Override
+    public boolean isInSearchUi() {
         return mInDialpadSearch || mInRegularSearch;
     }
 
+    @Override
+    public boolean hasSearchQuery() {
+        return !TextUtils.isEmpty(mSearchQuery);
+    }
+
+    @Override
+    public boolean shouldShowActionBar() {
+        return mListsFragment.shouldShowActionBar();
+    }
+
     private void setNotInSearchUi() {
         mInDialpadSearch = false;
         mInRegularSearch = false;
@@ -829,7 +847,6 @@
         transaction.commit();
 
         mListsFragment.getView().animate().alpha(0).withLayer();
-        mSearchEditTextLayout.animateExpandOrCollapse(true);
     }
 
     /**
@@ -856,7 +873,7 @@
         transaction.commit();
 
         mListsFragment.getView().animate().alpha(1).withLayer();
-        mSearchEditTextLayout.animateExpandOrCollapse(false);
+        mActionBarController.onSearchUiExited();
     }
 
     /** Returns an Intent to launch Call Settings screen */
@@ -974,7 +991,7 @@
      */
     @Override
     public void onDragStarted(int x, int y, PhoneFavoriteSquareTileView view) {
-        getActionBar().hide();
+        mActionBarController.slideActionBarUp(true);
         mRemoveViewContainer.setVisibility(View.VISIBLE);
     }
 
@@ -987,7 +1004,7 @@
      */
     @Override
     public void onDragFinished(int x, int y) {
-        getActionBar().show();
+        mActionBarController.slideActionBarDown(true);
         mRemoveViewContainer.setVisibility(View.GONE);
     }
 
@@ -1031,10 +1048,6 @@
         exitSearchUi();
     }
 
-    public int getActionBarHeight() {
-        return mActionBarHeight;
-    }
-
     @Override
     public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
 
@@ -1107,4 +1120,24 @@
         public void onAnimationRepeat(Animation animation) {
         }
     }
+
+    @Override
+    public boolean isActionBarShowing() {
+        return mActionBarController.isActionBarShowing();
+    }
+
+    @Override
+    public int getActionBarHideOffset() {
+        return getActionBar().getHideOffset();
+    }
+
+    @Override
+    public int getActionBarHeight() {
+        return mActionBarHeight;
+    }
+
+    @Override
+    public void setActionBarHideOffset(int hideOffset) {
+        getActionBar().setHideOffset(hideOffset);
+    }
 }
diff --git a/src/com/android/dialer/calllog/CallLogAdapter.java b/src/com/android/dialer/calllog/CallLogAdapter.java
index 583f10b..4752620 100644
--- a/src/com/android/dialer/calllog/CallLogAdapter.java
+++ b/src/com/android/dialer/calllog/CallLogAdapter.java
@@ -22,7 +22,6 @@
 import android.content.res.Resources;
 import android.database.Cursor;
 import android.net.Uri;
-import android.os.AsyncTask;
 import android.os.Handler;
 import android.os.Message;
 import android.provider.CallLog.Calls;
@@ -35,7 +34,6 @@
 import android.view.ViewTreeObserver;
 import android.widget.ImageView;
 import android.widget.TextView;
-import android.widget.Toast;
 
 import com.android.common.widget.GroupingListAdapter;
 import com.android.contacts.common.ContactPhotoManager;
@@ -45,8 +43,6 @@
 import com.android.dialer.PhoneCallDetails;
 import com.android.dialer.PhoneCallDetailsHelper;
 import com.android.dialer.R;
-import com.android.dialer.util.AsyncTaskExecutor;
-import com.android.dialer.util.AsyncTaskExecutors;
 import com.android.dialer.util.ExpirableCache;
 
 import com.google.common.annotations.VisibleForTesting;
@@ -127,10 +123,10 @@
     private static final int CONTACT_INFO_CACHE_SIZE = 100;
 
     /** Localized string representing the word "Today". */
-    private static final CharSequence TODAY_LABEL = DateUtils.getTodayString();
+    private final CharSequence mTodayLabel = DateUtils.getTodayString();
 
     /** Localized string representing the word "Yesterday". */
-    private static final CharSequence YESTERDAY_LABEL = DateUtils.getYesterdayString();
+    private final CharSequence mYesterdayLabel = DateUtils.getYesterdayString();
 
     /** Constant used to indicate no row is expanded. */
     private static final long NONE_EXPANDED = -1;
@@ -140,9 +136,6 @@
     private final CallFetcher mCallFetcher;
     private ViewTreeObserver mViewTreeObserver = null;
 
-    /** Aynchronous task executor, lazy instantiated as needed. */
-    private AsyncTaskExecutor mAsyncTaskExecutor;
-
     /**
      * A cache of the contact details for the phone numbers in the call log.
      * <p>
@@ -1320,9 +1313,9 @@
      */
     private CharSequence getGroupDescription(int group) {
        if (group == CallLogGroupBuilder.DAY_GROUP_TODAY) {
-           return TODAY_LABEL;
+           return mTodayLabel;
        } else if (group == CallLogGroupBuilder.DAY_GROUP_YESTERDAY) {
-           return YESTERDAY_LABEL;
+           return mYesterdayLabel;
        } else if (group == CallLogGroupBuilder.DAY_GROUP_LAST_WEEK) {
            return mContext.getResources().getString(R.string.call_log_header_last_week);
        } else {
diff --git a/src/com/android/dialer/calllog/CallLogFragment.java b/src/com/android/dialer/calllog/CallLogFragment.java
index faa4a3e..de00550 100644
--- a/src/com/android/dialer/calllog/CallLogFragment.java
+++ b/src/com/android/dialer/calllog/CallLogFragment.java
@@ -47,6 +47,7 @@
 import com.android.contacts.common.CallUtil;
 import com.android.contacts.common.GeoUtil;
 import com.android.contacts.common.util.PhoneNumberHelper;
+import com.android.contacts.common.util.ViewUtil;
 import com.android.dialer.R;
 import com.android.dialer.list.ListsFragment.HostInterface;
 import com.android.dialer.util.EmptyLoader;
@@ -563,6 +564,8 @@
         final ListView listView = getListView();
         listView.removeFooterView(mFooterView);
         listView.addFooterView(mFooterView);
+
+        ViewUtil.addBottomPaddingToListViewForFab(listView, getResources());
     }
 
     @Override
diff --git a/src/com/android/dialer/list/AllContactsFragment.java b/src/com/android/dialer/list/AllContactsFragment.java
index d05f66d..816869f 100644
--- a/src/com/android/dialer/list/AllContactsFragment.java
+++ b/src/com/android/dialer/list/AllContactsFragment.java
@@ -23,13 +23,14 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.AdapterView;
+import android.widget.ListView;
 import android.widget.QuickContactBadge;
 
 import com.android.contacts.common.list.ContactEntryListAdapter;
 import com.android.contacts.common.list.ContactEntryListFragment;
 import com.android.contacts.common.list.ContactListFilter;
-import com.android.contacts.common.list.ContactListItemView;
 import com.android.contacts.common.list.DefaultContactListAdapter;
+import com.android.contacts.common.util.ViewUtil;
 import com.android.dialer.R;
 
 /**
@@ -46,6 +47,12 @@
     }
 
     @Override
+    public void onViewCreated(View view, android.os.Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+        ViewUtil.addBottomPaddingToListViewForFab(getListView(), getResources());
+    }
+
+    @Override
     protected ContactEntryListAdapter createListAdapter() {
         final DefaultContactListAdapter adapter = new DefaultContactListAdapter(getActivity()) {
             @Override
diff --git a/src/com/android/dialer/list/DialerPhoneNumberListAdapter.java b/src/com/android/dialer/list/DialerPhoneNumberListAdapter.java
index 533a134..abceda4 100644
--- a/src/com/android/dialer/list/DialerPhoneNumberListAdapter.java
+++ b/src/com/android/dialer/list/DialerPhoneNumberListAdapter.java
@@ -139,16 +139,16 @@
         switch (shortcutType) {
             case SHORTCUT_DIRECT_CALL:
                 text = resources.getString(R.string.search_shortcut_call_number, number);
-                drawableId = R.drawable.ic_phone_dk;
+                drawableId = R.drawable.ic_search_phone;
                 break;
             case SHORTCUT_ADD_NUMBER_TO_CONTACTS:
                 text = resources.getString(R.string.search_shortcut_add_to_contacts);
-                drawableId = R.drawable.ic_add_person_dk;
+                drawableId = R.drawable.ic_search_add_contact;
                 break;
             default:
                 throw new IllegalArgumentException("Invalid shortcut type");
         }
-        v.setDrawableResource(R.drawable.list_item_avatar_bg, drawableId);
+        v.setDrawableResource(R.drawable.search_shortcut_background, drawableId);
         v.setDisplayName(text);
         v.setPhotoPosition(super.getPhotoPosition());
     }
diff --git a/src/com/android/dialer/list/ListsFragment.java b/src/com/android/dialer/list/ListsFragment.java
index ac3818c..2ff5a2a 100644
--- a/src/com/android/dialer/list/ListsFragment.java
+++ b/src/com/android/dialer/list/ListsFragment.java
@@ -126,12 +126,12 @@
     private PanelSlideListener mPanelSlideListener = new PanelSlideListener() {
         @Override
         public void onPanelSlide(View panel, float slideOffset) {
-            // For every 2 percent that the panel is slid upwards, clip 3 percent from each edge
+            // For every 1 percent that the panel is slid upwards, clip 2 percent from each edge
             // of the shortcut card, to achieve the animated effect of the shortcut card
             // rapidly shrinking and disappearing from view when the panel is slid upwards.
             // slideOffset is 1 when the shortcut card is fully exposed, and 0 when completely
             // hidden.
-            float ratioCardHidden = (1 - slideOffset) * 1.5f;
+            float ratioCardHidden = (1 - slideOffset) * 2f;
             if (mShortcutCardsListView.getCount() > 0) {
                 SwipeableShortcutCard v =
                         (SwipeableShortcutCard) mShortcutCardsListView.getChildAt(0);
@@ -326,13 +326,8 @@
         }
     }
 
-    public void maybeShowActionBar() {
-        // TODO: Try to show the action bar regardless of whether the panel is open, and then update
-        // the offset to show/hide the action bar, instead of updating the whether the action bar is
-        // shown in onPanelSlide.
-        if (mIsPanelOpen && mActionBar != null) {
-            mActionBar.show();
-        }
+    public boolean shouldShowActionBar() {
+        return mIsPanelOpen && mActionBar != null;
     }
 
     private void setupPaneLayout(OverlappingPaneLayout paneLayout) {
diff --git a/src/com/android/dialer/list/PhoneFavoriteSquareTileView.java b/src/com/android/dialer/list/PhoneFavoriteSquareTileView.java
index 0520ab4..776a7a2 100644
--- a/src/com/android/dialer/list/PhoneFavoriteSquareTileView.java
+++ b/src/com/android/dialer/list/PhoneFavoriteSquareTileView.java
@@ -21,6 +21,7 @@
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.ImageButton;
+import android.widget.TextView;
 
 import com.android.contacts.common.R;
 import com.android.contacts.common.list.ContactEntry;
@@ -47,7 +48,10 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-
+        final TextView nameView = (TextView) findViewById(R.id.contact_tile_name);
+        nameView.setElegantTextHeight(false);
+        final TextView phoneTypeView = (TextView) findViewById(R.id.contact_tile_phone_type);
+        phoneTypeView.setElegantTextHeight(false);
         mSecondaryButton = (ImageButton) findViewById(R.id.contact_tile_secondary_button);
     }
 
diff --git a/src/com/android/dialer/list/SearchFragment.java b/src/com/android/dialer/list/SearchFragment.java
index ab76fdc..9a30c4d 100644
--- a/src/com/android/dialer/list/SearchFragment.java
+++ b/src/com/android/dialer/list/SearchFragment.java
@@ -17,6 +17,7 @@
 
 import android.app.Activity;
 import android.content.Intent;
+import android.os.Bundle;
 import android.text.TextUtils;
 import android.view.View;
 import android.widget.AbsListView;
@@ -27,6 +28,7 @@
 import com.android.contacts.common.list.ContactListItemView;
 import com.android.contacts.common.list.OnPhoneNumberPickerActionListener;
 import com.android.contacts.common.list.PhoneNumberPickerFragment;
+import com.android.contacts.common.util.ViewUtil;
 import com.android.dialer.DialtactsActivity;
 import com.android.dialer.R;
 import com.android.dialer.list.OnListFragmentScrolledListener;
@@ -43,6 +45,12 @@
     private String mAddToContactNumber;
     private int mActionBarHeight;
 
+    public interface HostInterface {
+        public boolean isActionBarShowing();
+        public int getActionBarHideOffset();
+        public int getActionBarHeight();
+    }
+
     @Override
     public void onAttach(Activity activity) {
         super.onAttach(activity);
@@ -67,7 +75,9 @@
             getAdapter().setHasHeader(0, false);
         }
 
-        mActionBarHeight = ((DialtactsActivity) getActivity()).getActionBarHeight();
+        HostInterface activity = (HostInterface) getActivity();
+
+        mActionBarHeight = activity.getActionBarHeight();
 
         final View parentView = getView();
         parentView.setPaddingRelative(
@@ -90,12 +100,19 @@
             }
         });
 
-        if (!getActivity().getActionBar().isShowing()) {
+
+        if (!activity.isActionBarShowing()) {
             parentView.setTranslationY(-mActionBarHeight);
         }
     }
 
     @Override
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+        ViewUtil.addBottomPaddingToListViewForFab(getListView(), getResources());
+    }
+
+    @Override
     protected void setSearchMode(boolean flag) {
         super.setSearchMode(flag);
         // This hides the "All contacts with phone numbers" header in the search fragment
diff --git a/src/com/android/dialer/list/ShortcutCardsAdapter.java b/src/com/android/dialer/list/ShortcutCardsAdapter.java
index b4266d3..4df44f0 100644
--- a/src/com/android/dialer/list/ShortcutCardsAdapter.java
+++ b/src/com/android/dialer/list/ShortcutCardsAdapter.java
@@ -55,6 +55,7 @@
     private final ListsFragment mFragment;
 
     private final int mCallLogPadding;
+    private final int mCardMaxHorizontalClip;
 
     private final Context mContext;
 
@@ -101,6 +102,8 @@
         final Resources resources = context.getResources();
         mContext = context;
         mFragment = fragment;
+        mCardMaxHorizontalClip = resources.getDimensionPixelSize(
+                R.dimen.recent_call_log_item_horizontal_clip_limit);
         mCallLogPadding = resources.getDimensionPixelSize(R.dimen.recent_call_log_item_padding);
         mCallLogAdapter = callLogAdapter;
         mObserver = new CustomDataSetObserver();
@@ -301,8 +304,8 @@
             if (ratioHidden > 0.5f) {
                 mClipRect.set(0, 0 , 0, 0);
             } else {
-                int newLeft = (int) (ratioHidden * width);
-                int newRight = (width - newLeft);
+                int newLeft = (int) (ratioHidden * mCardMaxHorizontalClip);
+                int newRight = width - newLeft;
                 int newTop = (int) (ratioHidden * height);
                 int newBottom = (height - newTop);
                 mClipRect.set(newLeft, newTop, newRight, newBottom);
@@ -313,7 +316,7 @@
             final ViewGroup viewGroup = (ViewGroup) viewToClip;
             final int count = viewGroup.getChildCount();
             for (int i = 0; i < count; i++) {
-                viewGroup.getChildAt(i).setAlpha(Math.max(0, 1 - 4 * ratioHidden));
+                viewGroup.getChildAt(i).setAlpha(Math.max(0, 1 - 3 * ratioHidden));
             }
         }
     }
diff --git a/src/com/android/dialer/widget/ActionBarController.java b/src/com/android/dialer/widget/ActionBarController.java
new file mode 100644
index 0000000..49506f4
--- /dev/null
+++ b/src/com/android/dialer/widget/ActionBarController.java
@@ -0,0 +1,219 @@
+package com.android.dialer.widget;
+
+import com.google.common.annotations.VisibleForTesting;
+
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.os.Bundle;
+import android.util.Log;
+
+import com.android.dialer.DialtactsActivity;
+
+/**
+ * Controls the various animated properties of the actionBar: showing/hiding, fading/revealing,
+ * and collapsing/expanding, and assigns suitable properties to the actionBar based on the
+ * current state of the UI.
+ */
+public class ActionBarController {
+    public static final boolean DEBUG = DialtactsActivity.DEBUG;
+    public static final String TAG = "ActionBarController";
+    private static final String KEY_IS_SLID_UP = "key_actionbar_is_slid_up";
+    private static final String KEY_IS_FADED_OUT = "key_actionbar_is_faded_out";
+    private static final String KEY_IS_EXPANDED = "key_actionbar_is_expanded";
+
+    private ActivityUi mActivityUi;
+    private SearchEditTextLayout mSearchBox;
+
+    private boolean mIsActionBarSlidUp;
+
+    public interface ActivityUi {
+        public boolean isInSearchUi();
+        public boolean hasSearchQuery();
+        public boolean shouldShowActionBar();
+        public int getActionBarHeight();
+        public int getActionBarHideOffset();
+        public void setActionBarHideOffset(int hideOffset);
+    }
+
+    public ActionBarController(ActivityUi activityUi, SearchEditTextLayout searchBox) {
+        mActivityUi = activityUi;
+        mSearchBox = searchBox;
+    }
+
+    /**
+     * @return The offset the action bar is being translated upwards by
+     */
+    public int getHideOffset() {
+        return mActivityUi.getActionBarHideOffset();
+    }
+
+    /**
+     * @return Whether or not the action bar is currently showing (both slid down and visible)
+     */
+    public boolean isActionBarShowing() {
+        return !mIsActionBarSlidUp && !mSearchBox.isFadedOut();
+    }
+
+    /**
+     * Called when the user has tapped on the collapsed search box, to start a new search query.
+     */
+    public void onSearchBoxTapped() {
+        if (DEBUG) {
+            Log.d(TAG, "OnSearchBoxTapped: isInSearchUi " + mActivityUi.isInSearchUi());
+        }
+        if (!mActivityUi.isInSearchUi()) {
+            mSearchBox.expand(true /* animate */, true /* requestFocus */);
+        }
+    }
+
+    /**
+     * Called when search UI has been exited for some reason.
+     */
+    public void onSearchUiExited() {
+        if (DEBUG) {
+            Log.d(TAG, "OnSearchUIExited: isExpanded " + mSearchBox.isExpanded()
+                    + " isFadedOut: " + mSearchBox.isFadedOut()
+                    + " shouldShowActionBar: " + mActivityUi.shouldShowActionBar());
+        }
+        if (mSearchBox.isExpanded()) {
+            mSearchBox.collapse(true /* animate */);
+        }
+        if (mSearchBox.isFadedOut()) {
+            mSearchBox.fadeIn();
+        }
+
+        if (mActivityUi.shouldShowActionBar()) {
+            slideActionBarDown(false /* animate */);
+        } else {
+            slideActionBarUp(false /* animate */);
+        }
+    }
+
+    /**
+     * Called to indicate that the user is trying to hide the dialpad. Should be called before
+     * any state changes have actually occurred.
+     */
+    public void onDialpadDown() {
+        if (DEBUG) {
+            Log.d(TAG, "OnDialpadDown: isInSearchUi " + mActivityUi.isInSearchUi()
+                    + " hasSearchQuery: " + mActivityUi.hasSearchQuery()
+                    + " isFadedOut: " + mSearchBox.isFadedOut()
+                    + " isExpanded: " + mSearchBox.isExpanded());
+        }
+        if (mActivityUi.isInSearchUi()) {
+            if (mActivityUi.hasSearchQuery()) {
+                if (mSearchBox.isFadedOut()) {
+                    mSearchBox.setVisible(true);
+                }
+                if (!mSearchBox.isExpanded()) {
+                    mSearchBox.expand(false /* animate */, false /* requestFocus */);
+                }
+                slideActionBarDown(true /* animate */);
+            } else {
+                mSearchBox.fadeIn();
+            }
+        }
+    }
+
+    /**
+     * Called to indicate that the user is trying to show the dialpad. Should be called before
+     * any state changes have actually occurred.
+     */
+    public void onDialpadUp() {
+        if (DEBUG) {
+            Log.d(TAG, "OnDialpadUp: isInSearchUi " + mActivityUi.isInSearchUi());
+        }
+        if (mActivityUi.isInSearchUi()) {
+            slideActionBarUp(true);
+        } else {
+            // From the lists fragment
+            mSearchBox.fadeOut();
+        }
+    }
+
+    public void slideActionBarUp(boolean animate) {
+        if (DEBUG) {
+            Log.d(TAG, "Sliding actionBar up - animate: " + animate);
+        }
+        if (animate) {
+            ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
+            animator.addUpdateListener(new AnimatorUpdateListener() {
+                @Override
+                public void onAnimationUpdate(ValueAnimator animation) {
+                    final float value = (float) animation.getAnimatedValue();
+                    mActivityUi.setActionBarHideOffset(
+                            (int) (mActivityUi.getActionBarHeight() * value));
+                }
+            });
+            animator.start();
+        } else {
+           mActivityUi.setActionBarHideOffset(mActivityUi.getActionBarHeight());
+        }
+        mIsActionBarSlidUp = true;
+    }
+
+    public void slideActionBarDown(boolean animate) {
+        if (DEBUG) {
+            Log.d(TAG, "Sliding actionBar down - animate: " + animate);
+        }
+        if (animate) {
+            ValueAnimator animator = ValueAnimator.ofFloat(1, 0);
+            animator.addUpdateListener(new AnimatorUpdateListener() {
+                @Override
+                public void onAnimationUpdate(ValueAnimator animation) {
+                    final float value = (float) animation.getAnimatedValue();
+                    mActivityUi.setActionBarHideOffset(
+                            (int) (mActivityUi.getActionBarHeight() * value));
+                }
+            });
+            animator.start();
+        } else {
+            mActivityUi.setActionBarHideOffset(0);
+        }
+        mIsActionBarSlidUp = false;
+    }
+
+    /**
+     * Saves the current state of the action bar into a provided {@link Bundle}
+     */
+    public void saveInstanceState(Bundle outState) {
+        outState.putBoolean(KEY_IS_SLID_UP, mIsActionBarSlidUp);
+        outState.putBoolean(KEY_IS_FADED_OUT, mSearchBox.isFadedOut());
+        outState.putBoolean(KEY_IS_EXPANDED, mSearchBox.isExpanded());
+    }
+
+    /**
+     * Restores the action bar state from a provided {@link Bundle}
+     */
+    public void restoreInstanceState(Bundle inState) {
+        mIsActionBarSlidUp = inState.getBoolean(KEY_IS_SLID_UP);
+        if (mIsActionBarSlidUp) {
+            slideActionBarUp(false);
+        } else {
+            slideActionBarDown(false);
+        }
+
+        final boolean isSearchBoxFadedOut = inState.getBoolean(KEY_IS_FADED_OUT);
+        if (isSearchBoxFadedOut) {
+            if (!mSearchBox.isFadedOut()) {
+                mSearchBox.setVisible(false);
+            }
+        } else if (mSearchBox.isFadedOut()) {
+                mSearchBox.setVisible(true);
+        }
+
+        final boolean isSearchBoxExpanded = inState.getBoolean(KEY_IS_EXPANDED);
+        if (isSearchBoxExpanded) {
+            if (!mSearchBox.isExpanded()) {
+                mSearchBox.expand(false, false);
+            }
+        } else if (mSearchBox.isExpanded()) {
+                mSearchBox.collapse(false);
+        }
+    }
+
+    @VisibleForTesting
+    public boolean getIsActionBarSlidUp() {
+        return mIsActionBarSlidUp;
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/dialer/widget/SearchEditTextLayout.java b/src/com/android/dialer/widget/SearchEditTextLayout.java
index 6830842..ef3ddcc 100644
--- a/src/com/android/dialer/widget/SearchEditTextLayout.java
+++ b/src/com/android/dialer/widget/SearchEditTextLayout.java
@@ -16,6 +16,8 @@
 
 package com.android.dialer.widget;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.content.Context;
@@ -27,7 +29,7 @@
 import android.widget.EditText;
 import android.widget.FrameLayout;
 
-import com.android.contacts.common.animation.AnimationUtils;
+import com.android.contacts.common.animation.AnimUtils;
 import com.android.dialer.R;
 
 public class SearchEditTextLayout extends FrameLayout {
@@ -39,12 +41,16 @@
     private int mLeftMargin;
     private int mRightMargin;
 
-    private int mBackgroundColor;
+    /* Subclass-visible for testing */
+    protected boolean mIsExpanded = false;
+    protected boolean mIsFadedOut = false;
 
     private View mCollapsed;
     private View mExpanded;
     private EditText mSearchView;
 
+    private ValueAnimator mAnimator;
+
     private OnBackButtonClickedListener mOnBackButtonClickedListener;
 
     /**
@@ -56,7 +62,6 @@
 
     public SearchEditTextLayout(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mBackgroundColor = getResources().getColor(R.color.searchbox_background_color);
     }
 
     public void setPreImeKeyListener(OnKeyListener listener) {
@@ -117,32 +122,85 @@
         return super.dispatchKeyEventPreIme(event);
     }
 
-    public void animateExpandOrCollapse(boolean expand) {
-        final ValueAnimator animator;
-        if (expand) {
-            AnimationUtils.crossFadeViews(mExpanded, mCollapsed, ANIMATION_DURATION);
-            animator = ValueAnimator.ofFloat(1f, 0f);
-            setBackgroundResource(R.drawable.search_shadow);
-            mSearchView.requestFocus();
+    public void fadeOut() {
+        AnimUtils.fadeOut(this, ANIMATION_DURATION);
+        mIsFadedOut = true;
+    }
+
+    public void fadeIn() {
+        AnimUtils.fadeIn(this, ANIMATION_DURATION);
+        mIsFadedOut = false;
+    }
+
+    public void setVisible(boolean visible) {
+        if (visible) {
+            setAlpha(1);
+            setVisibility(View.VISIBLE);
+            mIsFadedOut = false;
         } else {
-            AnimationUtils.crossFadeViews(mCollapsed, mExpanded, ANIMATION_DURATION);
-            animator = ValueAnimator.ofFloat(0f, 1f);
-            setBackgroundResource(R.drawable.rounded_corner);
+            setAlpha(0);
+            setVisibility(View.GONE);
+            mIsFadedOut = true;
         }
-        animator.addUpdateListener(new AnimatorUpdateListener() {
+    }
+    public void expand(boolean animate, boolean requestFocus) {
+        if (animate) {
+            AnimUtils.crossFadeViews(mExpanded, mCollapsed, ANIMATION_DURATION);
+            mAnimator = ValueAnimator.ofFloat(1f, 0f);
+            prepareAnimator(true);
+        } else {
+            mExpanded.setVisibility(View.VISIBLE);
+            mExpanded.setAlpha(1);
+            setMargins(0f);
+            mCollapsed.setVisibility(View.GONE);
+        }
+
+        setBackgroundResource(R.drawable.search_shadow);
+        if (requestFocus) {
+            mSearchView.requestFocus();
+        }
+        mIsExpanded = true;
+    }
+
+    public void collapse(boolean animate) {
+        if (animate) {
+            AnimUtils.crossFadeViews(mCollapsed, mExpanded, ANIMATION_DURATION);
+            mAnimator = ValueAnimator.ofFloat(0f, 1f);
+            prepareAnimator(false);
+        } else {
+            mCollapsed.setVisibility(View.VISIBLE);
+            mCollapsed.setAlpha(1);
+            setMargins(1f);
+            mExpanded.setVisibility(View.GONE);
+        }
+
+        mIsExpanded = false;
+        setBackgroundResource(R.drawable.rounded_corner);
+    }
+
+    private void prepareAnimator(final boolean expand) {
+        if (mAnimator != null) {
+            mAnimator.cancel();
+        }
+
+        mAnimator.addUpdateListener(new AnimatorUpdateListener() {
             @Override
             public void onAnimationUpdate(ValueAnimator animation) {
                 final Float fraction = (Float) animation.getAnimatedValue();
-                MarginLayoutParams params = (MarginLayoutParams) getLayoutParams();
-                params.topMargin = (int) (mTopMargin * fraction);
-                params.bottomMargin = (int) (mBottomMargin * fraction);
-                params.leftMargin = (int) (mLeftMargin * fraction);
-                params.rightMargin = (int) (mRightMargin * fraction);
-                requestLayout();
+                setMargins(fraction);
             }
         });
-        animator.setDuration(ANIMATION_DURATION);
-        animator.start();
+
+        mAnimator.setDuration(ANIMATION_DURATION);
+        mAnimator.start();
+    }
+
+    public boolean isExpanded() {
+        return mIsExpanded;
+    }
+
+    public boolean isFadedOut() {
+        return mIsFadedOut;
     }
 
     private void showInputMethod(View view) {
@@ -152,4 +210,18 @@
             imm.showSoftInput(view, 0);
         }
     }
+
+    /**
+     * Assigns margins to the search box as a fraction of its maximum margin size
+     *
+     * @param fraction How large the margins should be as a fraction of their full size
+     */
+    private void setMargins(float fraction) {
+        MarginLayoutParams params = (MarginLayoutParams) getLayoutParams();
+        params.topMargin = (int) (mTopMargin * fraction);
+        params.bottomMargin = (int) (mBottomMargin * fraction);
+        params.leftMargin = (int) (mLeftMargin * fraction);
+        params.rightMargin = (int) (mRightMargin * fraction);
+        requestLayout();
+    }
 }
\ No newline at end of file
diff --git a/tests/src/com/android/dialer/widget/ActionBarControllerTest.java b/tests/src/com/android/dialer/widget/ActionBarControllerTest.java
new file mode 100644
index 0000000..c67ea35
--- /dev/null
+++ b/tests/src/com/android/dialer/widget/ActionBarControllerTest.java
@@ -0,0 +1,181 @@
+/*
+ * 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.
+ */
+
+package com.android.dialer.widget;
+
+import android.content.Context;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.dialer.widget.ActionBarController.ActivityUi;
+
+@SmallTest
+public class ActionBarControllerTest extends InstrumentationTestCase {
+
+    private static final int ACTION_BAR_HEIGHT = 100;
+    private ActionBarController mActionBarController;
+    private SearchEditTextLayout mSearchBox;
+    private MockActivityUi mActivityUi;
+
+    private class MockActivityUi implements ActivityUi {
+        boolean isInSearchUi;
+        boolean hasSearchQuery;
+        boolean shouldShowActionBar;
+        int actionBarHideOffset;
+
+        @Override
+        public boolean isInSearchUi() {
+            return isInSearchUi;
+        }
+
+        @Override
+        public boolean hasSearchQuery() {
+            return hasSearchQuery;
+        }
+
+        @Override
+        public boolean shouldShowActionBar() {
+            return shouldShowActionBar;
+        }
+
+        @Override
+        public int getActionBarHeight() {
+            return ACTION_BAR_HEIGHT;
+        }
+
+        @Override
+        public int getActionBarHideOffset() {
+            return actionBarHideOffset;
+        }
+
+        @Override
+        public void setActionBarHideOffset(int hideOffset) {
+            actionBarHideOffset = hideOffset;
+        }
+    }
+
+    /**
+     * Mock version of the searchbox, that updates its state immediately instead of animating
+     */
+    private class MockSearchBox extends SearchEditTextLayout {
+
+        public MockSearchBox(Context context) {
+            super(context, null);
+        }
+
+        @Override
+        public void expand(boolean animate, boolean requestFocus) {
+            mIsExpanded = true;
+        }
+
+        @Override
+        public void collapse(boolean animate) {
+            mIsExpanded = false;
+        }
+    }
+
+    @Override
+    protected void setUp() {
+        mActivityUi = new MockActivityUi();
+        mSearchBox = new MockSearchBox(this.getInstrumentation().getContext());
+        mActionBarController = new ActionBarController(mActivityUi, mSearchBox);
+    }
+
+    // Tapping the search box should only do something when the activity is not in the search UI
+    public void testSearchBoxTapped() {
+        mSearchBox.collapse(false);
+        mActivityUi.isInSearchUi = false;
+        mActionBarController.onSearchBoxTapped();
+        assertActionBarState(true, false, false);
+
+        // Collapse the search box manually again. This time tapping on the search box should not
+        // expand the search box because isInSearchUi is not true.
+        mSearchBox.collapse(false);
+        mActivityUi.isInSearchUi = true;
+        mActionBarController.onSearchBoxTapped();
+        assertActionBarState(false, false, false);
+    }
+
+    // The search box should always end up being faded in and collapsed. If necessary, it should
+    // be slid down or up depending on what the state of the action bar was before that.
+    public void testOnSearchUiExited() {
+        // ActionBar shown previously before entering searchUI
+        mSearchBox.expand(true, false);
+        mSearchBox.setVisible(false);
+        mActivityUi.shouldShowActionBar = true;
+        mActionBarController.onSearchUiExited();
+        assertActionBarState(false, false, false);
+
+        // ActionBar slid up previously before entering searchUI
+        mSearchBox.collapse(false);
+        mSearchBox.setVisible(false);
+        mActivityUi.shouldShowActionBar = false;
+        mActionBarController.onSearchUiExited();
+        assertActionBarState(false, false, true);
+    }
+
+    // Depending on what state the UI was in previously, sliding the dialpad down can mean either
+    // displaying the expanded search box by sliding it down, displaying the unexpanded search box,
+    // or nothing at all.
+    public void testOnDialpadDown() {
+        // No search query typed in the dialpad and action bar was showing before
+        mActivityUi.shouldShowActionBar = true;
+        mActivityUi.isInSearchUi = true;
+        mSearchBox.setVisible(false);
+        mActionBarController.onDialpadDown();
+        assertActionBarState(false, false, false);
+
+        // No search query typed in the dialpad, but action bar was not showing before
+        mActionBarController.slideActionBarUp(false);
+        mActivityUi.shouldShowActionBar = false;
+        mSearchBox.setVisible(false);
+        mActionBarController.onDialpadDown();
+        assertActionBarState(false, false, true);
+
+        // Something typed in the dialpad - so remain in search UI and slide the expanded search
+        // box down
+        mActionBarController.slideActionBarUp(false);
+        mActivityUi.shouldShowActionBar = true;
+        mActivityUi.hasSearchQuery= true;
+        mSearchBox.setVisible(false);
+        mSearchBox.expand(false, false);
+        mActionBarController.onDialpadDown();
+        assertActionBarState(true, false, false);
+    }
+
+    // Sliding the dialpad up should fade out the search box if we weren't already in search, or
+    // slide up the search box otherwise
+    public void testOnDialpadUp() {
+        mActivityUi.isInSearchUi = false;
+        mActionBarController.onDialpadUp();
+        assertActionBarState(false, true, false);
+
+        // In Search UI, with expanded search box and something currently typed in the search box
+        mActivityUi.isInSearchUi = true;
+        mActivityUi.hasSearchQuery = true;
+        mSearchBox.expand(true, false);
+        mSearchBox.setVisible(true);
+        mActionBarController.slideActionBarUp(false);
+        mActionBarController.onDialpadUp();
+        assertActionBarState(true, false, true);
+    }
+
+    private void assertActionBarState(boolean isExpanded, boolean isFadedOut, boolean isSlidUp) {
+        assertEquals(isExpanded, mSearchBox.isExpanded());
+        assertEquals(isFadedOut, mSearchBox.isFadedOut());
+        assertEquals(isSlidUp, mActionBarController.getIsActionBarSlidUp());
+    }
+}