Initial commit of all new dialer activities, layouts and styles

As far as possible, this change does not modify any behavior/look
of the existing dialer. All modifications to classes/layouts/style attributes
that would affect functionality of the old dialer are instead done in
separate new files.

Added new versions of all activities, fragments, layouts, menus
and resources that have been rewritten or modified.

The activities do not have intent filters yet in order to not interfere
with the existing dialer.

Added some new values in colors/styles/dimens for the newly added
layouts.

Added NewCallLogActivity to separate the CallLogFragment from
DialtactsActivity. All call log and voicemail entries are now presented
in a separate (New)CallLogActivity.

IntentProvider.getCallDetailIntent now takes a cursor instead of an
adapter for more flexibility.

Add OnListFragmentScrolledListener interface for DialtactsActivity
to receive callback when one of its children fragment is scrolled.

Added slide in and slide out animations for DialpadFragment.

Add slide up and hide animations for search view

All menu options now show up in a PopupMenu in NewPhoneFavoriteFragment.

Added call log adapter into NewPhoneFavoriteMergedAdapter.

Rewrote layout of DialpadFragment to show up as a fragment partially overlaying
the screen.
Removed some unused code in DialpadFragment (smart dialing, menu handling)

Add fragments and adapters for SmartDial.

- Update Dialer database to support highlight masking and record contact
  data Uri, as well as photo uri
- Add a fragment and adapter for smart dialing
- Add SmartDialCursorLoader to load SmartDial results.
- Typing in the dialpad now returns smart dialing results instead of regular
  search results

QuickContactTiles for all sub-adapters of PhoneFavoriteMergedAdapter now use
light theme instead of the the default dark theme.

Removed all redundant call log filter and contacts to display filter code

Moved Dialer specific UI list-related classes to the Dialer package

Change-Id: I34885813e4fa79b69e29ac870a87a56d6f08a5e7
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 0efe21d..273429c 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -123,6 +123,69 @@
             </intent-filter>
         </activity>
 
+        <activity android:name=".NewDialtactsActivity"
+            android:label="New Dialer"
+            android:theme="@style/NewDialtactsTheme"
+            android:uiOptions="splitActionBarWhenNarrow"
+            android:launchMode="singleTask"
+            android:clearTaskOnLaunch="true"
+            android:icon="@mipmap/ic_launcher_phone"
+            android:screenOrientation="nosensor"
+            android:enabled="@*android:bool/config_voice_capable"
+            android:windowSoftInputMode="stateAlwaysHidden|adjustNothing">
+
+            <!--
+            <intent-filter>
+                <action android:name="android.intent.action.DIAL" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.BROWSABLE" />
+                <data android:mimeType="vnd.android.cursor.item/phone" />
+                <data android:mimeType="vnd.android.cursor.item/person" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.DIAL" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.BROWSABLE" />
+                <data android:scheme="voicemail" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.DIAL" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.LAUNCHER" />
+                <category android:name="android.intent.category.BROWSABLE" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.VIEW" />
+                <action android:name="android.intent.action.DIAL" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.BROWSABLE" />
+                <data android:scheme="tel" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.CALL_BUTTON" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.BROWSABLE" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="com.android.phone.action.TOUCH_DIALER" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.TAB" />
+            </intent-filter>
+            -->
+
+        </activity>
+
+        <activity android:name="com.android.dialer.calllog.NewCallLogActivity"
+                  android:label="@string/recentCallsIconLabel"
+                  android:theme="@style/NewDialtactsTheme"
+                  android:screenOrientation="portrait"
+                  android:icon="@mipmap/ic_launcher_phone">
+        </activity>
+
         <activity android:name="com.android.dialer.CallDetailActivity"
                   android:label="@string/callDetailTitle"
                   android:theme="@style/CallDetailActivityTheme"
diff --git a/proguard.flags b/proguard.flags
index 2447bfd..40ef035 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -7,10 +7,9 @@
 
 # Any class or method annotated with NeededForTesting or NeededForReflection.
 -keep @com.android.contacts.common.test.NeededForTesting class *
--keep @com.android.dialer.test.NeededForReflection class *
 -keepclassmembers class * {
 @com.android.contacts.common.test.NeededForTesting *;
-@com.android.dialer.test.NeededForReflection *;
+@com.android.dialer.NeededForReflection *;
 }
 
 -verbose
diff --git a/res/anim/slide_in.xml b/res/anim/slide_in.xml
new file mode 100644
index 0000000..b7836f0
--- /dev/null
+++ b/res/anim/slide_in.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+<objectAnimator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:interpolator="@android:anim/linear_interpolator"
+    android:valueFrom="0.67"
+    android:valueTo="0"
+    android:valueType="floatType"
+    android:propertyName="yFraction"
+    android:duration="200" />
\ No newline at end of file
diff --git a/res/anim/slide_out.xml b/res/anim/slide_out.xml
new file mode 100644
index 0000000..7df102d
--- /dev/null
+++ b/res/anim/slide_out.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+<objectAnimator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:interpolator="@android:anim/linear_interpolator"
+    android:valueFrom="0"
+    android:valueTo="0.67"
+    android:valueType="floatType"
+    android:propertyName="yFraction"
+    android:duration="200" />
\ No newline at end of file
diff --git a/res/layout/call_log_activity_new.xml b/res/layout/call_log_activity_new.xml
new file mode 100644
index 0000000..f9806e8
--- /dev/null
+++ b/res/layout/call_log_activity_new.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_marginTop="?android:attr/actionBarSize"
+    android:id="@+id/calllog_frame">
+    <android.support.v4.view.ViewPager
+        android:id="@+id/call_log_pager"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_marginTop="?android:attr/actionBarSize" />
+</FrameLayout>
diff --git a/res/layout/new_call_log_fragment.xml b/res/layout/new_call_log_fragment.xml
index 041ca7b..e58e160 100644
--- a/res/layout/new_call_log_fragment.xml
+++ b/res/layout/new_call_log_fragment.xml
@@ -16,7 +16,6 @@
 
 <!-- Layout parameters are set programmatically. -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/FragmentActionBarPadding"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical"
diff --git a/res/layout/new_call_log_list_item.xml b/res/layout/new_call_log_list_item.xml
index 54f4fff..c674f2e 100644
--- a/res/layout/new_call_log_list_item.xml
+++ b/res/layout/new_call_log_list_item.xml
@@ -127,13 +127,6 @@
                     />
                 </LinearLayout>
             </LinearLayout>
-            <View
-                android:id="@+id/divider"
-                android:layout_width="1px"
-                android:layout_height="@dimen/call_log_call_action_size"
-                android:background="@drawable/ic_divider_dashed_holo_dark"
-                android:layout_gravity="center_vertical"
-            />
             <ImageButton
                 android:id="@+id/secondary_action_icon"
                 android:layout_width="@dimen/call_log_call_action_width"
diff --git a/res/layout/new_dialpad.xml b/res/layout/new_dialpad.xml
index f9a0785..29f9cf0 100644
--- a/res/layout/new_dialpad.xml
+++ b/res/layout/new_dialpad.xml
@@ -26,7 +26,6 @@
     android:paddingStart="5dip"
     android:paddingEnd="5dip"
     android:paddingBottom="10dip"
-    android:background="@drawable/dialpad_background"
     android:layoutDirection="ltr" >
 
     <TableRow
diff --git a/res/layout/new_dialpad_fragment.xml b/res/layout/new_dialpad_fragment.xml
index f3bd2a2..4641e00 100644
--- a/res/layout/new_dialpad_fragment.xml
+++ b/res/layout/new_dialpad_fragment.xml
@@ -13,108 +13,96 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/top"
+<view class="com.android.dialer.dialpad.NewDialpadFragment$DialpadSlidingLinearLayout"
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:orientation="vertical"
-    android:paddingStart="@dimen/dialpad_horizontal_margin"
-    android:paddingEnd="@dimen/dialpad_horizontal_margin"
-    android:layoutDirection="ltr" >
-
-    <!-- Text field and possibly soft menu button above the keypad where
-         the digits are displayed. -->
+    android:orientation="vertical" >
+    <!-- spacer view -->
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" />
     <LinearLayout
-        android:id="@+id/digits_container"
+        android:id="@+id/top"
         android:layout_width="match_parent"
-        android:layout_height="0px"
-        android:layout_weight="@integer/dialpad_layout_weight_digits"
-        android:layout_marginTop="@dimen/dialpad_vertical_margin"
-        android:gravity="center"
-        android:background="@drawable/dialpad_background" >
+        android:layout_height="0dp"
+        android:layout_weight="2"
+        android:orientation="vertical"
+        android:paddingStart="@dimen/dialpad_horizontal_margin"
+        android:paddingEnd="@dimen/dialpad_horizontal_margin"
+        android:layoutDirection="ltr"
+        android:background="@color/background_dialpad" >
 
-        <com.android.dialer.dialpad.DigitsEditText
-            android:id="@+id/digits"
-            android:layout_width="0dip"
-            android:layout_weight="1"
-            android:layout_height="match_parent"
-            android:gravity="center"
-            android:textAppearance="@style/DialtactsDigitsTextAppearance"
-            android:textColor="?android:attr/textColorPrimary"
-            android:nextFocusRight="@+id/overflow_menu"
-            android:background="@android:color/transparent" />
 
-        <ImageButton
-            android:id="@+id/deleteButton"
-            android:layout_width="56dip"
-            android:layout_height="match_parent"
-            android:layout_gravity="center_vertical"
-            android:gravity="center"
-            android:state_enabled="false"
-            android:background="?android:attr/selectableItemBackground"
-            android:contentDescription="@string/description_delete_button"
-            android:src="@drawable/ic_dial_action_delete" />
-    </LinearLayout>
-
-    <!-- Smart dial suggestion section.
-         sp is used here for this layout instead of dp in order for it to resize as
-         appropriate when the font size increases. This is a one-time exception that is
-         ok in this case because there is space for the suggestion strip to expand. -->
-    <RelativeLayout
-        android:id="@+id/dialpad_smartdial_container"
-        android:layout_width="match_parent"
-        android:layout_height="50sp"
-        android:layout_marginTop="@dimen/dialpad_vertical_margin">
-        <View
-            android:id="@+id/dialpad_smartdial_list_background"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:background="@drawable/dialpad_background">
-        </View>
+        <!-- Text field and possibly soft menu button above the keypad where
+             the digits are displayed. -->
         <LinearLayout
-            android:id="@+id/dialpad_smartdial_list"
+            android:id="@+id/digits_container"
             android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:orientation="horizontal"
-            android:gravity="center">
+            android:layout_height="0px"
+            android:layout_weight="@integer/dialpad_layout_weight_digits_new"
+            android:layout_marginTop="@dimen/dialpad_vertical_margin"
+            android:gravity="center" >
+
+            <com.android.dialer.dialpad.DigitsEditText
+                android:id="@+id/digits"
+                android:layout_width="0dip"
+                android:layout_weight="1"
+                android:layout_height="match_parent"
+                android:gravity="center"
+                android:textAppearance="@style/DialtactsDigitsTextAppearance"
+                android:textColor="@color/dialpad_text_color"
+                android:nextFocusRight="@+id/overflow_menu"
+                android:background="@android:color/transparent" />
+
+            <ImageButton
+                android:id="@+id/deleteButton"
+                android:layout_width="56dip"
+                android:layout_height="match_parent"
+                android:layout_gravity="center_vertical"
+                android:gravity="center"
+                android:state_enabled="false"
+                android:background="?android:attr/selectableItemBackground"
+                android:contentDescription="@string/description_delete_button"
+                android:src="@drawable/ic_dial_action_delete" />
         </LinearLayout>
-    </RelativeLayout>
 
-    <!-- Keypad section -->
-    <include layout="@layout/dialpad" />
+        <!-- Keypad section -->
+        <include layout="@layout/new_dialpad" />
 
-    <View style="@style/DialpadHorizontalSeparator"/>
+        <View style="@style/DialpadHorizontalSeparator"/>
 
-    <!-- left and right paddings will be modified by the code. See DialpadFragment. -->
-    <FrameLayout
-        android:id="@+id/dialButtonContainer"
-        android:layout_width="match_parent"
-        android:layout_height="0px"
-        android:layout_weight="@integer/dialpad_layout_weight_additional_buttons"
-        android:layout_gravity="center_horizontal"
-        android:background="@drawable/dialpad_background">
-
-        <ImageButton
-            android:id="@+id/dialButton"
+        <!-- left and right paddings will be modified by the code. See DialpadFragment. -->
+        <FrameLayout
+            android:id="@+id/dialButtonContainer"
             android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_gravity="center"
-            android:state_enabled="false"
-            android:background="@drawable/btn_call"
-            android:contentDescription="@string/description_dial_button"
-            android:src="@drawable/ic_dial_action_call" />
+            android:layout_height="0px"
+            android:layout_weight="@integer/dialpad_layout_weight_additional_buttons"
+            android:layout_gravity="center_horizontal"
+            android:background="@color/dialpad_primary_text_color">
 
-    </FrameLayout>
+            <ImageButton
+                android:id="@+id/dialButton"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_gravity="center"
+                android:state_enabled="false"
+                android:background="@drawable/btn_call"
+                android:contentDescription="@string/description_dial_button"
+                android:src="@drawable/ic_dial_action_call" />
 
-    <!-- "Dialpad chooser" UI, shown only when the user brings up the
-         Dialer while a call is already in progress.
-         When this UI is visible, the other Dialer elements
-         (the textfield/button and the dialpad) are hidden. -->
-    <ListView android:id="@+id/dialpadChooser"
-        android:layout_width="match_parent"
-        android:layout_height="1dip"
-        android:layout_weight="1"
-    />
+        </FrameLayout>
 
-</LinearLayout>
+        <!-- "Dialpad chooser" UI, shown only when the user brings up the
+             Dialer while a call is already in progress.
+             When this UI is visible, the other Dialer elements
+             (the textfield/button and the dialpad) are hidden. -->
+        <ListView android:id="@+id/dialpadChooser"
+            android:layout_width="match_parent"
+            android:layout_height="1dip"
+            android:layout_weight="1"
+        />
+
+    </LinearLayout>
+</view>
\ No newline at end of file
diff --git a/res/layout/new_dialtacts_activity.xml b/res/layout/new_dialtacts_activity.xml
index 079ce37..a9960d8 100644
--- a/res/layout/new_dialtacts_activity.xml
+++ b/res/layout/new_dialtacts_activity.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2006 The Android Open Source Project
+<!-- Copyright (C) 2013 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.
@@ -13,35 +13,37 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:layout_marginTop="?android:attr/actionBarSize"
-    android:id="@+id/dialtacts_frame"
+    android:focusable="true"
+    android:focusableInTouchMode="true"
+    android:clipChildren="false"
+    android:id="@+id/dialtacts_container"
     >
-    <android.support.v4.view.ViewPager
-        android:id="@+id/pager"
+    <LinearLayout
         android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-
-    <ImageButton
-         android:id="@+id/searchButton"
-         android:layout_width="wrap_content"
-         android:layout_height="?android:attr/actionBarSize"
-         android:layout_gravity="bottom|start"
-         android:state_enabled="false"
-         android:background="?android:attr/selectableItemBackground"
-         android:contentDescription="@string/description_search_button"
-         android:src="@drawable/ic_dial_action_search"/>
-
-    <ImageButton
-         android:id="@+id/overflow_menu"
-         android:layout_width="wrap_content"
-         android:layout_height="?android:attr/actionBarSize"
-         android:layout_gravity="bottom|end"
-         android:src="@drawable/ic_menu_overflow"
-         android:contentDescription="@string/action_menu_overflow_description"
-         android:nextFocusLeft="@id/digits"
-         android:background="?android:attr/selectableItemBackground"/>
+        android:layout_height="match_parent"
+        android:clipChildren="false"
+        android:orientation="vertical" >
+        <SearchView
+            android:id="@+id/search_view"
+            android:layout_width="match_parent"
+            android:layout_height="?android:attr/actionBarSize"
+            android:iconifiedByDefault="false"
+            android:inputType="textFilter" />
+        <FrameLayout
+            android:layout_height="0dp"
+            android:layout_weight="1"
+            android:layout_width="match_parent"
+            android:id="@id/dialtacts_frame"
+            android:clipChildren="false">
+        </FrameLayout>
+        <View
+            android:id="@+id/dialtacts_bottom_padding"
+            android:layout_width="match_parent"
+            android:layout_height="?android:attr/actionBarSize"
+            android:visibility="gone" />
+    </LinearLayout>
 </FrameLayout>
diff --git a/res/layout/new_phone_favorites_fragment.xml b/res/layout/new_phone_favorites_fragment.xml
index 8931cf6..33a3eb4 100644
--- a/res/layout/new_phone_favorites_fragment.xml
+++ b/res/layout/new_phone_favorites_fragment.xml
@@ -17,15 +17,16 @@
 <!-- Use LinearLayout + FrameLayout, just to rely on android:divider and android:showDividers -->
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/FragmentActionBarPadding"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical"
     android:divider="?android:attr/dividerHorizontal"
-    android:showDividers="end">
+    android:showDividers="end"
+    android:clipChildren="false">
     <FrameLayout
         android:layout_width="match_parent"
-        android:layout_height="match_parent">
+        android:layout_height="0dp"
+        android:layout_weight="1">
         <ListView
             android:id="@+id/contact_tile_list"
             android:layout_width="match_parent"
@@ -44,4 +45,33 @@
             android:textColor="?android:attr/textColorSecondary"
             android:textAppearance="?android:attr/textAppearanceLarge"/>
     </FrameLayout>
+    <FrameLayout
+        android:layout_height="?android:attr/actionBarSize"
+        android:layout_width="match_parent"
+        android:id="@+id/fake_action_bar">
+        <ImageButton
+            android:id="@+id/call_history_button"
+            android:layout_width="@dimen/fake_menu_button_min_width"
+            android:layout_height="match_parent"
+            android:layout_gravity="bottom|start"
+            android:background="?android:attr/selectableItemBackground"
+            android:contentDescription="@string/description_search_button"
+            android:src="@drawable/ic_dial_action_search"/>
+        <ImageButton
+            android:id="@+id/dialpad_button"
+            android:layout_width="@dimen/fake_menu_button_min_width"
+            android:layout_height="match_parent"
+            android:layout_gravity="bottom|center"
+            android:background="?android:attr/selectableItemBackground"
+            android:contentDescription="@string/description_search_button"
+            android:src="@drawable/ic_dial_action_search"/>
+        <ImageButton
+             android:id="@+id/overflow_menu"
+             android:layout_width="@dimen/fake_menu_button_min_width"
+             android:layout_height="match_parent"
+             android:layout_gravity="bottom|end"
+             android:src="@drawable/ic_menu_overflow"
+             android:contentDescription="@string/action_menu_overflow_description"
+             android:background="?android:attr/selectableItemBackground"/>
+    </FrameLayout>
 </LinearLayout>
diff --git a/res/layout/phone_favorite_regular_row_view.xml b/res/layout/phone_favorite_regular_row_view.xml
new file mode 100644
index 0000000..30e109f
--- /dev/null
+++ b/res/layout/phone_favorite_regular_row_view.xml
@@ -0,0 +1,106 @@
+<?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.
+-->
+
+<!-- Layout parameters are set programmatically. -->
+<view
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/contact_tile_frequent_phone"
+    class="com.android.dialer.list.PhoneFavoriteRegularRowView"
+    android:focusable="true"
+    android:background="?android:attr/selectableItemBackground"
+    android:nextFocusLeft="@+id/contact_tile_quick">
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" >
+
+        <com.android.contacts.common.widget.LayoutSuppressingQuickContactBadge
+            android:id="@id/contact_tile_quick"
+            android:layout_width="64dip"
+            android:layout_height="64dip"
+            android:layout_alignParentLeft="true"
+            android:layout_alignParentStart="true"
+            android:nextFocusRight="@id/contact_tile_frequent_phone"
+            android:scaleType="centerCrop"
+            android:focusable="true" />
+
+        <TextView
+            android:id="@+id/contact_tile_name"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="8dip"
+            android:layout_marginStart="8dip"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:layout_marginTop="8dip"
+            android:layout_toRightOf="@id/contact_tile_quick"
+            android:layout_toEndOf="@id/contact_tile_quick"
+            android:singleLine="true"
+            android:fadingEdge="horizontal"
+            android:fadingEdgeLength="3dip"
+            android:ellipsize="marquee"
+            android:textAlignment="viewStart" />
+
+        <LinearLayout
+            android:orientation="horizontal"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/contact_tile_name"
+            android:layout_toRightOf="@id/contact_tile_quick"
+            android:layout_toEndOf="@id/contact_tile_quick"
+            android:gravity="center_vertical">
+
+            <TextView
+                android:id="@+id/contact_tile_phone_number"
+                android:layout_width="0dip"
+                android:layout_height="wrap_content"
+                android:layout_weight="?attr/list_item_data_width_weight"
+                android:textSize="14sp"
+                android:ellipsize="marquee"
+                android:textColor="@color/dialtacts_secondary_text_color"
+                android:layout_marginLeft="8dip"
+                android:layout_marginStart="8dip"
+                android:singleLine="true"
+                android:layout_gravity="bottom"
+                android:textDirection="ltr"
+                android:textAlignment="viewStart" />
+
+            <TextView
+                android:id="@+id/contact_tile_phone_type"
+                android:layout_width="0dip"
+                android:layout_height="wrap_content"
+                android:layout_weight="?attr/list_item_label_width_weight"
+                android:textSize="12sp"
+                android:ellipsize="marquee"
+                android:singleLine="true"
+                android:textAllCaps="true"
+                android:textColor="@color/dialtacts_secondary_text_color"
+                android:layout_marginLeft="8dip"
+                android:layout_marginStart="8dip"
+                android:gravity="end"
+                android:layout_gravity="bottom" />
+
+        </LinearLayout>
+
+        <View
+            android:id="@+id/contact_tile_horizontal_divider"
+            android:layout_width="match_parent"
+            android:layout_height="1px"
+            android:background="?android:attr/listDivider"
+            android:layout_below="@id/contact_tile_quick" />
+
+    </RelativeLayout>
+
+</view>
diff --git a/res/layout/phone_favorite_tile_view.xml b/res/layout/phone_favorite_tile_view.xml
new file mode 100644
index 0000000..f6e44d8
--- /dev/null
+++ b/res/layout/phone_favorite_tile_view.xml
@@ -0,0 +1,78 @@
+<?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.
+-->
+<view
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:background="@null"
+    android:paddingBottom="1dip"
+    android:paddingRight="1dip"
+    android:paddingEnd="1dip"
+    class="com.android.dialer.list.PhoneFavoriteTileView" >
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" >
+
+        <com.android.contacts.common.widget.LayoutSuppressingImageView
+            android:id="@+id/contact_tile_image"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:scaleType="centerCrop" />
+
+        <TextView
+            android:id="@+id/contact_tile_name"
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/contact_tile_shadowbox_height"
+            android:background="@color/contact_tile_shadow_box_color"
+            android:gravity="center_vertical"
+            android:textColor="@android:color/white"
+            android:singleLine="true"
+            android:textSize="16sp"
+            android:fadingEdge="horizontal"
+            android:fadingEdgeLength="3dip"
+            android:ellipsize="marquee"
+            android:layout_alignParentBottom="true"
+            android:paddingLeft="8dip"
+            android:paddingRight="47dip"
+            android:paddingStart="8dip"
+            android:paddingEnd="47dip"
+            android:textAlignment="viewStart" />
+
+        <View
+            android:id="@+id/contact_tile_push_state"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:focusable="true"
+            android:nextFocusRight="@+id/contact_tile_secondary_button"
+            android:background="?android:attr/selectableItemBackground" />
+
+        <ImageButton
+            android:id="@id/contact_tile_secondary_button"
+            android:src="@drawable/ic_contacts_holo_dark"
+            android:background="?android:attr/selectableItemBackground"
+            android:layout_height="@dimen/contact_tile_shadowbox_height"
+            android:layout_width="48dip"
+            android:paddingLeft="8dip"
+            android:paddingRight="8dip"
+            android:paddingStart="8dip"
+            android:paddingEnd="8dip"
+            android:layout_alignParentBottom="true"
+            android:layout_alignParentRight="true"
+            android:layout_alignParentEnd="true"
+            android:contentDescription="@string/description_view_contact_detail" />
+
+    </RelativeLayout>
+
+</view>
diff --git a/res/menu/call_log_options_new.xml b/res/menu/call_log_options_new.xml
index bf2973f..50b1cad 100644
--- a/res/menu/call_log_options_new.xml
+++ b/res/menu/call_log_options_new.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
+<!-- Copyright (C) 2013 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.
@@ -14,38 +14,6 @@
      limitations under the License.
 -->
 <menu xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item
-        android:id="@+id/show_all_calls"
-        android:title="@string/menu_show_all_calls"
-        android:showAsAction="never"
-        android:orderInCategory="1"/>
-
-    <item
-        android:id="@+id/show_voicemails_only"
-        android:title="@string/menu_show_voicemails_only"
-        android:showAsAction="never"
-        android:orderInCategory="1"/>
-
-    <item
-        android:id="@+id/show_missed_only"
-        android:title="@string/menu_show_missed_only"
-        android:showAsAction="never"
-        android:orderInCategory="1"/>
-
-    <item
-        android:id="@+id/show_outgoing_only"
-        android:title="@string/menu_show_outgoing_only"
-        android:showAsAction="never"
-        android:orderInCategory="1"/>
-
-    <item
-        android:id="@+id/show_incoming_only"
-        android:title="@string/menu_show_incoming_only"
-        android:showAsAction="never"
-        android:orderInCategory="1"/>
-
-
     <item
         android:id="@+id/delete_all"
         android:title="@string/recentCalls_deleteAll"
diff --git a/res/menu/dialtacts_options_new.xml b/res/menu/dialtacts_options_new.xml
index 8eaa915..92708fe 100644
--- a/res/menu/dialtacts_options_new.xml
+++ b/res/menu/dialtacts_options_new.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
+<!-- Copyright (C) 2013 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.
@@ -15,38 +15,19 @@
 -->
 <menu xmlns:android="http://schemas.android.com/apk/res/android">
     <item
-        android:id="@+id/search_on_action_bar"
-        android:title="@string/menu_search"
-        android:icon="@drawable/ic_dial_action_search"
-        android:showAsAction="ifRoom" />
-
-    <!-- This should come after the other menus in CallLog and Dialpad -->
+        android:id="@+id/menu_import_export"
+        android:title="@string/menu_import_export" />
+    <item
+        android:id="@+id/menu_clear_frequents"
+        android:title="@string/menu_clear_frequents" />
+    <item
+        android:id="@+id/add_contact"
+        android:title="@string/menu_newContact"/>
+    <item
+        android:id="@+id/menu_show_hide_all_contacts"
+        android:title="@string/show_all_contacts" />
     <item
         android:id="@+id/menu_call_settings"
         android:title="@string/call_settings"
-        android:showAsAction="withText"
         android:orderInCategory="2" />
-
-    <item
-        android:id="@+id/filter_option"
-        android:title="@string/menu_contacts_filter"
-        android:showAsAction="withText" />
-
-    <item
-        android:id="@+id/add_contact"
-        android:icon="@drawable/ic_add_contact_holo_dark"
-        android:title="@string/menu_newContact"
-        android:showAsAction="ifRoom" />
-
-    <!-- Ugly hack: empty item never clickable.
-         This is for forcing search icon on left even when there's a single item
-         in the bottom ActionBar.
-         We intentionally don't use android:icon to avoid other issues around item with
-         a null icon.
-
-         TODO: look for better idea. -->
-    <item
-        android:id="@+id/empty_right_menu_item"
-        android:actionLayout="@layout/empty2"
-        android:showAsAction="ifRoom" />
 </menu>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 1aa217f..672c970 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -17,7 +17,9 @@
 <resources>
 
     <!-- Secondary text color in the Phone app -->
+    <color name="dialtacts_primary_text_color">#111111</color>
     <color name="dialtacts_secondary_text_color">#888888</color>
+    <color name="dialpad_text_color">#ffffff</color>
     <color name="smartdial_name_primary_text_color">#0099cc</color>
     <color name="smartdial_name_highlighted_text_color">#39c9ff</color>
     <color name="smartdial_number_primary_text_color">#bbbbbb</color>
@@ -40,4 +42,17 @@
 
     <!-- Standard color for selected items. -->
     <color name="item_selected">#660099cc</color>
+
+    <!-- Background color of new dialer activity -->
+    <color name="background_dial_holo_light">#ffffff</color>
+
+    <!-- Background color of new dialpad -->
+    <color name="background_dialpad">#ee020709</color>
+
+    <!-- Primary color of dialpad text, including the call button -->
+    <color name="dialpad_primary_text_color">#0099cc</color>
+    <!-- Secondary color of dialpad text (mainly used for the letters corresponding to each digit
+        -->
+    <color name="dialpad_secondary_text_color">#888888</color>
+
 </resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 5d7412b..474f572 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -45,6 +45,7 @@
          LinearLayout (dialpad_fragment.xml), configuring dialpad screen's vertical
          ratio. -->
     <integer name="dialpad_layout_weight_digits">20</integer>
+    <integer name="dialpad_layout_weight_digits_new">15</integer>
     <integer name="dialpad_layout_weight_dialpad">65</integer>
     <integer name="dialpad_layout_weight_additional_buttons">15</integer>
 
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 9bf0ee8..9be7481 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -511,4 +511,31 @@
     <!-- Message displayed when there is no application available to handle the add contact menu option. [CHAR LIMIT=NONE] -->
     <string name="add_contact_not_available">Re-enable the People application to use this feature.</string>
 
+    <!-- Hint displayed in dialer search box when there is no query that is currently typed.
+         [CHAR LIMIT=25] -->
+    <string name="dialer_hint_find_contact">Type a name or phone</string>
+
+    <!-- Title for the call log tab containing the list of all voicemails and calls
+         [CHAR LIMIT=10] -->
+    <string name="call_log_all_title">All</string>
+
+    <!-- Title for the call log tab containing the list of all missed calls only
+         [CHAR LIMIT=10] -->
+    <string name="call_log_missed_title">Missed</string>
+
+    <!-- Title for the call log tab containing the list of all voicemails only
+         [CHAR LIMIT=10] -->
+    <string name="call_log_voicemail_title">Voicemail</string>
+
+    <!-- Text displayed when the list of missed calls is empty -->
+    <string name="recentMissed_empty">No recent missed calls.</string>
+
+    <!-- Text displayed when the list of voicemails is empty -->
+    <string name="recentVoicemails_empty">No recent voicemails.</string>
+
+    <!--  Menu option to enable all contacts to be displayed -->
+    <string name="show_all_contacts">Show all contacts</string>
+
+    <!--  Menu option to show favorite contacts only -->
+    <string name="show_favorites_only">Show favorites only</string>
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 099bfd5..cb36090 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -65,6 +65,61 @@
         <item name="favorites_padding_bottom">?android:attr/actionBarSize</item>
     </style>
 
+    <style name="NewDialtactsTheme"
+           parent="android:Theme.Holo.Light">
+        <item name="android:textColorPrimary">@color/dialtacts_primary_text_color</item>
+        <item name="android:textColorSecondary">@color/dialtacts_secondary_text_color</item>
+        <item name="android:windowActionBarOverlay">true</item>
+        <item name="android:actionBarStyle">@style/DialtactsActionBarStyleNew</item>
+        <item name="android:windowContentOverlay">@null</item>
+        <item name="android:windowBackground">@color/background_dial_holo_light</item>
+        <item name="android:listViewStyle">@style/ListViewStyle</item>
+        <item name="activated_background">@drawable/list_item_activated_background</item>
+        <item name="section_header_background">@drawable/list_title_holo</item>
+        <item name="list_section_header_height">32dip</item>
+        <item name="list_item_divider">?android:attr/listDivider</item>
+        <item name="list_item_padding_top">0dip</item>
+        <item name="list_item_padding_right">0dip</item>
+        <item name="list_item_padding_bottom">0dip</item>
+        <item name="list_item_padding_left">0dip</item>
+        <item name="list_item_gap_between_image_and_text">8dip</item>
+        <item name="list_item_gap_between_label_and_data">5dip</item>
+        <item name="list_item_presence_icon_margin">4dip</item>
+        <item name="list_item_presence_icon_size">16dip</item>
+        <item name="list_item_photo_size">@dimen/contact_browser_list_item_photo_size</item>
+        <item name="list_item_profile_photo_size">70dip</item>
+        <item name="list_item_prefix_highlight_color">@color/people_app_theme_color</item>
+        <item name="list_item_header_text_indent">8dip</item>
+        <item name="list_item_header_text_color">@color/people_app_theme_color</item>
+        <item name="list_item_header_text_size">14sp</item>
+        <item name="list_item_header_height">24dip</item>
+        <item name="list_item_header_underline_height">1dip</item>
+        <item name="list_item_header_underline_color">@color/people_app_theme_color</item>
+        <item name="list_item_data_width_weight">5</item>
+        <item name="list_item_label_width_weight">3</item>
+        <item name="contact_browser_list_padding_left">16dip</item>
+        <item name="contact_browser_list_padding_right">0dip</item>
+        <item name="contact_browser_background">@android:color/transparent</item>
+        <item name="list_item_text_indent">@dimen/contact_browser_list_item_text_indent</item>
+        <!-- CallLog -->
+        <item name="call_log_primary_text_color">#111111</item>
+        <item name="call_log_primary_background_color">#000000</item>
+        <item name="call_log_secondary_text_color">#555555</item>
+        <item name="call_log_secondary_background_color">#333333</item>
+        <item name="call_log_header_color">#33b5e5</item>
+        <!-- VoicemailStatus -->
+        <item name="call_log_voicemail_status_height">48dip</item>
+        <item name="call_log_voicemail_status_background_color">#262626</item>
+        <item name="call_log_voicemail_status_text_color">#888888</item>
+        <item name="call_log_voicemail_status_action_text_color">#33b5e5</item>
+            <!-- Favorites -->
+        <item name="favorites_padding_bottom">?android:attr/actionBarSize</item>
+    </style>
+
+    <style name="DialpadTheme" parent="DialtactsTheme">
+        <item name="android:textColorPrimary">#FFFFFF</item>
+    </style>
+
     <style name="CallDetailActivityTheme" parent="android:Theme.Holo">
         <item name="android:windowBackground">@android:color/black</item>
         <item name="android:gravity">top</item>
@@ -110,6 +165,11 @@
         <item name="android:background">#66000000</item>
     </style>
 
+    <style name="DialtactsActionBarStyleNew" parent="android:Widget.Holo.ActionBar">
+        <item name="android:backgroundSplit">@null</item>
+        <item name="android:displayOptions"></item>
+    </style>
+
     <style name="DialtactsActionBarStyle" parent="android:Widget.Holo.ActionBar">
         <item name="android:backgroundSplit">@null</item>
         <item name="android:backgroundStacked">@drawable/ab_stacked_opaque_dark_holo</item>
diff --git a/src/com/android/dialer/NeededForReflection.java b/src/com/android/dialer/NeededForReflection.java
new file mode 100644
index 0000000..e836908
--- /dev/null
+++ b/src/com/android/dialer/NeededForReflection.java
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+package com.android.dialer;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Denotes that the class, constructor, method or field is used for reflection and therefore cannot
+ * be removed by tools like ProGuard.
+ */
+@Retention(RetentionPolicy.CLASS)
+@Target({ElementType.TYPE, ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.FIELD})
+public @interface NeededForReflection{}
diff --git a/src/com/android/dialer/NewDialtactsActivity.java b/src/com/android/dialer/NewDialtactsActivity.java
index 584c951..66cbe85 100644
--- a/src/com/android/dialer/NewDialtactsActivity.java
+++ b/src/com/android/dialer/NewDialtactsActivity.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2013 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.
@@ -16,10 +16,9 @@
 
 package com.android.dialer;
 
-import android.app.ActionBar;
-import android.app.ActionBar.LayoutParams;
-import android.app.ActionBar.Tab;
-import android.app.ActionBar.TabListener;
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorListenerAdapter;
 import android.app.Activity;
 import android.app.backup.BackupManager;
 import android.app.Fragment;
@@ -33,26 +32,20 @@
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.preference.PreferenceManager;
 import android.provider.CallLog.Calls;
+import android.provider.ContactsContract;
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.Intents.UI;
-import android.support.v13.app.FragmentPagerAdapter;
-import android.support.v4.view.ViewPager;
-import android.support.v4.view.ViewPager.OnPageChangeListener;
+import android.provider.Settings;
 import android.text.TextUtils;
-import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.Menu;
-import android.view.MenuInflater;
 import android.view.MenuItem;
-import android.view.MenuItem.OnMenuItemClickListener;
 import android.view.View;
-import android.view.View.OnClickListener;
 import android.view.View.OnFocusChangeListener;
 import android.view.ViewConfiguration;
-import android.view.ViewGroup;
 import android.view.inputmethod.InputMethodManager;
+import android.widget.AbsListView.OnScrollListener;
 import android.widget.PopupMenu;
 import android.widget.SearchView;
 import android.widget.SearchView.OnCloseListener;
@@ -61,27 +54,30 @@
 
 import com.android.contacts.common.CallUtil;
 import com.android.contacts.common.activity.TransactionSafeActivity;
-import com.android.contacts.common.list.ContactListFilterController;
-import com.android.contacts.common.list.ContactListFilterController.ContactListFilterListener;
+import com.android.contacts.common.dialog.ClearFrequentsDialog;
+import com.android.contacts.common.interactions.ImportExportDialogFragment;
 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.AccountFilterUtil;
-import com.android.dialer.calllog.CallLogFragment;
-import com.android.dialer.dialpad.DialpadFragment;
+import com.android.dialer.calllog.NewCallLogActivity;
+import com.android.dialer.dialpad.NewDialpadFragment;
+import com.android.dialer.dialpad.SmartDialNameMatcher;
 import com.android.dialer.interactions.PhoneNumberInteraction;
-import com.android.dialer.list.PhoneFavoriteFragment;
-import com.android.dialer.util.OrientationUtil;
+import com.android.dialer.list.NewPhoneFavoriteFragment;
+import com.android.dialer.list.OnListFragmentScrolledListener;
+import com.android.dialer.list.SmartDialSearchFragment;
 import com.android.internal.telephony.ITelephony;
 
 /**
- * The dialer activity that has one tab with the virtual 12key
- * dialer, a tab with recent calls in it, a tab with the contacts and
- * a tab with the favorite. This is the container and the tabs are
- * embedded using intents.
  * The dialer tab's title is 'phone', a more common name (see strings.xml).
+ *
+ * TODO krelease: All classes currently prefixed with New will replace the original classes or
+ * be renamed more appropriately before shipping.
  */
-public class NewDialtactsActivity extends TransactionSafeActivity implements View.OnClickListener {
+public class NewDialtactsActivity extends TransactionSafeActivity implements View.OnClickListener,
+        NewDialpadFragment.OnDialpadQueryChangedListener, PopupMenu.OnMenuItemClickListener,
+        OnListFragmentScrolledListener,
+        NewPhoneFavoriteFragment.OnPhoneFavoriteFragmentStartedListener {
     private static final String TAG = "DialtactsActivity";
 
     public static final boolean DEBUG = false;
@@ -95,18 +91,16 @@
     private static final String CALL_ORIGIN_DIALTACTS =
             "com.android.dialer.DialtactsActivity";
 
+    private static final String TAG_DIALPAD_FRAGMENT = "dialpad";
+    private static final String TAG_REGULAR_SEARCH_FRAGMENT = "search";
+    private static final String TAG_SMARTDIAL_SEARCH_FRAGMENT = "smartdial";
+    private static final String TAG_FAVORITES_FRAGMENT = "favorites";
+
     /**
      * Just for backward compatibility. Should behave as same as {@link Intent#ACTION_DIAL}.
      */
     private static final String ACTION_TOUCH_DIALER = "com.android.phone.action.TOUCH_DIALER";
 
-    /** Used both by {@link ActionBar} and {@link ViewPagerAdapter} */
-    private static final int TAB_INDEX_DIALER = 0;
-    private static final int TAB_INDEX_CALL_LOG = 1;
-    private static final int TAB_INDEX_FAVORITES = 2;
-
-    private static final int TAB_INDEX_COUNT = 3;
-
     private SharedPreferences mPrefs;
 
     public static final String SHARED_PREFS_NAME = "com.android.dialer_preferences";
@@ -114,242 +108,38 @@
     /** Last manually selected tab index */
     private static final String PREF_LAST_MANUALLY_SELECTED_TAB =
             "DialtactsActivity_last_manually_selected_tab";
-    private static final int PREF_LAST_MANUALLY_SELECTED_TAB_DEFAULT = TAB_INDEX_DIALER;
 
     private static final int SUBACTIVITY_ACCOUNT_FILTER = 1;
 
-    public class ViewPagerAdapter extends FragmentPagerAdapter {
-        public ViewPagerAdapter(FragmentManager fm) {
-            super(fm);
-        }
-
-        @Override
-        public Fragment getItem(int position) {
-            switch (position) {
-                case TAB_INDEX_DIALER:
-                    return new DialpadFragment();
-                case TAB_INDEX_CALL_LOG:
-                    return new CallLogFragment();
-                case TAB_INDEX_FAVORITES:
-                    return new PhoneFavoriteFragment();
-            }
-            throw new IllegalStateException("No fragment at position " + position);
-        }
-
-        @Override
-        public void setPrimaryItem(ViewGroup container, int position, Object object) {
-            // The parent's setPrimaryItem() also calls setMenuVisibility(), so we want to know
-            // when it happens.
-            if (DEBUG) {
-                Log.d(TAG, "FragmentPagerAdapter#setPrimaryItem(), position: " + position);
-            }
-            super.setPrimaryItem(container, position, object);
-        }
-
-        @Override
-        public int getCount() {
-            return TAB_INDEX_COUNT;
-        }
-    }
-
-    /**
-     * True when the app detects user's drag event. This variable should not become true when
-     * mUserTabClick is true.
-     *
-     * During user's drag or tab click, we shouldn't show fake buttons but just show real
-     * ActionBar at the bottom of the screen, for transition animation.
-     */
-    boolean mDuringSwipe = false;
-    /**
-     * True when the app detects user's tab click (at the top of the screen). This variable should
-     * not become true when mDuringSwipe is true.
-     *
-     * During user's drag or tab click, we shouldn't show fake buttons but just show real
-     * ActionBar at the bottom of the screen, for transition animation.
-     */
-    boolean mUserTabClick = false;
-
-    private class PageChangeListener implements OnPageChangeListener {
-        private int mCurrentPosition = -1;
-        /**
-         * Used during page migration, to remember the next position {@link #onPageSelected(int)}
-         * specified.
-         */
-        private int mNextPosition = -1;
-
-        @Override
-        public void onPageScrolled(
-                int position, float positionOffset, int positionOffsetPixels) {
-        }
-
-        @Override
-        public void onPageSelected(int position) {
-            if (DEBUG) Log.d(TAG, "onPageSelected: position: " + position);
-            final ActionBar actionBar = getActionBar();
-            if (mDialpadFragment != null) {
-                if (mDuringSwipe && position == TAB_INDEX_DIALER) {
-                    // TODO: Figure out if we want this or not. Right now
-                    // - with this call, both fake buttons and real action bar overlap
-                    // - without this call, there's tiny flicker happening to search/menu buttons.
-                    // If we can reduce the flicker without this call, it would be much better.
-                    // updateFakeMenuButtonsVisibility(true);
-                }
-            }
-
-            if (mCurrentPosition == position) {
-                Log.w(TAG, "Previous position and next position became same (" + position + ")");
-            }
-
-            actionBar.selectTab(actionBar.getTabAt(position));
-            mNextPosition = position;
-        }
-
-        public void setCurrentPosition(int position) {
-            mCurrentPosition = position;
-        }
-
-        public int getCurrentPosition() {
-            return mCurrentPosition;
-        }
-
-        @Override
-        public void onPageScrollStateChanged(int state) {
-            switch (state) {
-                case ViewPager.SCROLL_STATE_IDLE: {
-                    if (mNextPosition == -1) {
-                        // This happens when the user drags the screen just after launching the
-                        // application, and settle down the same screen without actually swiping it.
-                        // At that moment mNextPosition is apparently -1 yet, and we expect it
-                        // being updated by onPageSelected(), which is *not* called if the user
-                        // settle down the exact same tab after the dragging.
-                        if (DEBUG) {
-                            Log.d(TAG, "Next position is not specified correctly. Use current tab ("
-                                    + mViewPager.getCurrentItem() + ")");
-                        }
-                        mNextPosition = mViewPager.getCurrentItem();
-                    }
-                    if (DEBUG) {
-                        Log.d(TAG, "onPageScrollStateChanged() with SCROLL_STATE_IDLE. "
-                                + "mCurrentPosition: " + mCurrentPosition
-                                + ", mNextPosition: " + mNextPosition);
-                    }
-                    // Interpret IDLE as the end of migration (both swipe and tab click)
-                    mDuringSwipe = false;
-                    mUserTabClick = false;
-
-                    updateFakeMenuButtonsVisibility(mNextPosition == TAB_INDEX_DIALER);
-                    sendFragmentVisibilityChange(mCurrentPosition, false);
-                    sendFragmentVisibilityChange(mNextPosition, true);
-
-                    invalidateOptionsMenu();
-
-                    mCurrentPosition = mNextPosition;
-                    break;
-                }
-                case ViewPager.SCROLL_STATE_DRAGGING: {
-                    if (DEBUG) Log.d(TAG, "onPageScrollStateChanged() with SCROLL_STATE_DRAGGING");
-                    mDuringSwipe = true;
-                    mUserTabClick = false;
-                    break;
-                }
-                case ViewPager.SCROLL_STATE_SETTLING: {
-                    if (DEBUG) Log.d(TAG, "onPageScrollStateChanged() with SCROLL_STATE_SETTLING");
-                    mDuringSwipe = true;
-                    mUserTabClick = false;
-                    break;
-                }
-                default:
-                    break;
-            }
-        }
-    }
-
     private String mFilterText;
 
-    /** Enables horizontal swipe between Fragments. */
-    private ViewPager mViewPager;
-    private final PageChangeListener mPageChangeListener = new PageChangeListener();
-    private DialpadFragment mDialpadFragment;
-    private CallLogFragment mCallLogFragment;
-    private PhoneFavoriteFragment mPhoneFavoriteFragment;
-
-    private View mSearchButton;
-    private View mMenuButton;
-
-    private final ContactListFilterListener mContactListFilterListener =
-            new ContactListFilterListener() {
-        @Override
-        public void onContactListFilterChanged() {
-            boolean doInvalidateOptionsMenu = false;
-
-            if (mPhoneFavoriteFragment != null && mPhoneFavoriteFragment.isAdded()) {
-                mPhoneFavoriteFragment.setFilter(mContactListFilterController.getFilter());
-                doInvalidateOptionsMenu = true;
-            }
-
-            if (mSearchFragment != null && mSearchFragment.isAdded()) {
-                mSearchFragment.setFilter(mContactListFilterController.getFilter());
-                doInvalidateOptionsMenu = true;
-            } else {
-                Log.w(TAG, "Search Fragment isn't available when ContactListFilter is changed");
-            }
-
-            if (doInvalidateOptionsMenu) {
-                invalidateOptionsMenu();
-            }
-        }
-    };
-
-    private final TabListener mTabListener = new TabListener() {
-        @Override
-        public void onTabUnselected(Tab tab, FragmentTransaction ft) {
-            if (DEBUG) Log.d(TAG, "onTabUnselected(). tab: " + tab);
-        }
-
-        @Override
-        public void onTabSelected(Tab tab, FragmentTransaction ft) {
-            if (DEBUG) {
-                Log.d(TAG, "onTabSelected(). tab: " + tab + ", mDuringSwipe: " + mDuringSwipe);
-            }
-            // When the user swipes the screen horizontally, this method will be called after
-            // ViewPager.SCROLL_STATE_DRAGGING and ViewPager.SCROLL_STATE_SETTLING events, while
-            // when the user clicks a tab at the ActionBar at the top, this will be called before
-            // them. This logic interprets the order difference as a difference of the user action.
-            if (!mDuringSwipe) {
-                if (DEBUG) {
-                    Log.d(TAG, "Tab select. from: " + mPageChangeListener.getCurrentPosition()
-                            + ", to: " + tab.getPosition());
-                }
-                if (mDialpadFragment != null) {
-                    updateFakeMenuButtonsVisibility(tab.getPosition() == TAB_INDEX_DIALER);
-                }
-                mUserTabClick = true;
-            }
-
-            if (mViewPager.getCurrentItem() != tab.getPosition()) {
-                mViewPager.setCurrentItem(tab.getPosition(), true);
-            }
-
-            // During the call, we don't remember the tab position.
-            if (mDialpadFragment == null || !mDialpadFragment.phoneIsInUse()) {
-                // Remember this tab index. This function is also called, if the tab is set
-                // automatically in which case the setter (setCurrentTab) has to set this to its old
-                // value afterwards
-                mLastManuallySelectedFragment = tab.getPosition();
-            }
-        }
-
-        @Override
-        public void onTabReselected(Tab tab, FragmentTransaction ft) {
-            if (DEBUG) Log.d(TAG, "onTabReselected");
-        }
-    };
+    /**
+     * The main fragment displaying the user's favorites and frequent contacts
+     */
+    private NewPhoneFavoriteFragment mPhoneFavoriteFragment;
 
     /**
-     * Fragment for searching phone numbers. Unlike the other Fragments, this doesn't correspond
-     * to tab but is shown by a search action.
+     * Fragment containing the dialpad that slides into view
      */
-    private PhoneNumberPickerFragment mSearchFragment;
+    private NewDialpadFragment mDialpadFragment;
+
+    /**
+     * Fragment for searching phone numbers using the alphanumeric keyboard.
+     */
+    private NewSearchFragment mRegularSearchFragment;
+
+    /**
+     * Fragment for searching phone numbers using the dialpad.
+     */
+    private SmartDialSearchFragment mSmartDialSearchFragment;
+
+    private View mMenuButton;
+    private View mCallHistoryButton;
+    private View mDialpadButton;
+
+    // Padding view used to shift the fragments up when the dialpad is shown.
+    private View mBottomPaddingView;
+
     /**
      * True when this Activity is in its search UI (with a {@link SearchView} and
      * {@link PhoneNumberPickerFragment}).
@@ -357,48 +147,12 @@
     private boolean mInSearchUi;
     private SearchView mSearchView;
 
-    private final OnClickListener mFilterOptionClickListener = new OnClickListener() {
-        @Override
-        public void onClick(View view) {
-            final PopupMenu popupMenu = new PopupMenu(NewDialtactsActivity.this, view);
-            final Menu menu = popupMenu.getMenu();
-            popupMenu.inflate(R.menu.dialtacts_search_options);
-            final MenuItem filterOptionMenuItem = menu.findItem(R.id.filter_option);
-            filterOptionMenuItem.setOnMenuItemClickListener(mFilterOptionsMenuItemClickListener);
-            final MenuItem addContactOptionMenuItem = menu.findItem(R.id.add_contact);
-            addContactOptionMenuItem.setIntent(
-                    new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI));
-            popupMenu.show();
-        }
-    };
-
     /**
      * The index of the Fragment (or, the tab) that has last been manually selected.
      * This value does not keep track of programmatically set Tabs (e.g. Call Log after a Call)
      */
     private int mLastManuallySelectedFragment;
 
-    private ContactListFilterController mContactListFilterController;
-    private OnMenuItemClickListener mFilterOptionsMenuItemClickListener =
-            new OnMenuItemClickListener() {
-        @Override
-        public boolean onMenuItemClick(MenuItem item) {
-            AccountFilterUtil.startAccountFilterActivityForResult(
-                    NewDialtactsActivity.this, SUBACTIVITY_ACCOUNT_FILTER,
-                    mContactListFilterController.getFilter());
-            return true;
-        }
-    };
-
-    private OnMenuItemClickListener mSearchMenuItemClickListener =
-            new OnMenuItemClickListener() {
-        @Override
-        public boolean onMenuItemClick(MenuItem item) {
-            enterSearchUi();
-            return true;
-        }
-    };
-
     /**
      * Listener used when one of phone numbers in search UI is selected. This will initiate a
      * phone call using the phone number.
@@ -410,7 +164,7 @@
                     // Specify call-origin so that users will see the previous tab instead of
                     // CallLog screen (search UI will be automatically exited).
                     PhoneNumberInteraction.startInteractionForPhoneCall(
-                            NewDialtactsActivity.this, dataUri, getCallOrigin());
+                        NewDialtactsActivity.this, dataUri, getCallOrigin());
                 }
 
                 @Override
@@ -441,14 +195,29 @@
 
                 @Override
                 public boolean onQueryTextChange(String newText) {
+                    final boolean smartDialSearch = isDialpadShowing();
+
                     // Show search result with non-empty text. Show a bare list otherwise.
-                    if (mSearchFragment != null) {
-                        mSearchFragment.setQueryString(newText, true);
+                    if (TextUtils.isEmpty(newText) && mInSearchUi) {
+                        exitSearchUi();
+                        return true;
+                    } else if (!TextUtils.isEmpty(newText) && !mInSearchUi) {
+                        enterSearchUi(smartDialSearch);
+                    }
+
+                    if (isDialpadShowing()) {
+                        mSmartDialSearchFragment.setQueryString(newText, false);
+                    } else {
+                        mRegularSearchFragment.setQueryString(newText, false);
                     }
                     return true;
                 }
     };
 
+    private boolean isDialpadShowing() {
+        return mDialpadFragment.isVisible();
+    }
+
     /**
      * Listener used to handle the "close" button on the right side of {@link SearchView}.
      * If some text is in the search view, this will clean it up. Otherwise this will exit
@@ -467,135 +236,132 @@
                 }
     };
 
-    private final View.OnLayoutChangeListener mFirstLayoutListener
-            = new View.OnLayoutChangeListener() {
-        @Override
-        public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
-                int oldTop, int oldRight, int oldBottom) {
-            v.removeOnLayoutChangeListener(this); // Unregister self.
-            addSearchFragment();
-        }
-    };
-
     @Override
-    protected void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
 
         final Intent intent = getIntent();
         fixIntent(intent);
 
-        setContentView(R.layout.dialtacts_activity);
+        setContentView(R.layout.new_dialtacts_activity);
 
-        mContactListFilterController = ContactListFilterController.getInstance(this);
-        mContactListFilterController.addListener(mContactListFilterListener);
+        getActionBar().hide();
 
-        findViewById(R.id.dialtacts_frame).addOnLayoutChangeListener(mFirstLayoutListener);
+        mPhoneFavoriteFragment = new NewPhoneFavoriteFragment();
+        mPhoneFavoriteFragment.setListener(mPhoneFavoriteListener);
 
-        mViewPager = (ViewPager) findViewById(R.id.pager);
-        mViewPager.setAdapter(new ViewPagerAdapter(getFragmentManager()));
-        mViewPager.setOnPageChangeListener(mPageChangeListener);
-        mViewPager.setOffscreenPageLimit(2);
+        mRegularSearchFragment = new NewSearchFragment();
+        mSmartDialSearchFragment = new SmartDialSearchFragment();
+        mDialpadFragment = new NewDialpadFragment();
 
-        // Do same width calculation as ActionBar does
-        DisplayMetrics dm = getResources().getDisplayMetrics();
-        int minCellSize = getResources().getDimensionPixelSize(R.dimen.fake_menu_button_min_width);
-        int cellCount = dm.widthPixels / minCellSize;
-        int fakeMenuItemWidth = dm.widthPixels / cellCount;
-        if (DEBUG) Log.d(TAG, "The size of fake menu buttons (in pixel): " + fakeMenuItemWidth);
+        // TODO krelease: load fragments on demand instead of creating all of them at run time
+        final FragmentTransaction ft = getFragmentManager().beginTransaction();
+        ft.add(R.id.dialtacts_frame, mPhoneFavoriteFragment, TAG_FAVORITES_FRAGMENT);
+        ft.add(R.id.dialtacts_frame, mRegularSearchFragment, TAG_REGULAR_SEARCH_FRAGMENT);
+        ft.add(R.id.dialtacts_frame, mSmartDialSearchFragment, TAG_SMARTDIAL_SEARCH_FRAGMENT);
+        ft.add(R.id.dialtacts_container, mDialpadFragment, TAG_DIALPAD_FRAGMENT);
+        ft.hide(mRegularSearchFragment);
+        ft.hide(mDialpadFragment);
+        ft.hide(mSmartDialSearchFragment);
+        ft.commit();
 
-        // Soft menu button should appear only when there's no hardware menu button.
-        mMenuButton = findViewById(R.id.overflow_menu);
-        if (mMenuButton != null) {
-            mMenuButton.setMinimumWidth(fakeMenuItemWidth);
-            if (ViewConfiguration.get(this).hasPermanentMenuKey()) {
-                // This is required for dialpad button's layout, so must not use GONE here.
-                mMenuButton.setVisibility(View.INVISIBLE);
-            } else {
-                mMenuButton.setOnClickListener(this);
-            }
-        }
-        mSearchButton = findViewById(R.id.searchButton);
-        if (mSearchButton != null) {
-            mSearchButton.setMinimumWidth(fakeMenuItemWidth);
-            mSearchButton.setOnClickListener(this);
-        }
-
-        // Setup the ActionBar tabs (the order matches the tab-index contants TAB_INDEX_*)
-        setupDialer();
-        setupCallLog();
-        setupFavorites();
-        getActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
-        getActionBar().setDisplayShowTitleEnabled(false);
-        getActionBar().setDisplayShowHomeEnabled(false);
+        mBottomPaddingView = findViewById(R.id.dialtacts_bottom_padding);
+        prepareSearchView();
 
         // Load the last manually loaded tab
         mPrefs = this.getSharedPreferences(SHARED_PREFS_NAME, Context.MODE_PRIVATE);
-        mLastManuallySelectedFragment = mPrefs.getInt(PREF_LAST_MANUALLY_SELECTED_TAB,
-                PREF_LAST_MANUALLY_SELECTED_TAB_DEFAULT);
-        if (mLastManuallySelectedFragment >= TAB_INDEX_COUNT) {
-            // Stored value may have exceeded the number of current tabs. Reset it.
-            mLastManuallySelectedFragment = PREF_LAST_MANUALLY_SELECTED_TAB_DEFAULT;
-        }
 
-        setCurrentTab(intent);
+        /*
+         * TODO krelease : Remember which fragment was last displayed, and then redisplay it as
+         * necessary. mLastManuallySelectedFragment = mPrefs.getInt(PREF_LAST_MANUALLY_SELECTED_TAB,
+         * PREF_LAST_MANUALLY_SELECTED_TAB_DEFAULT); if (mLastManuallySelectedFragment >=
+         * TAB_INDEX_COUNT) { // Stored value may have exceeded the number of current tabs. Reset
+         * it. mLastManuallySelectedFragment = PREF_LAST_MANUALLY_SELECTED_TAB_DEFAULT; }
+         */
 
         if (UI.FILTER_CONTACTS_ACTION.equals(intent.getAction())
-                && icicle == null) {
+                && savedInstanceState == null) {
             setupFilterText(intent);
         }
     }
 
     @Override
-    public void onStart() {
-        super.onStart();
-        if (mPhoneFavoriteFragment != null) {
-            mPhoneFavoriteFragment.setFilter(mContactListFilterController.getFilter());
-        }
-        if (mSearchFragment != null) {
-            mSearchFragment.setFilter(mContactListFilterController.getFilter());
+    protected void onResume() {
+        super.onResume();
+        final FragmentManager fm = getFragmentManager();
+        mPhoneFavoriteFragment = (NewPhoneFavoriteFragment) fm.findFragmentByTag(
+                TAG_FAVORITES_FRAGMENT);
+        mDialpadFragment = (NewDialpadFragment) fm.findFragmentByTag(TAG_DIALPAD_FRAGMENT);
+
+        mRegularSearchFragment = (NewSearchFragment) fm.findFragmentByTag(
+                TAG_REGULAR_SEARCH_FRAGMENT);
+        mRegularSearchFragment.setOnPhoneNumberPickerActionListener(
+                mPhoneNumberPickerActionListener);
+        if (!mRegularSearchFragment.isHidden()) {
+            final FragmentTransaction transaction = getFragmentManager().beginTransaction();
+            transaction.hide(mRegularSearchFragment);
+            transaction.commit();
         }
 
-        if (mDuringSwipe || mUserTabClick) {
-            if (DEBUG) Log.d(TAG, "reset buggy flag state..");
-            mDuringSwipe = false;
-            mUserTabClick = false;
-        }
-
-        final int currentPosition = mPageChangeListener.getCurrentPosition();
-        if (DEBUG) {
-            Log.d(TAG, "onStart(). current position: " + mPageChangeListener.getCurrentPosition()
-                    + ". Reset all menu visibility state.");
-        }
-        updateFakeMenuButtonsVisibility(currentPosition == TAB_INDEX_DIALER && !mInSearchUi);
-        for (int i = 0; i < TAB_INDEX_COUNT; i++) {
-            sendFragmentVisibilityChange(i, i == currentPosition);
+        mSmartDialSearchFragment = (SmartDialSearchFragment) fm.findFragmentByTag(
+                TAG_SMARTDIAL_SEARCH_FRAGMENT);
+        mSmartDialSearchFragment.setOnPhoneNumberPickerActionListener(
+                mPhoneNumberPickerActionListener);
+        if (!mSmartDialSearchFragment.isHidden()) {
+            final FragmentTransaction transaction = getFragmentManager().beginTransaction();
+            transaction.hide(mSmartDialSearchFragment);
+            transaction.commit();
         }
     }
 
     @Override
-    public void onDestroy() {
-        super.onDestroy();
-        mContactListFilterController.removeListener(mContactListFilterListener);
+    public boolean onMenuItemClick(MenuItem item) {
+        switch (item.getItemId()) {
+            case R.id.menu_import_export:
+                // We hard-code the "contactsAreAvailable" argument because doing it properly would
+                // involve querying a {@link ProviderStatusLoader}, which we don't want to do right
+                // now in Dialtacts for (potential) performance reasons. Compare with how it is
+                // done in {@link PeopleActivity}.
+                ImportExportDialogFragment.show(getFragmentManager(), true,
+                        DialtactsActivity.class);
+                return true;
+            case R.id.menu_clear_frequents:
+                ClearFrequentsDialog.show(getFragmentManager());
+                return true;
+            case R.id.add_contact:
+                try {
+                    startActivity(new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI));
+                } catch (ActivityNotFoundException e) {
+                    Toast toast = Toast.makeText(this, R.string.add_contact_not_available,
+                            Toast.LENGTH_SHORT);
+                    toast.show();
+                }
+                return true;
+            case R.id.menu_call_settings:
+                final Intent settingsIntent = DialtactsActivity.getCallSettingsIntent();
+                startActivity(settingsIntent);
+        }
+        return false;
     }
 
     @Override
     public void onClick(View view) {
         switch (view.getId()) {
-            case R.id.searchButton: {
-                enterSearchUi();
-                break;
-            }
             case R.id.overflow_menu: {
-                if (mDialpadFragment != null) {
-                    PopupMenu popup = mDialpadFragment.constructPopupMenu(view);
-                    if (popup != null) {
-                        popup.show();
-                    }
-                } else {
-                    Log.w(TAG, "DialpadFragment is null during onClick() event for " + view);
-                }
+                final PopupMenu popupMenu = new PopupMenu(NewDialtactsActivity.this, view);
+                final Menu menu = popupMenu.getMenu();
+                popupMenu.inflate(R.menu.dialtacts_options_new);
+                popupMenu.setOnMenuItemClickListener(this);
+                popupMenu.show();
                 break;
             }
+            case R.id.dialpad_button:
+                showDialpadFragment();
+                break;
+            case R.id.call_history_button:
+                final Intent intent = new Intent(this, NewCallLogActivity.class);
+                startActivity(intent);
+                break;
             default: {
                 Log.wtf(TAG, "Unexpected onClick event from " + view);
                 break;
@@ -603,33 +369,22 @@
         }
     }
 
-    /**
-     * Add search fragment.  Note this is called during onLayout, so there's some restrictions,
-     * such as executePendingTransaction can't be used in it.
-     */
-    private void addSearchFragment() {
-        // In order to take full advantage of "fragment deferred start", we need to create the
-        // search fragment after all other fragments are created.
-        // The other fragments are created by the ViewPager on the first onMeasure().
-        // We use the first onLayout call, which is after onMeasure().
-
-        // Just return if the fragment is already created, which happens after configuration
-        // changes.
-        if (mSearchFragment != null) return;
-
+    private void showDialpadFragment() {
         final FragmentTransaction ft = getFragmentManager().beginTransaction();
-        final Fragment searchFragment = new PhoneNumberPickerFragment();
+        ft.setCustomAnimations(R.anim.slide_in, 0);
+        ft.show(mDialpadFragment);
+        ft.commit();
+    }
 
-        searchFragment.setUserVisibleHint(false);
-        ft.add(R.id.dialtacts_frame, searchFragment);
-        ft.hide(searchFragment);
-        ft.commitAllowingStateLoss();
+    private void hideDialpadFragment() {
+        final FragmentTransaction ft = getFragmentManager().beginTransaction();
+        ft.setCustomAnimations(0, R.anim.slide_out);
+        ft.hide(mDialpadFragment);
+        ft.commit();
     }
 
     private void prepareSearchView() {
-        final View searchViewLayout =
-                getLayoutInflater().inflate(R.layout.dialtacts_custom_action_bar, null);
-        mSearchView = (SearchView) searchViewLayout.findViewById(R.id.search_view);
+        mSearchView = (SearchView) findViewById(R.id.search_view);
         mSearchView.setOnQueryTextListener(mPhoneSearchQueryTextListener);
         mSearchView.setOnCloseListener(mPhoneSearchCloseListener);
         // Since we're using a custom layout for showing SearchView instead of letting the
@@ -639,8 +394,9 @@
         // - it should not be iconified at this time
         // See also comments for onActionViewExpanded()/onActionViewCollapsed()
         mSearchView.setIconifiedByDefault(true);
-        mSearchView.setQueryHint(getString(R.string.hint_findContacts));
+        mSearchView.setQueryHint(getString(R.string.dialer_hint_find_contact));
         mSearchView.setIconified(false);
+        mSearchView.clearFocus();
         mSearchView.setOnQueryTextFocusChangeListener(new OnFocusChangeListener() {
             @Override
             public void onFocusChange(View view, boolean hasFocus) {
@@ -649,69 +405,87 @@
                 }
             }
         });
-
-        if (!ViewConfiguration.get(this).hasPermanentMenuKey()) {
-            // Filter option menu should be shown on the right side of SearchView.
-            final View filterOptionView = searchViewLayout.findViewById(R.id.search_option);
-            filterOptionView.setVisibility(View.VISIBLE);
-            filterOptionView.setOnClickListener(mFilterOptionClickListener);
-        }
-
-        getActionBar().setCustomView(searchViewLayout,
-                new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
     }
 
-    @Override
-    public void onAttachFragment(Fragment fragment) {
-        // This method can be called before onCreate(), at which point we cannot rely on ViewPager.
-        // In that case, we will setup the "current position" soon after the ViewPager is ready.
-        final int currentPosition = mViewPager != null ? mViewPager.getCurrentItem() : -1;
+    private void hideDialpadFragmentIfNecessary() {
+        if (mDialpadFragment.isVisible()) {
+            hideDialpadFragment();
+        }
+    }
 
-        if (fragment instanceof DialpadFragment) {
-            mDialpadFragment = (DialpadFragment) fragment;
-        } else if (fragment instanceof CallLogFragment) {
-            mCallLogFragment = (CallLogFragment) fragment;
-        } else if (fragment instanceof PhoneFavoriteFragment) {
-            mPhoneFavoriteFragment = (PhoneFavoriteFragment) fragment;
-            mPhoneFavoriteFragment.setListener(mPhoneFavoriteListener);
-            if (mContactListFilterController != null
-                    && mContactListFilterController.getFilter() != null) {
-                mPhoneFavoriteFragment.setFilter(mContactListFilterController.getFilter());
-            }
-        } else if (fragment instanceof PhoneNumberPickerFragment) {
-            mSearchFragment = (PhoneNumberPickerFragment) fragment;
-            mSearchFragment.setOnPhoneNumberPickerActionListener(mPhoneNumberPickerActionListener);
-            mSearchFragment.setQuickContactEnabled(true);
-            mSearchFragment.setDarkTheme(true);
-            mSearchFragment.setPhotoPosition(ContactListItemView.getDefaultPhotoPosition(
-                    true /* opposite */));
-            mSearchFragment.setUseCallableUri(true);
-            if (mContactListFilterController != null
-                    && mContactListFilterController.getFilter() != null) {
-                mSearchFragment.setFilter(mContactListFilterController.getFilter());
-            }
-            // Here we assume that we're not on the search mode, so let's hide the fragment.
-            //
-            // We get here either when the fragment is created (normal case), or after configuration
-            // changes.  In the former case, we're not in search mode because we can only
-            // enter search mode if the fragment is created.  (see enterSearchUi())
-            // In the latter case we're not in search mode either because we don't retain
-            // mInSearchUi -- ideally we should but at this point it's not supported.
-            mSearchFragment.setUserVisibleHint(false);
-            // After configuration changes fragments will forget their "hidden" state, so make
-            // sure to hide it.
-            if (!mSearchFragment.isHidden()) {
-                final FragmentTransaction transaction = getFragmentManager().beginTransaction();
-                transaction.hide(mSearchFragment);
-                transaction.commitAllowingStateLoss();
+    final AnimatorListener mHideListener = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            mSearchView.setVisibility(View.GONE);
+        }
+    };
+
+    public void hideSearchBar() {
+        mSearchView.animate().cancel();
+        mSearchView.setAlpha(1);
+        mSearchView.setTranslationY(0);
+        mSearchView.animate().withLayer().alpha(0).translationY(-mSearchView.getHeight()).
+                setDuration(200).setListener(mHideListener);
+
+        mPhoneFavoriteFragment.getView().animate().withLayer()
+                .translationY(-mSearchView.getHeight()).setDuration(200).setListener(
+                    new AnimatorListenerAdapter() {
+                    @Override
+                        public void onAnimationEnd(Animator animation) {
+                            mBottomPaddingView.setVisibility(View.VISIBLE);
+                            mPhoneFavoriteFragment.getView().setTranslationY(0);
+                        }
+                    });
+    }
+
+    public void showSearchBar() {
+        mSearchView.animate().cancel();
+        mSearchView.setAlpha(0);
+        mSearchView.setTranslationY(-mSearchView.getHeight());
+        mSearchView.animate().withLayer().alpha(1).translationY(0).setDuration(200)
+                .setListener(new AnimatorListenerAdapter() {
+                        @Override
+                        public void onAnimationStart(Animator animation) {
+                            mSearchView.setVisibility(View.VISIBLE);
+                        }
+                });
+
+        mPhoneFavoriteFragment.getView().setTranslationY(-mSearchView.getHeight());
+        mPhoneFavoriteFragment.getView().animate().withLayer().translationY(0).setDuration(200)
+                .setListener(
+                        new AnimatorListenerAdapter() {
+                                @Override
+                                public void onAnimationStart(Animator animation) {
+                                    mBottomPaddingView.setVisibility(View.GONE);
+                                }
+                        });
+    }
+
+
+    public void setupFakeActionBarItems() {
+        mMenuButton = findViewById(R.id.overflow_menu);
+        if (mMenuButton != null) {
+            // mMenuButton.setMinimumWidth(fakeMenuItemWidth);
+            if (ViewConfiguration.get(this).hasPermanentMenuKey()) {
+                // This is required for dialpad button's layout, so must not use GONE here.
+                mMenuButton.setVisibility(View.INVISIBLE);
+            } else {
+                mMenuButton.setOnClickListener(this);
             }
         }
+
+        mCallHistoryButton = findViewById(R.id.call_history_button);
+        // mCallHistoryButton.setMinimumWidth(fakeMenuItemWidth);
+        mCallHistoryButton.setOnClickListener(this);
+
+        mDialpadButton = findViewById(R.id.dialpad_button);
+        // DialpadButton.setMinimumWidth(fakeMenuItemWidth);
+        mDialpadButton.setOnClickListener(this);
     }
 
     @Override
     protected void onPause() {
         super.onPause();
-
         mPrefs.edit().putInt(PREF_LAST_MANUALLY_SELECTED_TAB, mLastManuallySelectedFragment)
                 .apply();
         requestBackup();
@@ -733,30 +507,6 @@
         }
     }
 
-    private void setupDialer() {
-        final Tab tab = getActionBar().newTab();
-        tab.setContentDescription(R.string.dialerIconLabel);
-        tab.setTabListener(mTabListener);
-        tab.setIcon(R.drawable.ic_tab_dialer);
-        getActionBar().addTab(tab);
-    }
-
-    private void setupCallLog() {
-        final Tab tab = getActionBar().newTab();
-        tab.setContentDescription(R.string.recentCallsIconLabel);
-        tab.setIcon(R.drawable.ic_tab_recent);
-        tab.setTabListener(mTabListener);
-        getActionBar().addTab(tab);
-    }
-
-    private void setupFavorites() {
-        final Tab tab = getActionBar().newTab();
-        tab.setContentDescription(R.string.contactsFavoritesLabel);
-        tab.setIcon(R.drawable.ic_tab_all);
-        tab.setTabListener(mTabListener);
-        getActionBar().addTab(tab);
-    }
-
     /**
      * Returns true if the intent is due to hitting the green send key (hardware call button:
      * KEYCODE_CALL) while in a call.
@@ -765,8 +515,7 @@
      * @param recentCallsRequest true if the intent is requesting to view recent calls
      * @return true if the intent is due to hitting the green send key while in a call
      */
-    private boolean isSendKeyWhileInCall(final Intent intent,
-            final boolean recentCallsRequest) {
+    private boolean isSendKeyWhileInCall(Intent intent, boolean recentCallsRequest) {
         // If there is a call in progress go to the call screen
         if (recentCallsRequest) {
             final boolean callKey = intent.getBooleanExtra("call_key", false);
@@ -789,7 +538,10 @@
      *
      * @param intent Intent that contains information about which tab should be selected
      */
-    private void setCurrentTab(Intent intent) {
+    private void displayFragment(Intent intent) {
+        // TODO krelease: Make navigation via intent work by displaying the correct fragment
+        // as appropriate.
+
         // If we got here by hitting send and we're in call forward along to the in-call activity
         boolean recentCallsRequest = Calls.CONTENT_TYPE.equals(intent.resolveType(
             getContentResolver()));
@@ -797,61 +549,30 @@
             finish();
             return;
         }
-
-        // Remember the old manually selected tab index so that it can be restored if it is
-        // overwritten by one of the programmatic tab selections
-        final int savedTabIndex = mLastManuallySelectedFragment;
-
-        final int tabIndex;
-        if ((mDialpadFragment != null && mDialpadFragment.phoneIsInUse())
-                || isDialIntent(intent)) {
-            tabIndex = TAB_INDEX_DIALER;
-        } else if (recentCallsRequest) {
-            tabIndex = TAB_INDEX_CALL_LOG;
-        } else {
-            tabIndex = mLastManuallySelectedFragment;
-        }
-
-        final int previousItemIndex = mViewPager.getCurrentItem();
-        mViewPager.setCurrentItem(tabIndex, false /* smoothScroll */);
-        if (previousItemIndex != tabIndex) {
-            sendFragmentVisibilityChange(previousItemIndex, false /* not visible */ );
-        }
-        mPageChangeListener.setCurrentPosition(tabIndex);
-        sendFragmentVisibilityChange(tabIndex, true /* visible */ );
-
-        // Restore to the previous manual selection
-        mLastManuallySelectedFragment = savedTabIndex;
-        mDuringSwipe = false;
-        mUserTabClick = false;
     }
 
     @Override
     public void onNewIntent(Intent newIntent) {
         setIntent(newIntent);
         fixIntent(newIntent);
-        setCurrentTab(newIntent);
+        displayFragment(newIntent);
         final String action = newIntent.getAction();
         if (UI.FILTER_CONTACTS_ACTION.equals(action)) {
             setupFilterText(newIntent);
         }
-        if (mInSearchUi || (mSearchFragment != null && mSearchFragment.isVisible())) {
+        if (mInSearchUi || (mRegularSearchFragment != null && mRegularSearchFragment.isVisible())) {
             exitSearchUi();
         }
 
-        if (mViewPager.getCurrentItem() == TAB_INDEX_DIALER) {
-            if (mDialpadFragment != null) {
-                mDialpadFragment.setStartedFromNewIntent(true);
-            } else {
-                Log.e(TAG, "DialpadFragment isn't ready yet when the tab is already selected.");
-            }
-        } else if (mViewPager.getCurrentItem() == TAB_INDEX_CALL_LOG) {
-            if (mCallLogFragment != null) {
-                mCallLogFragment.configureScreenFromIntent(newIntent);
-            } else {
-                Log.e(TAG, "CallLogFragment isn't ready yet when the tab is already selected.");
-            }
-        }
+        // TODO krelease: Handle onNewIntent for all other fragments
+        /*
+         *if (mViewPager.getCurrentItem() == TAB_INDEX_DIALER) { if (mDialpadFragment != null) {
+         * mDialpadFragment.setStartedFromNewIntent(true); } else { Log.e(TAG,
+         * "DialpadFragment isn't ready yet when the tab is already selected."); } } else if
+         * (mViewPager.getCurrentItem() == TAB_INDEX_CALL_LOG) { if (mCallLogFragment != null) {
+         * mCallLogFragment.configureScreenFromIntent(newIntent); } else { Log.e(TAG,
+         * "CallLogFragment isn't ready yet when the tab is already selected."); } }
+         */
         invalidateOptionsMenu();
     }
 
@@ -911,28 +632,12 @@
         }
     }
 
-    @Override
-    public void onBackPressed() {
-        if (mInSearchUi) {
-            // We should let the user go back to usual screens with tabs.
-            exitSearchUi();
-        } else if (isTaskRoot()) {
-            // Instead of stopping, simply push this to the back of the stack.
-            // This is only done when running at the top of the stack;
-            // otherwise, we have been launched by someone else so need to
-            // allow the user to go back to the caller.
-            moveTaskToBack(false);
-        } else {
-            super.onBackPressed();
-        }
-    }
-
-    private final PhoneFavoriteFragment.Listener mPhoneFavoriteListener =
-            new PhoneFavoriteFragment.Listener() {
+    private final NewPhoneFavoriteFragment.Listener mPhoneFavoriteListener =
+            new NewPhoneFavoriteFragment.Listener() {
         @Override
         public void onContactSelected(Uri contactUri) {
             PhoneNumberInteraction.startInteractionForPhoneCall(
-                    NewDialtactsActivity.this, contactUri, getCallOrigin());
+                        NewDialtactsActivity.this, contactUri, getCallOrigin());
         }
 
         @Override
@@ -942,151 +647,14 @@
         }
     };
 
-    @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        MenuInflater inflater = getMenuInflater();
-        inflater.inflate(R.menu.dialtacts_options, menu);
-
-        // set up intents and onClick listeners
-        final MenuItem callSettingsMenuItem = menu.findItem(R.id.menu_call_settings);
-        final MenuItem searchMenuItem = menu.findItem(R.id.search_on_action_bar);
-        final MenuItem filterOptionMenuItem = menu.findItem(R.id.filter_option);
-
-        callSettingsMenuItem.setIntent(DialtactsActivity.getCallSettingsIntent());
-        searchMenuItem.setOnMenuItemClickListener(mSearchMenuItemClickListener);
-        filterOptionMenuItem.setOnMenuItemClickListener(mFilterOptionsMenuItemClickListener);
-
-        return true;
-    }
-
-    @Override
-    public boolean onPrepareOptionsMenu(Menu menu) {
-        if (mInSearchUi) {
-            prepareOptionsMenuInSearchMode(menu);
-        } else {
-            // get reference to the currently selected tab
-            final Tab tab = getActionBar().getSelectedTab();
-            if (tab != null) {
-                switch(tab.getPosition()) {
-                    case TAB_INDEX_DIALER:
-                        prepareOptionsMenuForDialerTab(menu);
-                        break;
-                    case TAB_INDEX_CALL_LOG:
-                        prepareOptionsMenuForCallLogTab(menu);
-                        break;
-                    case TAB_INDEX_FAVORITES:
-                        prepareOptionsMenuForFavoritesTab(menu);
-                        break;
-                }
-            }
-        }
-        return true;
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        switch (item.getItemId()) {
-            case R.id.add_contact:
-                try {
-                    startActivity(new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI));
-                } catch (ActivityNotFoundException e) {
-                    Toast toast = Toast.makeText(this, R.string.add_contact_not_available,
-                            Toast.LENGTH_SHORT);
-                    toast.show();
-                }
-                return true;
-        }
-        return super.onOptionsItemSelected(item);
-    }
-
-    private void prepareOptionsMenuInSearchMode(Menu menu) {
-        // get references to menu items
-        final MenuItem searchMenuItem = menu.findItem(R.id.search_on_action_bar);
-        final MenuItem filterOptionMenuItem = menu.findItem(R.id.filter_option);
-        final MenuItem addContactOptionMenuItem = menu.findItem(R.id.add_contact);
-        final MenuItem callSettingsMenuItem = menu.findItem(R.id.menu_call_settings);
-        final MenuItem emptyRightMenuItem = menu.findItem(R.id.empty_right_menu_item);
-
-        // prepare the menu items
-        searchMenuItem.setVisible(false);
-        filterOptionMenuItem.setVisible(ViewConfiguration.get(this).hasPermanentMenuKey());
-        addContactOptionMenuItem.setVisible(false);
-        callSettingsMenuItem.setVisible(false);
-        emptyRightMenuItem.setVisible(false);
-    }
-
-    private void prepareOptionsMenuForDialerTab(Menu menu) {
-        if (DEBUG) {
-            Log.d(TAG, "onPrepareOptionsMenu(dialer). swipe: " + mDuringSwipe
-                    + ", user tab click: " + mUserTabClick);
-        }
-
-        // get references to menu items
-        final MenuItem searchMenuItem = menu.findItem(R.id.search_on_action_bar);
-        final MenuItem filterOptionMenuItem = menu.findItem(R.id.filter_option);
-        final MenuItem addContactOptionMenuItem = menu.findItem(R.id.add_contact);
-        final MenuItem callSettingsMenuItem = menu.findItem(R.id.menu_call_settings);
-        final MenuItem emptyRightMenuItem = menu.findItem(R.id.empty_right_menu_item);
-
-        // prepare the menu items
-        filterOptionMenuItem.setVisible(false);
-        addContactOptionMenuItem.setVisible(false);
-        if (mDuringSwipe || mUserTabClick) {
-            // During horizontal movement, the real ActionBar menu items are shown
-            searchMenuItem.setVisible(true);
-            callSettingsMenuItem.setVisible(true);
-            // When there is a permanent menu key, there is no overflow icon on the right of
-            // the action bar which would force the search menu item (if it is visible) to the
-            // left.  This is the purpose of showing the emptyRightMenuItem.
-            emptyRightMenuItem.setVisible(ViewConfiguration.get(this).hasPermanentMenuKey());
-        } else {
-            // This is when the user is looking at the dialer pad.  In this case, the real
-            // ActionBar is hidden and fake menu items are shown.
-            // Except in landscape, in which case the real search menu item is shown.
-            searchMenuItem.setVisible(OrientationUtil.isLandscape(this));
-            // If a permanent menu key is available, then we need to show the call settings item
-            // so that the call settings item can be invoked by the permanent menu key.
-            callSettingsMenuItem.setVisible(ViewConfiguration.get(this).hasPermanentMenuKey());
-            emptyRightMenuItem.setVisible(false);
-        }
-    }
-
-    private void prepareOptionsMenuForCallLogTab(Menu menu) {
-        // get references to menu items
-        final MenuItem searchMenuItem = menu.findItem(R.id.search_on_action_bar);
-        final MenuItem filterOptionMenuItem = menu.findItem(R.id.filter_option);
-        final MenuItem addContactOptionMenuItem = menu.findItem(R.id.add_contact);
-        final MenuItem callSettingsMenuItem = menu.findItem(R.id.menu_call_settings);
-        final MenuItem emptyRightMenuItem = menu.findItem(R.id.empty_right_menu_item);
-
-        // prepare the menu items
-        searchMenuItem.setVisible(true);
-        filterOptionMenuItem.setVisible(false);
-        addContactOptionMenuItem.setVisible(false);
-        callSettingsMenuItem.setVisible(true);
-        emptyRightMenuItem.setVisible(ViewConfiguration.get(this).hasPermanentMenuKey());
-    }
-
-    private void prepareOptionsMenuForFavoritesTab(Menu menu) {
-        // get references to menu items
-        final MenuItem searchMenuItem = menu.findItem(R.id.search_on_action_bar);
-        final MenuItem filterOptionMenuItem = menu.findItem(R.id.filter_option);
-        final MenuItem addContactOptionMenuItem = menu.findItem(R.id.add_contact);
-        final MenuItem callSettingsMenuItem = menu.findItem(R.id.menu_call_settings);
-        final MenuItem emptyRightMenuItem = menu.findItem(R.id.empty_right_menu_item);
-
-        // prepare the menu items
-        searchMenuItem.setVisible(true);
-        filterOptionMenuItem.setVisible(true);
-        addContactOptionMenuItem.setVisible(true);
-        callSettingsMenuItem.setVisible(true);
-        emptyRightMenuItem.setVisible(false);
-    }
+    /* TODO krelease: This is only relevant for phones that have a hard button search key (i.e.
+     * Nexus S). Supporting it is a little more tricky because of the dialpad fragment might
+     * be showing when the search key is pressed so there is more state management involved.
 
     @Override
     public void startSearch(String initialQuery, boolean selectInitialQuery,
             Bundle appSearchData, boolean globalSearch) {
-        if (mSearchFragment != null && mSearchFragment.isAdded() && !globalSearch) {
+        if (mRegularSearchFragment != null && mRegularSearchFragment.isAdded() && !globalSearch) {
             if (mInSearchUi) {
                 if (mSearchView.hasFocus()) {
                     showInputMethod(mSearchView.findFocus());
@@ -1099,173 +667,52 @@
         } else {
             super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch);
         }
-    }
-
-    /**
-     * Hides every tab and shows search UI for phone lookup.
-     */
-    private void enterSearchUi() {
-        if (mSearchFragment == null) {
-            // We add the search fragment dynamically in the first onLayoutChange() and
-            // mSearchFragment is set sometime later when the fragment transaction is actually
-            // executed, which means there's a window when users are able to hit the (physical)
-            // search key but mSearchFragment is still null.
-            // It's quite hard to handle this case right, so let's just ignore the search key
-            // in this case.  Users can just hit it again and it will work this time.
-            return;
-        }
-        if (mSearchView == null) {
-            prepareSearchView();
-        }
-
-        final ActionBar actionBar = getActionBar();
-
-        final Tab tab = actionBar.getSelectedTab();
-
-        // User can search during the call, but we don't want to remember the status.
-        if (tab != null && (mDialpadFragment == null ||
-                        !mDialpadFragment.phoneIsInUse())) {
-            mLastManuallySelectedFragment = tab.getPosition();
-        }
-
-        mSearchView.setQuery(null, true);
-
-        actionBar.setDisplayShowCustomEnabled(true);
-        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
-        actionBar.setDisplayShowHomeEnabled(true);
-        actionBar.setDisplayHomeAsUpEnabled(true);
-
-        updateFakeMenuButtonsVisibility(false);
-
-        for (int i = 0; i < TAB_INDEX_COUNT; i++) {
-            sendFragmentVisibilityChange(i, false /* not visible */ );
-        }
-
-        // Show the search fragment and hide everything else.
-        mSearchFragment.setUserVisibleHint(true);
-        final FragmentTransaction transaction = getFragmentManager().beginTransaction();
-        transaction.show(mSearchFragment);
-        transaction.commitAllowingStateLoss();
-        mViewPager.setVisibility(View.GONE);
-
-        // We need to call this and onActionViewCollapsed() manually, since we are using a custom
-        // layout instead of asking the search menu item to take care of SearchView.
-        mSearchView.onActionViewExpanded();
-        mInSearchUi = true;
-    }
+    }*/
 
     private void showInputMethod(View view) {
-        InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
+        final InputMethodManager imm = (InputMethodManager) getSystemService(
+                Context.INPUT_METHOD_SERVICE);
         if (imm != null) {
-            if (!imm.showSoftInput(view, 0)) {
-                Log.w(TAG, "Failed to show soft input method.");
-            }
+            imm.showSoftInput(view, 0);
         }
     }
 
     private void hideInputMethod(View view) {
-        InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
+        final InputMethodManager imm = (InputMethodManager) getSystemService(
+                Context.INPUT_METHOD_SERVICE);
         if (imm != null && view != null) {
             imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
         }
     }
 
     /**
-     * Goes back to usual Phone UI with tags. Previously selected Tag and associated Fragment
-     * should be automatically focused again.
+     * Shows the search fragment
      */
-    private void exitSearchUi() {
-        final ActionBar actionBar = getActionBar();
-
-        // Hide the search fragment, if exists.
-        if (mSearchFragment != null) {
-            mSearchFragment.setUserVisibleHint(false);
-
-            final FragmentTransaction transaction = getFragmentManager().beginTransaction();
-            transaction.hide(mSearchFragment);
-            transaction.commitAllowingStateLoss();
+    private void enterSearchUi(boolean smartDialSearch) {
+        final FragmentTransaction transaction = getFragmentManager().beginTransaction();
+        transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
+        transaction.hide(mPhoneFavoriteFragment);
+        if (smartDialSearch) {
+            transaction.show(mSmartDialSearchFragment);
+        } else {
+            transaction.show(mRegularSearchFragment);
         }
+        transaction.commit();
 
-        // We want to hide SearchView and show Tabs. Also focus on previously selected one.
-        actionBar.setDisplayShowCustomEnabled(false);
-        actionBar.setDisplayShowHomeEnabled(false);
-        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
-
-        for (int i = 0; i < TAB_INDEX_COUNT; i++) {
-            sendFragmentVisibilityChange(i, i == mViewPager.getCurrentItem());
-        }
-
-        // Before exiting the search screen, reset swipe state.
-        mDuringSwipe = false;
-        mUserTabClick = false;
-
-        mViewPager.setVisibility(View.VISIBLE);
-
-        hideInputMethod(getCurrentFocus());
-
-        // Request to update option menu.
-        invalidateOptionsMenu();
-
-        // See comments in onActionViewExpanded()
-        mSearchView.onActionViewCollapsed();
-        mInSearchUi = false;
-    }
-
-    private Fragment getFragmentAt(int position) {
-        switch (position) {
-            case TAB_INDEX_DIALER:
-                return mDialpadFragment;
-            case TAB_INDEX_CALL_LOG:
-                return mCallLogFragment;
-            case TAB_INDEX_FAVORITES:
-                return mPhoneFavoriteFragment;
-            default:
-                throw new IllegalStateException("Unknown fragment index: " + position);
-        }
-    }
-
-    private void sendFragmentVisibilityChange(int position, boolean visibility) {
-        if (DEBUG) {
-            Log.d(TAG, "sendFragmentVisibiltyChange(). position: " + position
-                    + ", visibility: " + visibility);
-        }
-        // Position can be -1 initially. See PageChangeListener.
-        if (position >= 0) {
-            final Fragment fragment = getFragmentAt(position);
-            if (fragment != null) {
-                fragment.setMenuVisibility(visibility);
-                fragment.setUserVisibleHint(visibility);
-            }
-        }
+        mInSearchUi = true;
     }
 
     /**
-     * Update visibility of the search button and menu button at the bottom.
-     * They should be invisible when bottom ActionBar's real items are available, and be visible
-     * otherwise.
-     *
-     * @param visible True when visible.
+     * Hides the search fragment
      */
-    private void updateFakeMenuButtonsVisibility(boolean visible) {
-        // Note: Landscape mode does not have the fake menu and search buttons.
-        if (DEBUG) {
-            Log.d(TAG, "updateFakeMenuButtonVisibility(" + visible + ")");
-        }
-
-        if (mSearchButton != null) {
-            if (visible) {
-                mSearchButton.setVisibility(View.VISIBLE);
-            } else {
-                mSearchButton.setVisibility(View.INVISIBLE);
-            }
-        }
-        if (mMenuButton != null) {
-            if (visible && !ViewConfiguration.get(this).hasPermanentMenuKey()) {
-                mMenuButton.setVisibility(View.VISIBLE);
-            } else {
-                mMenuButton.setVisibility(View.INVISIBLE);
-            }
-        }
+    private void exitSearchUi() {
+        final FragmentTransaction transaction = getFragmentManager().beginTransaction();
+        transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
+        transaction.hide(mRegularSearchFragment);
+        transaction.hide(mSmartDialSearchFragment);
+        transaction.show(mPhoneFavoriteFragment);
+        transaction.commit();
+        mInSearchUi = false;
     }
 
     /** Returns an Intent to launch Call Settings screen */
@@ -1277,16 +724,41 @@
     }
 
     @Override
-    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
-        if (resultCode != Activity.RESULT_OK) {
-            return;
+    public void onBackPressed() {
+        if (mDialpadFragment.isVisible()) {
+            hideDialpadFragment();
+        } else if (mInSearchUi) {
+            mSearchView.setQuery(null, false);
+        } else if (isTaskRoot()) {
+            // Instead of stopping, simply push this to the back of the stack.
+            // This is only done when running at the top of the stack;
+            // otherwise, we have been launched by someone else so need to
+            // allow the user to go back to the caller.
+            moveTaskToBack(false);
+        } else {
+            super.onBackPressed();
         }
-        switch (requestCode) {
-            case SUBACTIVITY_ACCOUNT_FILTER: {
-                AccountFilterUtil.handleAccountFilterResult(
-                        mContactListFilterController, resultCode, data);
-            }
-            break;
+    }
+
+    @Override
+    public void onDialpadQueryChanged(String query) {
+        final String normalizedQuery = SmartDialNameMatcher.normalizeNumber(query,
+                SmartDialNameMatcher.LATIN_SMART_DIAL_MAP);
+        if (!TextUtils.equals(mSearchView.getQuery(), normalizedQuery)) {
+            mSearchView.setQuery(normalizedQuery, false);
         }
     }
+
+    @Override
+    public void onListFragmentScrollStateChange(int scrollState) {
+        if (scrollState == OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
+            hideDialpadFragmentIfNecessary();
+            hideInputMethod(getCurrentFocus());
+        }
+    }
+
+    @Override
+    public void onPhoneFavoriteFragmentStarted() {
+        setupFakeActionBarItems();
+    }
 }
diff --git a/src/com/android/dialer/NewSearchFragment.java b/src/com/android/dialer/NewSearchFragment.java
new file mode 100644
index 0000000..c428db2
--- /dev/null
+++ b/src/com/android/dialer/NewSearchFragment.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2013 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;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AbsListView;
+import android.widget.AbsListView.OnScrollListener;
+import android.widget.ListView;
+
+import com.android.contacts.common.list.ContactListItemView;
+import com.android.contacts.common.list.PhoneNumberListAdapter;
+import com.android.contacts.common.list.PhoneNumberPickerFragment;
+import com.android.dialer.list.OnListFragmentScrolledListener;
+
+public class NewSearchFragment extends PhoneNumberPickerFragment {
+
+    private OnListFragmentScrolledListener mActivityScrollListener;
+
+    @Override
+    public void onAttach(Activity activity) {
+        super.onAttach(activity);
+
+        setQuickContactEnabled(true);
+        setDarkTheme(false);
+        setPhotoPosition(ContactListItemView.getDefaultPhotoPosition(true /* opposite */));
+        setUseCallableUri(true);
+
+        try {
+            mActivityScrollListener = (OnListFragmentScrolledListener) activity;
+        } catch (ClassCastException e) {
+            throw new ClassCastException(activity.toString()
+                    + " must implement OnListFragmentScrolledListener");
+        }
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        getListView().setOnScrollListener(new OnScrollListener() {
+            @Override
+            public void onScrollStateChanged(AbsListView view, int scrollState) {
+                mActivityScrollListener.onListFragmentScrollStateChange(scrollState);
+            }
+
+            @Override
+            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
+                    int totalItemCount) {
+            }
+        });
+    }
+
+    @Override
+    protected void setSearchMode(boolean flag) {
+        super.setSearchMode(flag);
+        // This hides the "All contacts with phone numbers" header in the search fragment
+        getAdapter().setHasHeader(0, false);
+    }
+}
diff --git a/src/com/android/dialer/calllog/CallLogAdapter.java b/src/com/android/dialer/calllog/CallLogAdapter.java
index 46f010a..46bb4fd 100644
--- a/src/com/android/dialer/calllog/CallLogAdapter.java
+++ b/src/com/android/dialer/calllog/CallLogAdapter.java
@@ -517,7 +517,7 @@
 
         views.primaryActionView.setTag(
                 IntentProvider.getCallDetailIntentProvider(
-                        this, c.getPosition(), c.getLong(CallLogQuery.ID), count));
+                        getCursor(), c.getPosition(), c.getLong(CallLogQuery.ID), count));
         // Store away the voicemail information so we can play it directly.
         if (callType == Calls.VOICEMAIL_TYPE) {
             String voicemailUri = c.getString(CallLogQuery.VOICEMAIL_URI);
diff --git a/src/com/android/dialer/calllog/CallLogQueryHandler.java b/src/com/android/dialer/calllog/CallLogQueryHandler.java
index fed3814..91a2e5d 100644
--- a/src/com/android/dialer/calllog/CallLogQueryHandler.java
+++ b/src/com/android/dialer/calllog/CallLogQueryHandler.java
@@ -45,7 +45,7 @@
 import javax.annotation.concurrent.GuardedBy;
 
 /** Handles asynchronous queries to the call log. */
-/*package*/ class CallLogQueryHandler extends NoNullCursorAsyncQueryHandler {
+public class CallLogQueryHandler extends NoNullCursorAsyncQueryHandler {
     private static final String[] EMPTY_STRING_ARRAY = new String[0];
 
     private static final String TAG = "CallLogQueryHandler";
@@ -62,6 +62,8 @@
     /** The token for the query to fetch voicemail status messages. */
     private static final int QUERY_VOICEMAIL_STATUS_TOKEN = 58;
 
+    private final int mLogLimit;
+
     /**
      * Call type similar to Calls.INCOMING_TYPE used to specify all types instead of one particular
      * type.
@@ -121,10 +123,16 @@
     }
 
     public CallLogQueryHandler(ContentResolver contentResolver, Listener listener) {
+        this(contentResolver, listener, -1);
+    }
+
+    public CallLogQueryHandler(ContentResolver contentResolver, Listener listener, int limit) {
         super(contentResolver);
         mListener = new WeakReference<Listener>(listener);
+        mLogLimit = limit;
     }
 
+
     /**
      * Fetches the list of calls from the call log for a given type.
      * <p>
@@ -154,8 +162,9 @@
             selection = String.format("(%s = ?)", Calls.TYPE);
             selectionArgs.add(Integer.toString(callType));
         }
+        final int limit = (mLogLimit == -1) ? NUM_LOGS_TO_DISPLAY : mLogLimit;
         Uri uri = Calls.CONTENT_URI_WITH_VOICEMAIL.buildUpon()
-                .appendQueryParameter(Calls.LIMIT_PARAM_KEY, Integer.toString(NUM_LOGS_TO_DISPLAY))
+                .appendQueryParameter(Calls.LIMIT_PARAM_KEY, Integer.toString(limit))
                 .build();
         startQuery(token, requestId, uri,
                 CallLogQuery._PROJECTION, selection, selectionArgs.toArray(EMPTY_STRING_ARRAY),
diff --git a/src/com/android/dialer/calllog/IntentProvider.java b/src/com/android/dialer/calllog/IntentProvider.java
index 1b79d6e..01ebf2f 100644
--- a/src/com/android/dialer/calllog/IntentProvider.java
+++ b/src/com/android/dialer/calllog/IntentProvider.java
@@ -62,11 +62,10 @@
     }
 
     public static IntentProvider getCallDetailIntentProvider(
-            final CallLogAdapter adapter, final int position, final long id, final int groupSize) {
+            final Cursor cursor, final int position, final long id, final int groupSize) {
         return new IntentProvider() {
             @Override
             public Intent getIntent(Context context) {
-                Cursor cursor = adapter.getCursor();
                 cursor.moveToPosition(position);
 
                 Intent intent = new Intent(context, CallDetailActivity.class);
diff --git a/src/com/android/dialer/calllog/NewCallLogActivity.java b/src/com/android/dialer/calllog/NewCallLogActivity.java
new file mode 100644
index 0000000..a3704cc
--- /dev/null
+++ b/src/com/android/dialer/calllog/NewCallLogActivity.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2013 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.calllog;
+
+import android.app.ActionBar;
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.app.ActionBar.Tab;
+import android.app.ActionBar.TabListener;
+import android.app.FragmentTransaction;
+import android.content.Intent;
+import android.os.Bundle;
+import android.provider.CallLog.Calls;
+import android.support.v13.app.FragmentPagerAdapter;
+import android.support.v4.view.PagerTabStrip;
+import android.support.v4.view.ViewPager;
+import android.support.v4.view.ViewPager.OnPageChangeListener;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+
+import com.android.dialer.NewDialtactsActivity;
+import com.android.dialer.R;
+import com.android.dialer.calllog.NewCallLogFragment;
+
+public class NewCallLogActivity extends Activity {
+
+    private ViewPager mViewPager;
+    private ViewPagerAdapter mViewPagerAdapter;
+    private NewCallLogFragment mAllCallsFragment;
+    private NewCallLogFragment mMissedCallsFragment;
+    private NewCallLogFragment mVoicemailsFragment;
+
+    private static final int TAB_INDEX_ALL = 0;
+    private static final int TAB_INDEX_MISSED = 1;
+    private static final int TAB_INDEX_VOICEMAIL = 2;
+
+    private static final int TAB_INDEX_COUNT = 3;
+
+    public class ViewPagerAdapter extends FragmentPagerAdapter {
+        public ViewPagerAdapter(FragmentManager fm) {
+            super(fm);
+        }
+
+        @Override
+        public Fragment getItem(int position) {
+            switch (position) {
+                case TAB_INDEX_ALL:
+                    mAllCallsFragment = new NewCallLogFragment(CallLogQueryHandler.CALL_TYPE_ALL);
+                    return mAllCallsFragment;
+                case TAB_INDEX_MISSED:
+                    mMissedCallsFragment = new NewCallLogFragment(Calls.MISSED_TYPE);
+                    return mMissedCallsFragment;
+                case TAB_INDEX_VOICEMAIL:
+                    mVoicemailsFragment = new NewCallLogFragment(Calls.VOICEMAIL_TYPE);
+                    return mVoicemailsFragment;
+            }
+            throw new IllegalStateException("No fragment at position " + position);
+        }
+
+        @Override
+        public int getCount() {
+            return TAB_INDEX_COUNT;
+        }
+    }
+
+    private final TabListener mTabListener = new TabListener() {
+        @Override
+        public void onTabUnselected(Tab tab, FragmentTransaction ft) {
+        }
+
+        @Override
+        public void onTabSelected(Tab tab, FragmentTransaction ft) {
+            if (mViewPager != null && mViewPager.getCurrentItem() != tab.getPosition()) {
+                mViewPager.setCurrentItem(tab.getPosition(), true);
+            }
+        }
+
+        @Override
+        public void onTabReselected(Tab tab, FragmentTransaction ft) {
+        }
+    };
+
+    private final OnPageChangeListener mOnPageChangeListener = new OnPageChangeListener() {
+
+        @Override
+        public void onPageScrolled(
+                int position, float positionOffset, int positionOffsetPixels) {}
+
+        @Override
+        public void onPageSelected(int position) {
+            final ActionBar actionBar = getActionBar();
+            actionBar.selectTab(actionBar.getTabAt(position));
+        }
+
+        @Override
+        public void onPageScrollStateChanged(int arg0) {
+        }
+    };
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.call_log_activity_new);
+
+        final ActionBar actionBar = getActionBar();
+        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+        actionBar.setDisplayShowHomeEnabled(true);
+        actionBar.setDisplayHomeAsUpEnabled(true);
+        actionBar.setDisplayShowTitleEnabled(true);
+
+        final Tab allTab = actionBar.newTab();
+        final String allTitle = getString(R.string.call_log_all_title);
+        allTab.setContentDescription(allTitle);
+        allTab.setText(allTitle);
+        allTab.setTabListener(mTabListener);
+        actionBar.addTab(allTab);
+
+        final Tab missedTab = actionBar.newTab();
+        final String missedTitle = getString(R.string.call_log_missed_title);
+        missedTab.setContentDescription(missedTitle);
+        missedTab.setText(missedTitle);
+        missedTab.setTabListener(mTabListener);
+        actionBar.addTab(missedTab);
+
+        final Tab voicemailTab = actionBar.newTab();
+        final String voicemailTitle = getString(R.string.call_log_voicemail_title);
+        voicemailTab.setContentDescription(voicemailTitle);
+        voicemailTab.setText(voicemailTitle);
+        voicemailTab.setTabListener(mTabListener);
+        actionBar.addTab(voicemailTab);
+
+        mViewPager = (ViewPager) findViewById(R.id.call_log_pager);
+        mViewPagerAdapter = new ViewPagerAdapter(getFragmentManager());
+        mViewPager.setAdapter(mViewPagerAdapter);
+        mViewPager.setOnPageChangeListener(mOnPageChangeListener);
+        mViewPager.setOffscreenPageLimit(2);
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        final MenuInflater inflater = getMenuInflater();
+        inflater.inflate(R.menu.call_log_options_new, menu);
+        return true;
+    }
+
+    @Override
+    public boolean onPrepareOptionsMenu(Menu menu) {
+        final MenuItem itemDeleteAll = menu.findItem(R.id.delete_all);
+
+        final NewCallLogAdapter adapter = mAllCallsFragment.getAdapter();
+        // Check if all the menu items are inflated correctly. As a shortcut, we assume all
+        // menu items are ready if the first item is non-null.
+        if (itemDeleteAll != null) {
+            itemDeleteAll.setEnabled(adapter != null && !adapter.isEmpty());
+        }
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case android.R.id.home:
+                final Intent intent = new Intent(this, NewDialtactsActivity.class);
+                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                startActivity(intent);
+                return true;
+            case R.id.delete_all:
+                ClearCallLogDialog.show(getFragmentManager());
+                return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+}
diff --git a/src/com/android/dialer/calllog/NewCallLogAdapter.java b/src/com/android/dialer/calllog/NewCallLogAdapter.java
index 079919f..c2f7c71 100644
--- a/src/com/android/dialer/calllog/NewCallLogAdapter.java
+++ b/src/com/android/dialer/calllog/NewCallLogAdapter.java
@@ -46,7 +46,7 @@
 /**
  * Adapter class to fill in data for the Call Log.
  */
-/*package*/ class NewCallLogAdapter extends GroupingListAdapter
+public class NewCallLogAdapter extends GroupingListAdapter
         implements ViewTreeObserver.OnPreDrawListener, CallLogGroupBuilder.GroupCreator {
     /** Interface used to initiate a refresh of the content. */
     public interface CallFetcher {
@@ -166,7 +166,7 @@
     private QueryThread mCallerIdThread;
 
     /** Instance of helper class for managing views. */
-    private final CallLogListItemHelper mCallLogViewsHelper;
+    private final NewCallLogListItemHelper mCallLogViewsHelper;
 
     /** Helper to set up contact photos. */
     private final ContactPhotoManager mContactPhotoManager;
@@ -227,7 +227,7 @@
         }
     };
 
-    NewCallLogAdapter(Context context, CallFetcher callFetcher,
+    public NewCallLogAdapter(Context context, CallFetcher callFetcher,
             ContactInfoHelper contactInfoHelper) {
         super(context);
 
@@ -246,7 +246,7 @@
         PhoneCallDetailsHelper phoneCallDetailsHelper = new PhoneCallDetailsHelper(
                 resources, callTypeHelper, mPhoneNumberHelper);
         mCallLogViewsHelper =
-                new CallLogListItemHelper(
+                new NewCallLogListItemHelper(
                         phoneCallDetailsHelper, mPhoneNumberHelper, resources);
         mCallLogGroupBuilder = new CallLogGroupBuilder(this);
     }
@@ -259,7 +259,7 @@
         mCallFetcher.fetchCalls();
     }
 
-    void setLoading(boolean loading) {
+    public void setLoading(boolean loading) {
         mLoading = loading;
     }
 
@@ -444,7 +444,7 @@
     protected View newStandAloneView(Context context, ViewGroup parent) {
         LayoutInflater inflater =
                 (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        View view = inflater.inflate(R.layout.call_log_list_item, parent, false);
+        View view = inflater.inflate(R.layout.new_call_log_list_item, parent, false);
         findAndCacheViews(view);
         return view;
     }
@@ -458,7 +458,7 @@
     protected View newChildView(Context context, ViewGroup parent) {
         LayoutInflater inflater =
                 (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        View view = inflater.inflate(R.layout.call_log_list_item, parent, false);
+        View view = inflater.inflate(R.layout.new_call_log_list_item, parent, false);
         findAndCacheViews(view);
         return view;
     }
@@ -472,7 +472,7 @@
     protected View newGroupView(Context context, ViewGroup parent) {
         LayoutInflater inflater =
                 (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        View view = inflater.inflate(R.layout.call_log_list_item, parent, false);
+        View view = inflater.inflate(R.layout.new_call_log_list_item, parent, false);
         findAndCacheViews(view);
         return view;
     }
@@ -515,9 +515,10 @@
 
         final ContactInfo cachedContactInfo = getContactInfoFromCallLog(c);
 
-        /*views.primaryActionView.setTag(
+        views.primaryActionView.setTag(
                 IntentProvider.getCallDetailIntentProvider(
-                        this, c.getPosition(), c.getLong(CallLogQuery.ID), count));*/
+                        getCursor(), c.getPosition(), c.getLong(CallLogQuery.ID), count));
+
         // Store away the voicemail information so we can play it directly.
         if (callType == Calls.VOICEMAIL_TYPE) {
             String voicemailUri = c.getString(CallLogQuery.VOICEMAIL_URI);
@@ -715,7 +716,7 @@
 
     private void setPhoto(CallLogListItemViews views, long photoId, Uri contactUri) {
         views.quickContactView.assignContactUri(contactUri);
-        mContactPhotoManager.loadThumbnail(views.quickContactView, photoId, true);
+        mContactPhotoManager.loadThumbnail(views.quickContactView, photoId, false /* darkTheme */);
     }
 
     /**
diff --git a/src/com/android/dialer/calllog/NewCallLogFragment.java b/src/com/android/dialer/calllog/NewCallLogFragment.java
index d5b1795..c470c55 100644
--- a/src/com/android/dialer/calllog/NewCallLogFragment.java
+++ b/src/com/android/dialer/calllog/NewCallLogFragment.java
@@ -34,7 +34,6 @@
 import android.telephony.PhoneNumberUtils;
 import android.telephony.PhoneStateListener;
 import android.telephony.TelephonyManager;
-import android.text.TextUtils;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.Menu;
@@ -59,10 +58,11 @@
 import java.util.List;
 
 /**
- * Displays a list of call log entries.
+ * Displays a list of call log entries. To filter for a particular kind of call
+ * (all, missed or voicemails), specify it in the constructor.
  */
 public class NewCallLogFragment extends ListFragment
-        implements CallLogQueryHandler.Listener, CallLogAdapter.CallFetcher {
+        implements CallLogQueryHandler.Listener, NewCallLogAdapter.CallFetcher {
     private static final String TAG = "CallLogFragment";
 
     /**
@@ -70,7 +70,7 @@
      */
     private static final int EMPTY_LOADER_ID = 0;
 
-    private CallLogAdapter mAdapter;
+    private NewCallLogAdapter mAdapter;
     private CallLogQueryHandler mCallLogQueryHandler;
     private boolean mScrollToTop;
 
@@ -81,7 +81,6 @@
     private View mStatusMessageView;
     private TextView mStatusMessageText;
     private TextView mStatusMessageAction;
-    private TextView mFilterStatusView;
     private KeyguardManager mKeyguardManager;
 
     private boolean mEmptyLoaderRunning;
@@ -114,11 +113,30 @@
     // Default to all calls.
     private int mCallTypeFilter = CallLogQueryHandler.CALL_TYPE_ALL;
 
+    // Log limit - if no limit is specified, then the default in {@link NewCallLogQueryHandler}
+    // will be used.
+    private int mLogLimit = -1;
+
+    public NewCallLogFragment() {
+        this(CallLogQueryHandler.CALL_TYPE_ALL, -1);
+    }
+
+    public NewCallLogFragment(int filterType) {
+        this(filterType, -1);
+    }
+
+    public NewCallLogFragment(int filterType, int logLimit) {
+        super();
+        mCallTypeFilter = filterType;
+        mLogLimit = logLimit;
+    }
+
     @Override
     public void onCreate(Bundle state) {
         super.onCreate(state);
 
-        mCallLogQueryHandler = new CallLogQueryHandler(getActivity().getContentResolver(), this);
+        mCallLogQueryHandler = new CallLogQueryHandler(getActivity().getContentResolver(),
+                this, mLogLimit);
         mKeyguardManager =
                 (KeyguardManager) getActivity().getSystemService(Context.KEYGUARD_SERVICE);
         getActivity().getContentResolver().registerContentObserver(
@@ -126,6 +144,7 @@
         getActivity().getContentResolver().registerContentObserver(
                 ContactsContract.Contacts.CONTENT_URI, true, mContactsObserver);
         setHasOptionsMenu(true);
+        updateCallList(mCallTypeFilter);
     }
 
     /** Called by the CallLogQueryHandler when the list of calls has been fetched or updated. */
@@ -205,20 +224,20 @@
 
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
-        View view = inflater.inflate(R.layout.call_log_fragment, container, false);
+        View view = inflater.inflate(R.layout.new_call_log_fragment, container, false);
         mVoicemailStatusHelper = new VoicemailStatusHelperImpl();
         mStatusMessageView = view.findViewById(R.id.voicemail_status);
         mStatusMessageText = (TextView) view.findViewById(R.id.voicemail_status_message);
         mStatusMessageAction = (TextView) view.findViewById(R.id.voicemail_status_action);
-        mFilterStatusView = (TextView) view.findViewById(R.id.filter_status);
         return view;
     }
 
     @Override
     public void onViewCreated(View view, Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
+        updateEmptyMessage(mCallTypeFilter);
         String currentCountryIso = GeoUtil.getCurrentCountryIso(getActivity());
-        mAdapter = new CallLogAdapter(getActivity(), this,
+        mAdapter = new NewCallLogAdapter(getActivity(), this,
                 new ContactInfoHelper(getActivity(), currentCountryIso));
         setListAdapter(mAdapter);
         getListView().setItemsCanFocus(true);
@@ -250,6 +269,7 @@
 
     @Override
     public void onResume() {
+        Log.d(TAG, "Call Log Fragment resume");
         super.onResume();
         refreshData();
     }
@@ -320,132 +340,30 @@
         mCallLogQueryHandler.fetchVoicemailStatus();
     }
 
-    @Override
-    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
-        super.onCreateOptionsMenu(menu, inflater);
-        inflater.inflate(R.menu.call_log_options, menu);
-    }
-
-    @Override
-    public void onPrepareOptionsMenu(Menu menu) {
-        final MenuItem itemDeleteAll = menu.findItem(R.id.delete_all);
-        // Check if all the menu items are inflated correctly. As a shortcut, we assume all
-        // menu items are ready if the first item is non-null.
-        if (itemDeleteAll != null) {
-            itemDeleteAll.setEnabled(mAdapter != null && !mAdapter.isEmpty());
-
-            showAllFilterMenuOptions(menu);
-            hideCurrentFilterMenuOption(menu);
-
-            // Only hide if not available.  Let the above calls handle showing.
-            if (!mVoicemailSourcesAvailable) {
-                menu.findItem(R.id.show_voicemails_only).setVisible(false);
-            }
+    private void updateCallList(int filterType) {
+        if (filterType == CallLogQueryHandler.CALL_TYPE_ALL) {
+            unregisterPhoneCallReceiver();
+        } else {
+            // TODO krelease: Make this work
+            //registerPhoneCallReceiver();
         }
+        mCallLogQueryHandler.fetchCalls(filterType);
     }
 
-    private void hideCurrentFilterMenuOption(Menu menu) {
-        MenuItem item = null;
-        switch (mCallTypeFilter) {
-            case CallLogQueryHandler.CALL_TYPE_ALL:
-                item = menu.findItem(R.id.show_all_calls);
-                break;
-            case Calls.INCOMING_TYPE:
-                item = menu.findItem(R.id.show_incoming_only);
-                break;
-            case Calls.OUTGOING_TYPE:
-                item = menu.findItem(R.id.show_outgoing_only);
-                break;
-            case Calls.MISSED_TYPE:
-                item = menu.findItem(R.id.show_missed_only);
-                break;
-            case Calls.VOICEMAIL_TYPE:
-                menu.findItem(R.id.show_voicemails_only);
-                break;
-        }
-        if (item != null) {
-            item.setVisible(false);
-        }
-    }
-
-    private void showAllFilterMenuOptions(Menu menu) {
-        menu.findItem(R.id.show_all_calls).setVisible(true);
-        menu.findItem(R.id.show_incoming_only).setVisible(true);
-        menu.findItem(R.id.show_outgoing_only).setVisible(true);
-        menu.findItem(R.id.show_missed_only).setVisible(true);
-        menu.findItem(R.id.show_voicemails_only).setVisible(true);
-    }
-
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        switch (item.getItemId()) {
-            case R.id.delete_all:
-                ClearCallLogDialog.show(getFragmentManager());
-                return true;
-
-            case R.id.show_outgoing_only:
-                // We only need the phone call receiver when there is an active call type filter.
-                // Not many people may use the filters so don't register the receiver until now .
-                registerPhoneCallReceiver();
-                mCallLogQueryHandler.fetchCalls(Calls.OUTGOING_TYPE);
-                updateFilterTypeAndHeader(Calls.OUTGOING_TYPE);
-                return true;
-
-            case R.id.show_incoming_only:
-                registerPhoneCallReceiver();
-                mCallLogQueryHandler.fetchCalls(Calls.INCOMING_TYPE);
-                updateFilterTypeAndHeader(Calls.INCOMING_TYPE);
-                return true;
-
-            case R.id.show_missed_only:
-                registerPhoneCallReceiver();
-                mCallLogQueryHandler.fetchCalls(Calls.MISSED_TYPE);
-                updateFilterTypeAndHeader(Calls.MISSED_TYPE);
-                return true;
-
-            case R.id.show_voicemails_only:
-                registerPhoneCallReceiver();
-                mCallLogQueryHandler.fetchCalls(Calls.VOICEMAIL_TYPE);
-                updateFilterTypeAndHeader(Calls.VOICEMAIL_TYPE);
-                return true;
-
-            case R.id.show_all_calls:
-                // Filter is being turned off, receiver no longer needed.
-                unregisterPhoneCallReceiver();
-                mCallLogQueryHandler.fetchCalls(CallLogQueryHandler.CALL_TYPE_ALL);
-                updateFilterTypeAndHeader(CallLogQueryHandler.CALL_TYPE_ALL);
-                return true;
-
-            default:
-                return false;
-        }
-    }
-
-    private void updateFilterTypeAndHeader(int filterType) {
-        mCallTypeFilter = filterType;
-
+    private void updateEmptyMessage(int filterType) {
+        final String message;
         switch (filterType) {
-            case CallLogQueryHandler.CALL_TYPE_ALL:
-                mFilterStatusView.setVisibility(View.GONE);
-                break;
-            case Calls.INCOMING_TYPE:
-                showFilterStatus(R.string.call_log_incoming_header);
-                break;
-            case Calls.OUTGOING_TYPE:
-                showFilterStatus(R.string.call_log_outgoing_header);
-                break;
             case Calls.MISSED_TYPE:
-                showFilterStatus(R.string.call_log_missed_header);
+                message = getString(R.string.recentMissed_empty);
                 break;
             case Calls.VOICEMAIL_TYPE:
-                showFilterStatus(R.string.call_log_voicemail_header);
+                message = getString(R.string.recentVoicemails_empty);
+                break;
+            default:
+                message = getString(R.string.recentCalls_empty);
                 break;
         }
-    }
-
-    private void showFilterStatus(int resId) {
-        mFilterStatusView.setText(resId);
-        mFilterStatusView.setVisibility(View.VISIBLE);
+        ((TextView) getListView().getEmptyView()).setText(message);
     }
 
     public void callSelectedEntry() {
@@ -489,8 +407,7 @@
         }
     }
 
-    @VisibleForTesting
-    CallLogAdapter getAdapter() {
+    NewCallLogAdapter getAdapter() {
         return mAdapter;
     }
 
@@ -547,6 +464,8 @@
         updateOnTransition(true);
     }
 
+    // TODO krelease: Figure out if we still need this. If so, it should be probably be moved to
+    // the call log activity instead, or done only in a single call log fragment.
     private void updateOnTransition(boolean onEntry) {
         // We don't want to update any call data when keyguard is on because the user has likely not
         // seen the new calls yet.
@@ -570,9 +489,13 @@
         getActivity().startService(serviceIntent);
     }
 
+    // TODO krelease: Make the ViewPager switch to the correct tab (All) when a phone call is
+    // placed.
+    // This should probably be moved to the call log activity.
     /**
      * Register a phone call filter to reset the call type when a phone call is place.
      */
+    /*
     private void registerPhoneCallReceiver() {
         if (mPhoneStateListener != null) {
             return; // Already registered.
@@ -592,13 +515,13 @@
                         if (getActivity() == null || getActivity().isFinishing()) {
                             return;
                         }
-                        updateFilterTypeAndHeader(CallLogQueryHandler.CALL_TYPE_ALL);
                     }
                  });
             }
         };
         mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
     }
+    */
 
     /**
      * Un-registers the phone call receiver.
diff --git a/src/com/android/dialer/calllog/NewCallLogListItemHelper.java b/src/com/android/dialer/calllog/NewCallLogListItemHelper.java
index 371094d..6cb80a0 100644
--- a/src/com/android/dialer/calllog/NewCallLogListItemHelper.java
+++ b/src/com/android/dialer/calllog/NewCallLogListItemHelper.java
@@ -27,8 +27,12 @@
 
 /**
  * Helper class to fill in the views of a call log entry.
+ * TODO krelease: The only difference between this and the original is that we don't touch
+ * divider views, which are not present in the new dialer. Once the new dialer replaces
+ * the old one, we can replace it entirely. Otherwise we would have redundant divider=null
+ * checks all over the place.
  */
-/*package*/ class NewCallLogListItemHelper {
+/* package */class NewCallLogListItemHelper {
     /** Helper for populating the details of a phone call. */
     private final PhoneCallDetailsHelper mPhoneCallDetailsHelper;
     /** Helper for handling phone numbers. */
@@ -67,15 +71,12 @@
         if (canPlay) {
             // Playback action takes preference.
             configurePlaySecondaryAction(views, isHighlighted);
-            views.dividerView.setVisibility(View.VISIBLE);
         } else if (canCall) {
             // Call is the secondary action.
             configureCallSecondaryAction(views, details);
-            views.dividerView.setVisibility(View.VISIBLE);
         } else {
             // No action available.
             views.secondaryActionView.setVisibility(View.GONE);
-            views.dividerView.setVisibility(View.GONE);
         }
     }
 
diff --git a/src/com/android/dialer/database/DialerDatabaseHelper.java b/src/com/android/dialer/database/DialerDatabaseHelper.java
index fd402c9..a802825 100644
--- a/src/com/android/dialer/database/DialerDatabaseHelper.java
+++ b/src/com/android/dialer/database/DialerDatabaseHelper.java
@@ -31,12 +31,12 @@
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.Data;
 import android.provider.ContactsContract.Directory;
-import com.android.contacts.common.test.NeededForTesting;
 import android.util.Log;
 
 import com.android.contacts.common.util.StopWatch;
 import com.android.dialer.dialpad.SmartDialNameMatcher;
 import com.android.dialer.dialpad.SmartDialPrefix;
+
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Objects;
 import com.google.common.base.Preconditions;
@@ -68,7 +68,7 @@
      *   0-98   KeyLimePie
      * </pre>
      */
-    private static final int DATABASE_VERSION = 1;
+    private static final int DATABASE_VERSION = 2;
     private static final String SMARTDIAL_DATABASE_NAME = "dialer.db";
 
     /**
@@ -77,7 +77,7 @@
     private static final String DATABASE_LAST_CREATED_SHARED_PREF = "com.android.dialer_smartdial";
     private static final String LAST_UPDATED_MILLIS = "last_updated_millis";
 
-    private static final int MAX_ENTRIES = 3;
+    private static final int MAX_ENTRIES = 20;
 
     public interface Tables {
         /** Saves the necessary smart dial information of all contacts. */
@@ -88,10 +88,12 @@
 
     public interface SmartDialDbColumns {
         static final String _ID = "id";
+        static final String DATA_ID = "data_id";
         static final String NUMBER = "phone_number";
         static final String CONTACT_ID = "contact_id";
         static final String LOOKUP_KEY = "lookup_key";
         static final String DISPLAY_NAME_PRIMARY = "display_name";
+        static final String PHOTO_ID = "photo_id";
         static final String LAST_TIME_USED = "last_time_used";
         static final String TIMES_USED = "times_used";
         static final String STARRED = "starred";
@@ -122,12 +124,13 @@
             Phone.CONTACT_ID,                   // 4
             Phone.LOOKUP_KEY,                   // 5
             Phone.DISPLAY_NAME_PRIMARY,         // 6
-            Data.LAST_TIME_USED,                // 7
-            Data.TIMES_USED,                    // 8
-            Contacts.STARRED,                   // 9
-            Data.IS_SUPER_PRIMARY,              // 10
-            Contacts.IN_VISIBLE_GROUP,          // 11
-            Data.IS_PRIMARY,                    // 12
+            Phone.PHOTO_ID,                     // 7
+            Data.LAST_TIME_USED,                // 8
+            Data.TIMES_USED,                    // 9
+            Contacts.STARRED,                   // 10
+            Data.IS_SUPER_PRIMARY,              // 11
+            Contacts.IN_VISIBLE_GROUP,          // 12
+            Data.IS_PRIMARY,                    // 13
         };
 
         static final int PHONE_ID = 0;
@@ -137,12 +140,13 @@
         static final int PHONE_CONTACT_ID = 4;
         static final int PHONE_LOOKUP_KEY = 5;
         static final int PHONE_DISPLAY_NAME = 6;
-        static final int PHONE_LAST_TIME_USED = 7;
-        static final int PHONE_TIMES_USED = 8;
-        static final int PHONE_STARRED = 9;
-        static final int PHONE_IS_SUPER_PRIMARY = 10;
-        static final int PHONE_IN_VISIBLE_GROUP = 11;
-        static final int PHONE_IS_PRIMARY = 12;
+        static final int PHONE_PHOTO_ID = 7;
+        static final int PHONE_LAST_TIME_USED = 8;
+        static final int PHONE_TIMES_USED = 9;
+        static final int PHONE_STARRED = 10;
+        static final int PHONE_IS_SUPER_PRIMARY = 11;
+        static final int PHONE_IN_VISIBLE_GROUP = 12;
+        static final int PHONE_IS_PRIMARY = 13;
 
         /** Selects only rows that have been updated after a certain time stamp.*/
         static final String SELECT_UPDATED_CLAUSE =
@@ -210,21 +214,26 @@
      * smart dial interface.
      */
     public static class ContactNumber {
-        public final String displayName;
-        public final String lookupKey;
         public final long id;
+        public final long dataId;
+        public final String displayName;
         public final String phoneNumber;
+        public final String lookupKey;
+        public final long photoId;
 
-        public ContactNumber(long id, String displayName, String phoneNumber, String lookupKey) {
-            this.displayName = displayName;
-            this.lookupKey = lookupKey;
+        public ContactNumber(long id, long dataID, String displayName, String phoneNumber,
+                String lookupKey, long photoId) {
+            this.dataId = dataID;
             this.id = id;
+            this.displayName = displayName;
             this.phoneNumber = phoneNumber;
+            this.lookupKey = lookupKey;
+            this.photoId = photoId;
         }
 
         @Override
         public int hashCode() {
-            return Objects.hashCode(displayName, id, lookupKey, phoneNumber);
+            return Objects.hashCode(id, dataId, displayName, phoneNumber, lookupKey, photoId);
         }
 
         @Override
@@ -234,10 +243,12 @@
             }
             if (object instanceof ContactNumber) {
                 final ContactNumber that = (ContactNumber) object;
-                return Objects.equal(this.displayName, that.displayName)
-                        && Objects.equal(this.id, that.id)
+                return Objects.equal(this.id, that.id)
+                        && Objects.equal(this.dataId, that.dataId)
+                        && Objects.equal(this.displayName, that.displayName)
+                        && Objects.equal(this.phoneNumber, that.phoneNumber)
                         && Objects.equal(this.lookupKey, that.lookupKey)
-                        && Objects.equal(this.phoneNumber, that.phoneNumber);
+                        && Objects.equal(this.photoId, that.photoId);
             }
             return false;
         }
@@ -290,7 +301,7 @@
     /**
      * Returns a new instance for unit tests. The database will be created in memory.
      */
-    @NeededForTesting
+    @VisibleForTesting
     static DialerDatabaseHelper getNewInstanceForTest(Context context) {
         return new DialerDatabaseHelper(context, null);
     }
@@ -309,10 +320,12 @@
     public void onCreate(SQLiteDatabase db) {
         db.execSQL("CREATE TABLE " + Tables.SMARTDIAL_TABLE + " (" +
                 SmartDialDbColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
+                SmartDialDbColumns.DATA_ID + " INTEGER, " +
                 SmartDialDbColumns.NUMBER + " TEXT," +
                 SmartDialDbColumns.CONTACT_ID + " INTEGER," +
                 SmartDialDbColumns.LOOKUP_KEY + " TEXT," +
                 SmartDialDbColumns.DISPLAY_NAME_PRIMARY + " TEXT, " +
+                SmartDialDbColumns.PHOTO_ID + " INTEGER, " +
                 SmartDialDbColumns.LAST_SMARTDIAL_UPDATE_TIME + " LONG, " +
                 SmartDialDbColumns.LAST_TIME_USED + " LONG, " +
                 SmartDialDbColumns.TIMES_USED + " INTEGER, " +
@@ -329,6 +342,21 @@
                 ");");
     }
 
+    @Override
+    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+        Log.w(TAG, oldVersion + " to " + newVersion + ", rebuilding table");
+
+        final SharedPreferences databaseLastUpdateSharedPref = mContext.getSharedPreferences(
+                DATABASE_LAST_CREATED_SHARED_PREF, Context.MODE_PRIVATE);
+        final SharedPreferences.Editor editor = databaseLastUpdateSharedPref.edit();
+        editor.putLong(LAST_UPDATED_MILLIS, 0);
+        editor.commit();
+
+        db.execSQL("DROP TABLE IF EXISTS " + Tables.PREFIX_TABLE);
+        db.execSQL("DROP TABLE IF EXISTS " + Tables.SMARTDIAL_TABLE);
+        onCreate(db);
+    }
+
     /**
      * Starts the database upgrade process in the background.
      */
@@ -468,10 +496,12 @@
         db.beginTransaction();
         try {
             final String sqlInsert = "INSERT INTO " + Tables.SMARTDIAL_TABLE + " (" +
+                    SmartDialDbColumns.DATA_ID + ", " +
                     SmartDialDbColumns.NUMBER + ", " +
                     SmartDialDbColumns.CONTACT_ID + ", " +
                     SmartDialDbColumns.LOOKUP_KEY + ", " +
                     SmartDialDbColumns.DISPLAY_NAME_PRIMARY + ", " +
+                    SmartDialDbColumns.PHOTO_ID + ", " +
                     SmartDialDbColumns.LAST_TIME_USED + ", " +
                     SmartDialDbColumns.TIMES_USED + ", " +
                     SmartDialDbColumns.STARRED + ", " +
@@ -479,7 +509,7 @@
                     SmartDialDbColumns.IN_VISIBLE_GROUP+ ", " +
                     SmartDialDbColumns.IS_PRIMARY + ", " +
                     SmartDialDbColumns.LAST_SMARTDIAL_UPDATE_TIME + ") " +
-                    " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+                    " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
             final SQLiteStatement insert = db.compileStatement(sqlInsert);
 
             final String numberSqlInsert = "INSERT INTO " + Tables.PREFIX_TABLE + " (" +
@@ -490,17 +520,19 @@
 
             updatedContactCursor.moveToPosition(-1);
             while (updatedContactCursor.moveToNext()) {
-                insert.bindString(1, updatedContactCursor.getString(PhoneQuery.PHONE_NUMBER));
-                insert.bindLong(2, updatedContactCursor.getLong(PhoneQuery.PHONE_CONTACT_ID));
-                insert.bindString(3, updatedContactCursor.getString(PhoneQuery.PHONE_LOOKUP_KEY));
-                insert.bindString(4, updatedContactCursor.getString(PhoneQuery.PHONE_DISPLAY_NAME));
-                insert.bindLong(5, updatedContactCursor.getLong(PhoneQuery.PHONE_LAST_TIME_USED));
-                insert.bindLong(6, updatedContactCursor.getInt(PhoneQuery.PHONE_TIMES_USED));
-                insert.bindLong(7, updatedContactCursor.getInt(PhoneQuery.PHONE_STARRED));
-                insert.bindLong(8, updatedContactCursor.getInt(PhoneQuery.PHONE_IS_SUPER_PRIMARY));
-                insert.bindLong(9, updatedContactCursor.getInt(PhoneQuery.PHONE_IN_VISIBLE_GROUP));
-                insert.bindLong(10, updatedContactCursor.getInt(PhoneQuery.PHONE_IS_PRIMARY));
-                insert.bindLong(11, currentMillis);
+                insert.bindLong(1, updatedContactCursor.getLong(PhoneQuery.PHONE_ID));
+                insert.bindString(2, updatedContactCursor.getString(PhoneQuery.PHONE_NUMBER));
+                insert.bindLong(3, updatedContactCursor.getLong(PhoneQuery.PHONE_CONTACT_ID));
+                insert.bindString(4, updatedContactCursor.getString(PhoneQuery.PHONE_LOOKUP_KEY));
+                insert.bindString(5, updatedContactCursor.getString(PhoneQuery.PHONE_DISPLAY_NAME));
+                insert.bindLong(6, updatedContactCursor.getLong(PhoneQuery.PHONE_PHOTO_ID));
+                insert.bindLong(7, updatedContactCursor.getLong(PhoneQuery.PHONE_LAST_TIME_USED));
+                insert.bindLong(8, updatedContactCursor.getInt(PhoneQuery.PHONE_TIMES_USED));
+                insert.bindLong(9, updatedContactCursor.getInt(PhoneQuery.PHONE_STARRED));
+                insert.bindLong(10, updatedContactCursor.getInt(PhoneQuery.PHONE_IS_SUPER_PRIMARY));
+                insert.bindLong(11, updatedContactCursor.getInt(PhoneQuery.PHONE_IN_VISIBLE_GROUP));
+                insert.bindLong(12, updatedContactCursor.getInt(PhoneQuery.PHONE_IS_PRIMARY));
+                insert.bindLong(13, currentMillis);
                 insert.executeInsert();
                 insert.clearBindings();
 
@@ -719,7 +751,6 @@
         }
     }
 
-
     /**
      * Returns a list of candidate contacts where the query is a prefix of the dialpad index of
      * the contact's name or phone number.
@@ -747,7 +778,9 @@
 
         /** Queries the database to find contacts that have an index matching the query prefix. */
         final Cursor cursor = db.rawQuery("SELECT " +
+                SmartDialDbColumns.DATA_ID + ", " +
                 SmartDialDbColumns.DISPLAY_NAME_PRIMARY + ", " +
+                SmartDialDbColumns.PHOTO_ID + ", " +
                 SmartDialDbColumns.NUMBER + ", " +
                 SmartDialDbColumns.CONTACT_ID + ", " +
                 SmartDialDbColumns.LOOKUP_KEY +
@@ -765,10 +798,12 @@
         }
 
         /** Gets the column ID from the cursor.*/
-        final int columnDisplayNamePrimary = 0;
-        final int columnNumber = 1;
-        final int columnId = 2;
-        final int columnLookupKey = 3;
+        final int columnDataId = 0;
+        final int columnDisplayNamePrimary = 1;
+        final int columnPhotoId = 2;
+        final int columnNumber = 3;
+        final int columnId = 4;
+        final int columnLookupKey = 5;
         if (DEBUG) {
             stopWatch.lap("Found column IDs");
         }
@@ -781,9 +816,11 @@
             }
             /** Iterates the cursor to find top contact suggestions without duplication.*/
             while ((cursor.moveToNext()) && (counter < MAX_ENTRIES)) {
+                final long dataID = cursor.getLong(columnDataId);
                 final String displayName = cursor.getString(columnDisplayNamePrimary);
                 final String phoneNumber = cursor.getString(columnNumber);
                 final long id = cursor.getLong(columnId);
+                final long photoId = cursor.getLong(columnPhotoId);
                 final String lookupKey = cursor.getString(columnLookupKey);
 
                 /** If a contact already exists and another phone number of the contact is being
@@ -798,11 +835,14 @@
                  * If the contact has either the name or number that matches the query, add to the
                  * result.
                  */
-                if (nameMatcher.matches(displayName) ||
-                        nameMatcher.matchesNumber(phoneNumber, query) != null) {
+                final boolean nameMatches = nameMatcher.matches(displayName);
+                final boolean numberMatches =
+                        (nameMatcher.matchesNumber(phoneNumber, query) != null);
+                if (nameMatches || numberMatches) {
                     /** If a contact has not been added, add it to the result and the hash set.*/
                     duplicates.add(contactMatch);
-                    result.add(new ContactNumber(id, displayName, phoneNumber, lookupKey));
+                    result.add(new ContactNumber(id, dataID, displayName, phoneNumber, lookupKey,
+                            photoId));
                     counter++;
                     if (DEBUG) {
                         stopWatch.lap("Added one result");
@@ -818,9 +858,4 @@
         }
         return result;
     }
-
-    @Override
-    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
-
-    }
 }
diff --git a/src/com/android/dialer/dialpad/NewDialpadFragment.java b/src/com/android/dialer/dialpad/NewDialpadFragment.java
index 7076517..46f5d06 100644
--- a/src/com/android/dialer/dialpad/NewDialpadFragment.java
+++ b/src/com/android/dialer/dialpad/NewDialpadFragment.java
@@ -32,7 +32,6 @@
 import android.media.AudioManager;
 import android.media.ToneGenerator;
 import android.net.Uri;
-import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -50,6 +49,7 @@
 import android.text.TextUtils;
 import android.text.TextWatcher;
 import android.text.style.RelativeSizeSpan;
+import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.KeyEvent;
@@ -60,13 +60,15 @@
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.OnPreDrawListener;
 import android.widget.AdapterView;
 import android.widget.BaseAdapter;
 import android.widget.EditText;
 import android.widget.ImageView;
+import android.widget.LinearLayout;
 import android.widget.ListView;
 import android.widget.PopupMenu;
-import android.widget.RelativeLayout;
 import android.widget.TextView;
 
 import com.android.contacts.common.CallUtil;
@@ -76,6 +78,8 @@
 import com.android.contacts.common.util.PhoneNumberFormatter;
 import com.android.contacts.common.util.StopWatch;
 import com.android.dialer.DialtactsActivity;
+import com.android.dialer.NeededForReflection;
+import com.android.dialer.NewDialtactsActivity;
 import com.android.dialer.R;
 import com.android.dialer.SpecialCharSequenceMgr;
 import com.android.dialer.database.DialerDatabaseHelper;
@@ -86,8 +90,6 @@
 import com.android.phone.common.HapticFeedback;
 import com.google.common.annotations.VisibleForTesting;
 
-import java.util.List;
-
 /**
  * Fragment that displays a twelve-key phone dialpad.
  */
@@ -96,10 +98,42 @@
         View.OnLongClickListener, View.OnKeyListener,
         AdapterView.OnItemClickListener, TextWatcher,
         PopupMenu.OnMenuItemClickListener,
-        DialpadImageButton.OnPressedListener,
-        SmartDialLoaderTask.SmartDialLoaderCallback {
+        DialpadImageButton.OnPressedListener {
     private static final String TAG = NewDialpadFragment.class.getSimpleName();
 
+    /**
+     * LinearLayout with getter and setter methods for the translationY property using floats,
+     * for animation purposes.
+     */
+    public static class DialpadSlidingLinearLayout extends LinearLayout {
+
+        public DialpadSlidingLinearLayout(Context context) {
+            super(context);
+        }
+
+        public DialpadSlidingLinearLayout(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+
+        public DialpadSlidingLinearLayout(Context context, AttributeSet attrs, int defStyle) {
+            super(context, attrs, defStyle);
+        }
+
+        @NeededForReflection
+        public float getYFraction() {
+            return getTranslationY() / getHeight();
+        }
+
+        @NeededForReflection
+        public void setYFraction(float yFraction) {
+            setTranslationY(yFraction * getHeight());
+        }
+    }
+
+    public interface OnDialpadQueryChangedListener {
+        void onDialpadQueryChanged(String query);
+    }
+
     private static final boolean DEBUG = DialtactsActivity.DEBUG;
 
     private static final String EMPTY_NUMBER = "";
@@ -118,6 +152,10 @@
 
     private ContactsPreferences mContactsPrefs;
 
+    private OnDialpadQueryChangedListener mDialpadQueryListener;
+
+    private View mFragmentView;
+
     /**
      * View (usually FrameLayout) containing mDigits field. This can be null, in which mDigits
      * isn't enclosed by the container.
@@ -145,25 +183,6 @@
     private ListView mDialpadChooser;
     private DialpadChooserAdapter mDialpadChooserAdapter;
 
-    /** Will be set only if the view has the smart dialing section. */
-    private RelativeLayout mSmartDialContainer;
-
-    /**
-     * Will be set only if the view has the smart dialing section.
-     */
-    private SmartDialController mSmartDialAdapter;
-
-    /**
-     * Use latin character map by default
-     */
-    private SmartDialMap mSmartDialMap = new LatinSmartDialMap();
-
-    /**
-     * Master switch controlling whether or not smart dialing is enabled, and whether the
-     * smart dialing suggestion strip is visible.
-     */
-    private boolean mSmartDialEnabled = false;
-
     private DialerDatabaseHelper mDialerDatabaseHelper;
 
     /**
@@ -287,8 +306,10 @@
             mDigits.setCursorVisible(false);
         }
 
+        if (mDialpadQueryListener != null) {
+            mDialpadQueryListener.onDialpadQueryChanged(mDigits.getText().toString());
+        }
         updateDialAndDeleteButtonEnabledState();
-        loadSmartDialEntries();
     }
 
     @Override
@@ -308,8 +329,6 @@
              Log.e(TAG, "Vibrate control bool missing.", nfe);
         }
 
-        setHasOptionsMenu(true);
-
         mProhibitedPhoneNumberRegexp = getResources().getString(
                 R.string.config_prohibited_phone_number_regexp);
 
@@ -320,7 +339,29 @@
 
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
-        View fragmentView = inflater.inflate(R.layout.dialpad_fragment, container, false);
+        View fragmentView = inflater.inflate(R.layout.new_dialpad_fragment, container, false);
+        mFragmentView = fragmentView;
+        mFragmentView.buildLayer();
+
+        // TODO krelease: Get rid of this ugly hack which is to prevent the first frame of the
+        // animation from drawing the fragment at translationY = 0
+        final ViewTreeObserver vto = mFragmentView.getViewTreeObserver();
+        final OnPreDrawListener preDrawListener = new OnPreDrawListener() {
+
+            @Override
+            public boolean onPreDraw() {
+                if (isHidden()) return true;
+                if (mFragmentView.getTranslationY() == 0) {
+                    ((DialpadSlidingLinearLayout) mFragmentView).setYFraction(0.67f);
+                }
+                final ViewTreeObserver vto = mFragmentView.getViewTreeObserver();
+                vto.removeOnPreDrawListener(this);
+                return true;
+            }
+
+        };
+
+        vto.addOnPreDrawListener(preDrawListener);
 
         // Load up the resources for the text field.
         Resources r = getResources();
@@ -379,15 +420,6 @@
         mDialpadChooser = (ListView) fragmentView.findViewById(R.id.dialpadChooser);
         mDialpadChooser.setOnItemClickListener(this);
 
-        // Smart dial container. This is null if in landscape mode since it is not present
-        // in the landscape dialer layout.
-        mSmartDialContainer = (RelativeLayout) fragmentView.findViewById(
-                R.id.dialpad_smartdial_container);
-
-        if (mSmartDialContainer != null) {
-            mSmartDialAdapter = new SmartDialController(getActivity(), mSmartDialContainer,
-                    new OnSmartDialShortClick(), new OnSmartDialLongClick());
-        }
         return fragmentView;
     }
 
@@ -560,6 +592,9 @@
     public void onResume() {
         super.onResume();
 
+        final NewDialtactsActivity activity = (NewDialtactsActivity) getActivity();
+        mDialpadQueryListener = activity;
+
         final StopWatch stopWatch = StopWatch.start("Dialpad.onResume");
 
         // Query the last dialed number. Do it first because hitting
@@ -574,10 +609,6 @@
         mDTMFToneEnabled = Settings.System.getInt(contentResolver,
                 Settings.System.DTMF_TONE_WHEN_DIALING, 1) == 1;
 
-        // retrieve dialpad autocomplete setting
-        mSmartDialEnabled = Settings.Secure.getInt(contentResolver,
-                Settings.Secure.DIALPAD_AUTOCOMPLETE, 0) == 1 && mSmartDialContainer != null;
-
         stopWatch.lap("dtwd");
 
         // Retrieve the haptic feedback setting.
@@ -678,6 +709,7 @@
     @Override
     public void onStop() {
         super.onStop();
+
         if (mClearDigitsOnStop) {
             mClearDigitsOnStop = false;
             mDigits.getText().clear();
@@ -690,28 +722,6 @@
         outState.putBoolean(PREF_DIGITS_FILLED_BY_INTENT, mDigitsFilledByIntent);
     }
 
-    @Override
-    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
-        super.onCreateOptionsMenu(menu, inflater);
-        // Landscape dialer uses the real actionbar menu, whereas portrait uses a fake one
-        // that is created using constructPopupMenu()
-        if (OrientationUtil.isLandscape(this.getActivity()) ||
-                ViewConfiguration.get(getActivity()).hasPermanentMenuKey() &&
-                isLayoutReady() && mDialpadChooser != null) {
-            inflater.inflate(R.menu.dialpad_options, menu);
-        }
-    }
-
-    @Override
-    public void onPrepareOptionsMenu(Menu menu) {
-        // Hardware menu key should be available and Views should already be ready.
-        if (OrientationUtil.isLandscape(this.getActivity()) ||
-                ViewConfiguration.get(getActivity()).hasPermanentMenuKey() &&
-                isLayoutReady() && mDialpadChooser != null) {
-            setupMenuItems(menu);
-        }
-    }
-
     private void setupMenuItems(Menu menu) {
         final MenuItem callSettingsMenuItem = menu.findItem(R.id.menu_call_settings_dialpad);
         final MenuItem addToContactMenuItem = menu.findItem(R.id.menu_add_contacts);
@@ -1481,24 +1491,6 @@
         return getTelephonyManager().getCallState() == TelephonyManager.CALL_STATE_OFFHOOK;
     }
 
-    /**
-     * Returns true whenever any one of the options from the menu is selected.
-     * Code changes to support dialpad options
-     */
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        switch (item.getItemId()) {
-            case R.id.menu_2s_pause:
-                updateDialString(PAUSE);
-                return true;
-            case R.id.menu_add_wait:
-                updateDialString(WAIT);
-                return true;
-            default:
-                return false;
-        }
-    }
-
     @Override
     public boolean onMenuItemClick(MenuItem item) {
         return onOptionsItemSelected(item);
@@ -1507,6 +1499,7 @@
     /**
      * Updates the dial string (mDigits) after inserting a Pause character (,)
      * or Wait character (;).
+     * TODO krelease: add new dialpad buttons to add PAUSE and WAIT characters
      */
     private void updateDialString(char newDigit) {
         if(newDigit != WAIT && newDigit != PAUSE) {
@@ -1654,79 +1647,22 @@
         return intent;
     }
 
-    private String mLastDigitsForSmartDial;
-
-    private void loadSmartDialEntries() {
-        if (!mSmartDialEnabled || mSmartDialAdapter == null) {
-            // No smart dial views.  Landscape?
-            return;
-        }
-
-        // Update only when the digits have changed.
-        final String digits = SmartDialNameMatcher.normalizeNumber(mDigits.getText().toString(),
-                mSmartDialMap);
-        if (TextUtils.equals(digits, mLastDigitsForSmartDial)) {
-            return;
-        }
-        mLastDigitsForSmartDial = digits;
-
-        if (digits.length() < 1) {
-            mSmartDialAdapter.clear();
-        } else {
-            final SmartDialLoaderTask task = new SmartDialLoaderTask(this, digits, getActivity());
-            task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, new String[] {});
-        }
+    private void initializeSmartDialingState() {
+        // Handle smart dialing related state
+        // TODO krelease: This should probably be moved to somewhere more appropriate, maybe
+        // into DialtactsActivity
+        mDialerDatabaseHelper.startSmartDialUpdateThread();
     }
 
     @Override
-    public void setSmartDialAdapterEntries(List<SmartDialEntry> data, String query) {
-        if (data == null || query == null || !query.equals(mLastDigitsForSmartDial)) {
-            return;
-        }
-        mSmartDialAdapter.setEntries(data);
-    }
-
-    private void initializeSmartDialingState() {
-        // Handle smart dialing related state
-        if (mSmartDialEnabled) {
-            mSmartDialContainer.setVisibility(View.VISIBLE);
-
-            if (DEBUG) {
-                Log.w(TAG, "Creating smart dial database");
-            }
-            mDialerDatabaseHelper.startSmartDialUpdateThread();
+    public void onHiddenChanged(boolean hidden) {
+        super.onHiddenChanged(hidden);
+        final NewDialtactsActivity activity = (NewDialtactsActivity) getActivity();
+        if (activity == null) return;
+        if (hidden) {
+            activity.showSearchBar();
         } else {
-            if (mSmartDialContainer != null) {
-                mSmartDialContainer.setVisibility(View.GONE);
-            }
-        }
-    }
-
-    private class OnSmartDialLongClick implements View.OnLongClickListener {
-        @Override
-        public boolean onLongClick(View view) {
-            final SmartDialEntry entry = (SmartDialEntry) view.getTag();
-            if (entry == null) return false; // just in case.
-            mClearDigitsOnStop = true;
-            // Show the phone number disambiguation dialog without using the primary
-            // phone number so that the user can decide which number to call
-            PhoneNumberInteraction.startInteractionForPhoneCall(
-                    (TransactionSafeActivity) getActivity(), entry.contactUri, false);
-            return true;
-        }
-    }
-
-    private class OnSmartDialShortClick implements View.OnClickListener {
-        @Override
-        public void onClick(View view) {
-            final SmartDialEntry entry = (SmartDialEntry) view.getTag();
-            if (entry == null) return; // just in case.
-            // Dial the displayed phone number immediately
-            final Intent intent = CallUtil.getCallIntent(entry.phoneNumber.toString(),
-                    (getActivity() instanceof DialtactsActivity ?
-                            ((DialtactsActivity) getActivity()).getCallOrigin() : null));
-            startActivity(intent);
-            mClearDigitsOnStop = true;
+            activity.hideSearchBar();
         }
     }
 }
diff --git a/src/com/android/dialer/dialpad/SmartDialCursorLoader.java b/src/com/android/dialer/dialpad/SmartDialCursorLoader.java
new file mode 100644
index 0000000..715f1e7
--- /dev/null
+++ b/src/com/android/dialer/dialpad/SmartDialCursorLoader.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2013 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.dialpad;
+
+import android.content.AsyncTaskLoader;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.telephony.PhoneNumberUtils;
+import android.util.Log;
+
+import com.android.dialer.database.DialerDatabaseHelper;
+import com.android.dialer.database.DialerDatabaseHelper.ContactNumber;
+
+import java.util.ArrayList;
+
+/**
+ * Implements a Loader<Cursor> class to asynchronously load SmartDial search results.
+ */
+public class SmartDialCursorLoader extends AsyncTaskLoader<Cursor> {
+
+    private final String TAG = SmartDialCursorLoader.class.getSimpleName();
+    private final boolean DEBUG = false;
+
+    private final Context mContext;
+
+    private Cursor mCursor;
+
+    private String mQuery;
+    private SmartDialNameMatcher mNameMatcher;
+
+    /** Constructs the columns of the cursor to be used. */
+    public static class SmartDialPhoneQuery {
+        public static final String[] PROJECTION_PRIMARY = new String[] {
+            Phone._ID,                          // 0
+            Phone.TYPE,                         // 1
+            Phone.LABEL,                        // 2
+            Phone.NUMBER,                       // 3
+            Phone.CONTACT_ID,                   // 4
+            Phone.LOOKUP_KEY,                   // 5
+            Phone.PHOTO_ID,                     // 6
+            Phone.DISPLAY_NAME_PRIMARY,         // 7
+        };
+
+        public static final int SMARTDIAL_ID          = 0;
+        public static final int SMARTDIAL_TYPE         = 1;
+        public static final int SMARTDIAL_LABEL        = 2;
+        public static final int SMARTDIAL_NUMBER       = 3;
+        public static final int SMARTDIAL_CONTACT_ID   = 4;
+        public static final int SMARTDIAL_LOOKUP_KEY   = 5;
+        public static final int SMARTDIAL_PHOTO_ID     = 6;
+        public static final int SMARTDIAL_DISPLAY_NAME = 7;
+    }
+
+    public SmartDialCursorLoader(Context context) {
+        super(context);
+        mContext = context;
+    }
+
+    /**
+     * Configures the query string to be used to find SmartDial matches.
+     * @param query The query string user typed.
+     */
+    public void configureQuery(String query) {
+        if (DEBUG) {
+            Log.v(TAG, "Configure new query to be " + query);
+        }
+        mQuery = query;
+
+        /** Constructs a name matcher object for matching names. */
+        mNameMatcher = new SmartDialNameMatcher(PhoneNumberUtils.normalizeNumber(query),
+            SmartDialPrefix.getMap());
+    }
+
+    /**
+     * Queries the SmartDial database and loads results in background.
+     * @return Cursor of contacts that matches the SmartDial query.
+     */
+    @Override
+    public Cursor loadInBackground() {
+        if (DEBUG) {
+            Log.v(TAG, "Load in background " + mQuery);
+        }
+
+        /** Loads results from the database helper. */
+        DialerDatabaseHelper dialerDatabaseHelper = DialerDatabaseHelper.getInstance(mContext);
+        final ArrayList<ContactNumber> allMatches = dialerDatabaseHelper.getLooseMatches(mQuery,
+                mNameMatcher);
+
+        if (DEBUG) {
+            Log.v(TAG, "Loaded matches " + String.valueOf(allMatches.size()));
+        }
+
+        /** Constructs a cursor for the returned array of results. */
+        final MatrixCursor cursor = new MatrixCursor(SmartDialPhoneQuery.PROJECTION_PRIMARY);
+        for (ContactNumber contact : allMatches) {
+            cursor.addRow(new Object[] {contact.dataId, null, null, contact.phoneNumber, contact.id,
+                    contact.lookupKey, contact.photoId, contact.displayName});
+        }
+        return cursor;
+    }
+
+    @Override
+    public void deliverResult(Cursor cursor) {
+        if (isReset()) {
+            /** The Loader has been reset; ignore the result and invalidate the data. */
+            releaseResources(cursor);
+            return;
+        }
+
+        /** Hold a reference to the old data so it doesn't get garbage collected. */
+        Cursor oldCursor = mCursor;
+        mCursor = cursor;
+
+        if (isStarted()) {
+            /** If the Loader is in a started state, deliver the results to the client. */
+            super.deliverResult(cursor);
+        }
+
+        /** Invalidate the old data as we don't need it any more. */
+        if (oldCursor != null && oldCursor != cursor) {
+            releaseResources(oldCursor);
+        }
+    }
+
+    @Override
+    protected void onStartLoading() {
+        if (mCursor != null) {
+            /** Deliver any previously loaded data immediately. */
+            deliverResult(mCursor);
+        }
+        if (mCursor == null) {
+            /** Force loads every time as our results change with queries. */
+            forceLoad();
+        }
+    }
+
+    @Override
+    protected void onStopLoading() {
+        /** The Loader is in a stopped state, so we should attempt to cancel the current load. */
+        cancelLoad();
+    }
+
+    @Override
+    protected void onReset() {
+        /** Ensure the loader has been stopped. */
+        onStopLoading();
+
+        /** Release all previously saved query results. */
+        if (mCursor != null) {
+            releaseResources(mCursor);
+            mCursor = null;
+        }
+    }
+
+    @Override
+    public void onCanceled(Cursor cursor) {
+        super.onCanceled(cursor);
+
+        /** The load has been canceled, so we should release the resources associated with 'data'.*/
+        releaseResources(cursor);
+    }
+
+    private void releaseResources(Cursor cursor) {
+        cursor.close();
+    }
+}
diff --git a/src/com/android/dialer/dialpad/SmartDialMatchPosition.java b/src/com/android/dialer/dialpad/SmartDialMatchPosition.java
index 4348746..452ac91 100644
--- a/src/com/android/dialer/dialpad/SmartDialMatchPosition.java
+++ b/src/com/android/dialer/dialpad/SmartDialMatchPosition.java
@@ -28,7 +28,7 @@
  * in the query. Used by {@link SmartDialController} to highlight certain parts of the contact's
  * display name to indicate that those ranges matched the user's query.
  */
-class SmartDialMatchPosition {
+public class SmartDialMatchPosition {
     public int start;
     public int end;
 
diff --git a/src/com/android/dialer/dialpad/SmartDialNameMatcher.java b/src/com/android/dialer/dialpad/SmartDialNameMatcher.java
index fe88e93..c160bd2 100644
--- a/src/com/android/dialer/dialpad/SmartDialNameMatcher.java
+++ b/src/com/android/dialer/dialpad/SmartDialNameMatcher.java
@@ -45,10 +45,13 @@
 
     private final ArrayList<SmartDialMatchPosition> mMatchPositions = Lists.newArrayList();
 
-    private static final SmartDialMap LATIN_SMART_DIAL_MAP = new LatinSmartDialMap();
+    public static final SmartDialMap LATIN_SMART_DIAL_MAP = new LatinSmartDialMap();
 
     private final SmartDialMap mMap;
 
+    private String mNameMatchMask = "";
+    private String mPhoneNumberMatchMask = "";
+
     @VisibleForTesting
     public SmartDialNameMatcher(String query) {
         this(query, LATIN_SMART_DIAL_MAP);
@@ -60,6 +63,29 @@
     }
 
     /**
+     * Constructs empty highlight mask. Bit 0 at a position means there is no match, Bit 1 means
+     * there is a match and should be highlighted in the TextView.
+     * @param builder StringBuilder object
+     * @param length Length of the desired mask.
+     */
+    private void constructEmptyMask(StringBuilder builder, int length) {
+        for (int i = 0; i < length; ++i) {
+            builder.append("0");
+        }
+    }
+
+    /**
+     * Replaces the 0-bit at a position with 1-bit, indicating that there is a match.
+     * @param builder StringBuilder object.
+     * @param matchPos Match Positions to mask as 1.
+     */
+    private void replaceBitInMask(StringBuilder builder, SmartDialMatchPosition matchPos) {
+        for (int i = matchPos.start; i < matchPos.end; ++i) {
+            builder.replace(i, i + 1, "1");
+        }
+    }
+
+    /**
      * Strips a phone number of unnecessary characters (spaces, dashes, etc.)
      *
      * @param number Phone number we want to normalize
@@ -98,6 +124,10 @@
      */
     @VisibleForTesting
     public SmartDialMatchPosition matchesNumber(String phoneNumber, String query, boolean useNanp) {
+        StringBuilder builder = new StringBuilder();
+        constructEmptyMask(builder, phoneNumber.length());
+        mPhoneNumberMatchMask = builder.toString();
+
         // Try matching the number as is
         SmartDialMatchPosition matchPos = matchesNumberWithOffset(phoneNumber, query, 0);
         if (matchPos == null) {
@@ -105,6 +135,10 @@
                     SmartDialPrefix.parsePhoneNumber(phoneNumber);
 
             if (phoneNumberTokens == null) {
+                if (matchPos != null) {
+                    replaceBitInMask(builder, matchPos);
+                    mPhoneNumberMatchMask = builder.toString();
+                }
                 return matchPos;
             }
             if (phoneNumberTokens.countryCodeOffset != 0) {
@@ -116,10 +150,26 @@
                         phoneNumberTokens.nanpCodeOffset);
             }
         }
+        if (matchPos != null) {
+            replaceBitInMask(builder, matchPos);
+            mPhoneNumberMatchMask = builder.toString();
+        }
         return matchPos;
     }
 
     /**
+     * Matches a phone number against the saved query, taking care of formatting characters and also
+     * taking into account country code prefixes and special NANP number treatment.
+     *
+     * @param phoneNumber - Raw phone number
+     * @return {@literal null} if the number and the query don't match, a valid
+     *         SmartDialMatchPosition with the matching positions otherwise
+     */
+    public SmartDialMatchPosition matchesNumber(String phoneNumber) {
+        return matchesNumber(phoneNumber, mQuery, true);
+    }
+
+    /**
      * Matches a phone number against a query, taking care of formatting characters and also
      * taking into account country code prefixes and special NANP number treatment.
      *
@@ -210,6 +260,9 @@
     @VisibleForTesting
     boolean matchesCombination(String displayName, String query,
             ArrayList<SmartDialMatchPosition> matchList) {
+        StringBuilder builder = new StringBuilder();
+        constructEmptyMask(builder, displayName.length());
+        mNameMatchMask = builder.toString();
         final int nameLength = displayName.length();
         final int queryLength = query.length();
 
@@ -286,6 +339,10 @@
                         // one so if we find a full token match, we can return right away
                         matchList.add(new SmartDialMatchPosition(
                                 tokenStart, queryLength + tokenStart + seperatorCount));
+                        for (SmartDialMatchPosition match : matchList) {
+                            replaceBitInMask(builder, match);
+                        }
+                        mNameMatchMask = builder.toString();
                         return true;
                     } else if (ALLOW_INITIAL_MATCH && queryStart < INITIAL_LENGTH_LIMIT) {
                         // we matched the first character.
@@ -343,6 +400,10 @@
         // then partial will always be empty.
         if (!partial.isEmpty()) {
             matchList.addAll(partial);
+            for (SmartDialMatchPosition match : matchList) {
+                replaceBitInMask(builder, match);
+            }
+            mNameMatchMask = builder.toString();
             return true;
         }
         return false;
@@ -359,6 +420,14 @@
         return new ArrayList<SmartDialMatchPosition>(mMatchPositions);
     }
 
+    public String getNameMatchPositionsInString() {
+        return mNameMatchMask;
+    }
+
+    public String getNumberMatchPositionsInString() {
+        return mPhoneNumberMatchMask;
+    }
+
     public String getQuery() {
         return mQuery;
     }
diff --git a/src/com/android/dialer/list/NewPhoneFavoriteFragment.java b/src/com/android/dialer/list/NewPhoneFavoriteFragment.java
index e694d60..db2999c 100644
--- a/src/com/android/dialer/list/NewPhoneFavoriteFragment.java
+++ b/src/com/android/dialer/list/NewPhoneFavoriteFragment.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2013 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.
@@ -27,14 +27,10 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
-import android.provider.ContactsContract;
 import android.provider.ContactsContract.Directory;
 import android.provider.Settings;
 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.ViewGroup;
@@ -47,18 +43,16 @@
 
 import com.android.contacts.common.ContactPhotoManager;
 import com.android.contacts.common.ContactTileLoaderFactory;
-import com.android.contacts.common.dialog.ClearFrequentsDialog;
-import com.android.contacts.common.list.ContactListFilter;
-import com.android.contacts.common.list.ContactListFilterController;
+import com.android.contacts.common.GeoUtil;
 import com.android.contacts.common.list.ContactListItemView;
-import com.android.contacts.common.list.ContactTileAdapter;
 import com.android.contacts.common.list.ContactTileView;
 import com.android.contacts.common.list.PhoneNumberListAdapter;
 import com.android.contacts.common.preference.ContactsPreferences;
-import com.android.contacts.common.util.AccountFilterUtil;
-import com.android.contacts.common.interactions.ImportExportDialogFragment;
-import com.android.dialer.DialtactsActivity;
+import com.android.dialer.NewDialtactsActivity;
 import com.android.dialer.R;
+import com.android.dialer.calllog.ContactInfoHelper;
+import com.android.dialer.calllog.NewCallLogAdapter;
+import com.android.dialer.calllog.CallLogQueryHandler;
 
 /**
  * Fragment for Phone UI's favorite screen.
@@ -68,7 +62,8 @@
  * {@link com.android.contacts.common.list.PhoneNumberListAdapter} into one unified list using {@link PhoneFavoriteMergedAdapter}.
  * A contact filter header is also inserted between those adapters' results.
  */
-public class NewPhoneFavoriteFragment extends Fragment implements OnItemClickListener {
+public class NewPhoneFavoriteFragment extends Fragment implements OnItemClickListener,
+        CallLogQueryHandler.Listener, NewCallLogAdapter.CallFetcher {
     private static final String TAG = NewPhoneFavoriteFragment.class.getSimpleName();
     private static final boolean DEBUG = false;
 
@@ -78,9 +73,9 @@
     private static int LOADER_ID_CONTACT_TILE = 1;
     private static int LOADER_ID_ALL_CONTACTS = 2;
 
-    private static final String KEY_FILTER = "filter";
-
-    private static final int REQUEST_CODE_ACCOUNT_FILTER = 1;
+    public interface OnPhoneFavoriteFragmentStartedListener {
+        public void onPhoneFavoriteFragmentStarted();
+    }
 
     public interface Listener {
         public void onContactSelected(Uri contactUri);
@@ -113,11 +108,7 @@
             mAllContactsLoaderStarted = true;
 
             // Show the filter header with "loading" state.
-            updateFilterHeaderView();
             mAccountFilterHeader.setVisibility(View.VISIBLE);
-
-            // invalidate the options menu if needed
-            invalidateOptionsMenuIfNeeded();
         }
 
         @Override
@@ -139,7 +130,6 @@
         public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
             if (DEBUG) Log.d(TAG, "AllContactsLoaderListener#onLoadFinished");
             mAllContactsAdapter.changeCursor(0, data);
-            updateFilterHeaderView();
             mHandler.removeMessages(MESSAGE_SHOW_LOADING_EFFECT);
             mLoadingView.setVisibility(View.VISIBLE);
         }
@@ -171,16 +161,6 @@
         }
     }
 
-    private class FilterHeaderClickListener implements OnClickListener {
-        @Override
-        public void onClick(View view) {
-            AccountFilterUtil.startAccountFilterActivityForResult(
-                    NewPhoneFavoriteFragment.this,
-                    REQUEST_CODE_ACCOUNT_FILTER,
-                    mFilter);
-        }
-    }
-
     private class ContactsPreferenceChangeListener
             implements ContactsPreferences.ChangeListener {
         @Override
@@ -204,10 +184,13 @@
                 mListView.setFastScrollAlwaysVisible(shouldShow);
                 mShouldShowFastScroller = shouldShow;
             }
+
+
         }
 
         @Override
         public void onScrollStateChanged(AbsListView view, int scrollState) {
+            mActivityScrollListener.onListFragmentScrollStateChange(scrollState);
         }
     }
 
@@ -225,10 +208,15 @@
     };
 
     private Listener mListener;
-    private PhoneFavoriteMergedAdapter mAdapter;
-    private ContactTileAdapter mContactTileAdapter;
+
+    private OnListFragmentScrolledListener mActivityScrollListener;
+    private NewPhoneFavoriteMergedAdapter mAdapter;
+    private PhoneFavoritesTileAdapter mContactTileAdapter;
     private PhoneNumberListAdapter mAllContactsAdapter;
 
+    private NewCallLogAdapter mCallLogAdapter;
+    private CallLogQueryHandler mCallLogQueryHandler;
+
     /**
      * true when the loader for {@link PhoneNumberListAdapter} has started already.
      */
@@ -241,7 +229,6 @@
     private boolean mAllContactsForceReload;
 
     private ContactsPreferences mContactsPrefs;
-    private ContactListFilter mFilter;
 
     private TextView mEmptyView;
     private ListView mListView;
@@ -263,7 +250,6 @@
             new ContactTileLoaderListener();
     private final LoaderManager.LoaderCallbacks<Cursor> mAllContactsLoaderListener =
             new AllContactsLoaderListener();
-    private final OnClickListener mFilterHeaderClickListener = new FilterHeaderClickListener();
     private final ContactsPreferenceChangeListener mContactsPreferenceChangeListener =
             new ContactsPreferenceChangeListener();
     private final ScrollListener mScrollListener = new ScrollListener();
@@ -281,9 +267,9 @@
         // We don't construct the resultant adapter at this moment since it requires LayoutInflater
         // that will be available on onCreateView().
 
-        mContactTileAdapter = new ContactTileAdapter(activity, mContactTileAdapterListener,
-                getResources().getInteger(R.integer.contact_tile_column_count_in_favorites),
-                ContactTileAdapter.DisplayType.STREQUENT_PHONE_ONLY);
+        mContactTileAdapter = new PhoneFavoritesTileAdapter(activity, mContactTileAdapterListener,
+                getResources().getInteger(R.integer.contact_tile_column_count_in_favorites_new),
+                1);
         mContactTileAdapter.setPhotoLoader(ContactPhotoManager.getInstance(activity));
 
         // Setup the "all" adapter manually. See also the setup logic in ContactEntryListFragment.
@@ -293,7 +279,7 @@
         mAllContactsAdapter.setSearchMode(false);
         mAllContactsAdapter.setIncludeProfile(false);
         mAllContactsAdapter.setSelectionVisible(false);
-        mAllContactsAdapter.setDarkTheme(true);
+        mAllContactsAdapter.setDarkTheme(false);
         mAllContactsAdapter.setPhotoLoader(ContactPhotoManager.getInstance(activity));
         // Disable directory header.
         mAllContactsAdapter.setHasHeader(0, false);
@@ -318,27 +304,27 @@
     public void onCreate(Bundle savedState) {
         if (DEBUG) Log.d(TAG, "onCreate()");
         super.onCreate(savedState);
-        if (savedState != null) {
-            mFilter = savedState.getParcelable(KEY_FILTER);
 
-            if (mFilter != null) {
-                mAllContactsAdapter.setFilter(mFilter);
-            }
-        }
+        mCallLogQueryHandler = new CallLogQueryHandler(getActivity().getContentResolver(),
+                this, 1);
+        final String currentCountryIso = GeoUtil.getCurrentCountryIso(getActivity());
+        mCallLogAdapter = new NewCallLogAdapter(getActivity(), this,
+                new ContactInfoHelper(getActivity(), currentCountryIso));
         setHasOptionsMenu(true);
     }
 
     @Override
-    public void onSaveInstanceState(Bundle outState) {
-        super.onSaveInstanceState(outState);
-        outState.putParcelable(KEY_FILTER, mFilter);
+    public void onResume() {
+        super.onResume();
+        mCallLogQueryHandler.fetchCalls(CallLogQueryHandler.CALL_TYPE_ALL);
+        mCallLogAdapter.setLoading(true);
     }
 
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
         final View listLayout = inflater.inflate(
-                R.layout.phone_contact_tile_list, container, false);
+                R.layout.new_phone_favorites_fragment, container, false);
 
         mListView = (ListView) listLayout.findViewById(R.id.contact_tile_list);
         mListView.setItemsCanFocus(true);
@@ -347,18 +333,18 @@
         mListView.setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_RIGHT);
         mListView.setScrollBarStyle(ListView.SCROLLBARS_OUTSIDE_OVERLAY);
 
+        // TODO krelease: Don't show this header anymore
         // Create the account filter header but keep it hidden until "all" contacts are loaded.
         mAccountFilterHeaderContainer = new FrameLayout(getActivity(), null);
         mAccountFilterHeader = inflater.inflate(R.layout.account_filter_header_for_phone_favorite,
                 mListView, false);
-        mAccountFilterHeader.setOnClickListener(mFilterHeaderClickListener);
         mAccountFilterHeaderContainer.addView(mAccountFilterHeader);
 
         mLoadingView = inflater.inflate(R.layout.phone_loading_contacts, mListView, false);
 
-        mAdapter = new PhoneFavoriteMergedAdapter(getActivity(),
+        mAdapter = new NewPhoneFavoriteMergedAdapter(getActivity(),
                 mContactTileAdapter, mAccountFilterHeaderContainer, mAllContactsAdapter,
-                mLoadingView);
+                mCallLogAdapter, mLoadingView);
 
         mListView.setAdapter(mAdapter);
 
@@ -370,68 +356,48 @@
         mEmptyView.setText(getString(R.string.listTotalAllContactsZero));
         mListView.setEmptyView(mEmptyView);
 
-        updateFilterHeaderView();
-
         return listLayout;
     }
 
+    // TODO krelease: update the options menu when displaying the popup menu instead. We could
+    // possibly get rid of this method entirely.
     private boolean isOptionsMenuChanged() {
         return mOptionsMenuHasFrequents != hasFrequents();
     }
 
-    private void invalidateOptionsMenuIfNeeded() {
-        if (isOptionsMenuChanged()) {
-            getActivity().invalidateOptionsMenu();
-        }
-    }
-
-    @Override
-    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
-        super.onCreateOptionsMenu(menu, inflater);
-        inflater.inflate(R.menu.phone_favorite_options, menu);
-    }
-
+    // TODO krelease: Configure the menu items properly. Since the menu items show up as a PopupMenu
+    // rather than a normal actionbar menu, the initialization should be done there.
+    /*
     @Override
     public void onPrepareOptionsMenu(Menu menu) {
         final MenuItem clearFrequents = menu.findItem(R.id.menu_clear_frequents);
         mOptionsMenuHasFrequents = hasFrequents();
         clearFrequents.setVisible(mOptionsMenuHasFrequents);
-    }
+    }*/
 
     private boolean hasFrequents() {
         return mContactTileAdapter.getNumFrequents() > 0;
     }
 
     @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        switch (item.getItemId()) {
-            case R.id.menu_import_export:
-                // We hard-code the "contactsAreAvailable" argument because doing it properly would
-                // involve querying a {@link ProviderStatusLoader}, which we don't want to do right
-                // now in Dialtacts for (potential) performance reasons.  Compare with how it is
-                // done in {@link PeopleActivity}.
-                ImportExportDialogFragment.show(getFragmentManager(), true,
-                        DialtactsActivity.class);
-                return true;
-            case R.id.menu_accounts:
-                final Intent intent = new Intent(Settings.ACTION_SYNC_SETTINGS);
-                intent.putExtra(Settings.EXTRA_AUTHORITIES, new String[] {
-                    ContactsContract.AUTHORITY
-                });
-                intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
-                startActivity(intent);
-                return true;
-            case R.id.menu_clear_frequents:
-                ClearFrequentsDialog.show(getFragmentManager());
-                return true;
-        }
-        return false;
-    }
-
-    @Override
     public void onStart() {
         super.onStart();
 
+        final Activity activity = getActivity();
+
+        try {
+            ((OnPhoneFavoriteFragmentStartedListener) activity).onPhoneFavoriteFragmentStarted();
+        } catch (ClassCastException e) {
+            throw new ClassCastException(activity.toString()
+                    + " must implement OnPhoneFavoriteFragmentStartedListener");
+        }
+
+        try {
+            mActivityScrollListener = (OnListFragmentScrolledListener) activity;
+        } catch (ClassCastException e) {
+            throw new ClassCastException(activity.toString()
+                    + " must implement OnListFragmentScrolledListener");
+        }
         mContactsPrefs.registerChangeListener(mContactsPreferenceChangeListener);
 
         // If ContactsPreferences has changed, we need to reload "all" contacts with the new
@@ -478,18 +444,6 @@
         }
     }
 
-    @Override
-    public void onActivityResult(int requestCode, int resultCode, Intent data) {
-        if (requestCode == REQUEST_CODE_ACCOUNT_FILTER) {
-            if (getActivity() != null) {
-                AccountFilterUtil.handleAccountFilterResult(
-                        ContactListFilterController.getInstance(getActivity()), resultCode, data);
-            } else {
-                Log.e(TAG, "getActivity() returns null during Fragment#onActivityResult()");
-            }
-        }
-    }
-
     private boolean loadContactsPreferences() {
         if (mContactsPrefs == null || mAllContactsAdapter == null) {
             return false;
@@ -536,38 +490,24 @@
         getLoaderManager().restartLoader(LOADER_ID_ALL_CONTACTS, null, mAllContactsLoaderListener);
     }
 
-    private void updateFilterHeaderView() {
-        final ContactListFilter filter = getFilter();
-        if (mAccountFilterHeader == null || mAllContactsAdapter == null || filter == null) {
-            return;
-        }
-        AccountFilterUtil.updateAccountFilterTitleForPhone(mAccountFilterHeader, filter, true);
-    }
-
-    public ContactListFilter getFilter() {
-        return mFilter;
-    }
-
-    public void setFilter(ContactListFilter filter) {
-        if ((mFilter == null && filter == null) || (mFilter != null && mFilter.equals(filter))) {
-            return;
-        }
-
-        if (DEBUG) {
-            Log.d(TAG, "setFilter(). old filter (" + mFilter
-                    + ") will be replaced with new filter (" + filter + ")");
-        }
-
-        mFilter = filter;
-
-        if (mAllContactsAdapter != null) {
-            mAllContactsAdapter.setFilter(mFilter);
-            requestReloadAllContacts();
-            updateFilterHeaderView();
-        }
-    }
-
     public void setListener(Listener listener) {
         mListener = listener;
     }
+
+    // TODO krelease: Implement this
+    @Override
+    public void onVoicemailStatusFetched(Cursor statusCursor) {
+    }
+
+    @Override
+    public void onCallsFetched(Cursor cursor) {
+        mCallLogAdapter.setLoading(false);
+        mCallLogAdapter.changeCursor(cursor);
+        mAdapter.notifyDataSetChanged();
+    }
+
+    // TODO krelease: Implement this
+    @Override
+    public void fetchCalls() {
+    }
 }
diff --git a/src/com/android/dialer/list/NewPhoneFavoriteMergedAdapter.java b/src/com/android/dialer/list/NewPhoneFavoriteMergedAdapter.java
index 047609f..49d46a8 100644
--- a/src/com/android/dialer/list/NewPhoneFavoriteMergedAdapter.java
+++ b/src/com/android/dialer/list/NewPhoneFavoriteMergedAdapter.java
@@ -27,13 +27,15 @@
 
 import com.android.contacts.common.list.ContactEntryListAdapter;
 import com.android.contacts.common.list.ContactListItemView;
-import com.android.contacts.common.list.ContactTileAdapter;
 import com.android.dialer.R;
+import com.android.dialer.calllog.NewCallLogAdapter;
 
 /**
  * An adapter that combines items from {@link com.android.contacts.common.list.ContactTileAdapter} and
- * {@link com.android.contacts.common.list.ContactEntryListAdapter} into a single list. In between those two results,
- * an account filter header will be inserted.
+ * {@link com.android.contacts.common.list.ContactEntryListAdapter} into a single list.
+ * In between those two results, an account filter header will be inserted.
+ *
+ * Has one extra view at the top: The most recent call/voicemail/missed call.
  */
 public class NewPhoneFavoriteMergedAdapter extends BaseAdapter implements SectionIndexer {
 
@@ -44,38 +46,41 @@
         }
     }
 
-    private final ContactTileAdapter mContactTileAdapter;
+    private static final String TAG = NewPhoneFavoriteMergedAdapter.class.getSimpleName();
+
+    private final PhoneFavoritesTileAdapter mContactTileAdapter;
     private final ContactEntryListAdapter mContactEntryListAdapter;
+    private final NewCallLogAdapter mCallLogAdapter;
     private final View mAccountFilterHeaderContainer;
     private final View mLoadingView;
 
+    // TODO krelease: Add a setting to toggle mShowAllContacts, and really handle it
+    // properly below.
+    private boolean mShowAllContacts = false;
+
     private final int mItemPaddingLeft;
     private final int mItemPaddingRight;
 
-    // Make frequent header consistent with account filter header.
-    private final int mFrequentHeaderPaddingTop;
-
     private final DataSetObserver mObserver;
 
     public NewPhoneFavoriteMergedAdapter(Context context,
-            ContactTileAdapter contactTileAdapter,
+            PhoneFavoritesTileAdapter contactTileAdapter,
             View accountFilterHeaderContainer,
             ContactEntryListAdapter contactEntryListAdapter,
+            NewCallLogAdapter callLogAdapter,
             View loadingView) {
-        Resources resources = context.getResources();
+        final Resources resources = context.getResources();
         mItemPaddingLeft = resources.getDimensionPixelSize(R.dimen.detail_item_side_margin);
         mItemPaddingRight = resources.getDimensionPixelSize(R.dimen.list_visible_scrollbar_padding);
-        mFrequentHeaderPaddingTop = resources.getDimensionPixelSize(
-                R.dimen.contact_browser_list_top_margin);
         mContactTileAdapter = contactTileAdapter;
         mContactEntryListAdapter = contactEntryListAdapter;
+        mCallLogAdapter = callLogAdapter;
 
         mAccountFilterHeaderContainer = accountFilterHeaderContainer;
 
         mObserver = new CustomDataSetObserver();
         mContactTileAdapter.registerDataSetObserver(mObserver);
         mContactEntryListAdapter.registerDataSetObserver(mObserver);
-
         mLoadingView = loadingView;
     }
 
@@ -83,34 +88,52 @@
     public boolean isEmpty() {
         // Cannot use the super's method here because we add extra rows in getCount() to account
         // for headers
-        return mContactTileAdapter.getCount() + mContactEntryListAdapter.getCount() == 0;
+        return mCallLogAdapter.getCount() + mContactTileAdapter.getCount() +
+                mContactEntryListAdapter.getCount() == 0;
     }
 
     @Override
     public int getCount() {
         final int contactTileAdapterCount = mContactTileAdapter.getCount();
-        final int contactEntryListAdapterCount = mContactEntryListAdapter.getCount();
-        if (mContactEntryListAdapter.isLoading()) {
+        final int contactEntryListAdapterCount = mShowAllContacts ?
+                mContactEntryListAdapter.getCount() : 0;
+
+        final int callLogAdapterCount = mCallLogAdapter.getCount();
+
+        if (mShowAllContacts && mContactEntryListAdapter.isLoading()) {
             // Hide "all" contacts during its being loaded. Instead show "loading" view.
             //
             // "+2" for mAccountFilterHeaderContainer and mLoadingView
-            return contactTileAdapterCount + 2;
+            return contactTileAdapterCount + 1 + (mShowAllContacts ? 1 : 0) +
+                    callLogAdapterCount;
         } else {
             // "+1" for mAccountFilterHeaderContainer
-            return contactTileAdapterCount + contactEntryListAdapterCount + 1;
+            return contactTileAdapterCount + contactEntryListAdapterCount +
+                    (mShowAllContacts ? 1 : 0) + callLogAdapterCount;
         }
     }
 
     @Override
     public Object getItem(int position) {
         final int contactTileAdapterCount = mContactTileAdapter.getCount();
-        final int contactEntryListAdapterCount = mContactEntryListAdapter.getCount();
+        final int contactEntryListAdapterCount = mShowAllContacts ?
+                mContactEntryListAdapter.getCount() : 0;
+
+        final int callLogAdapterCount = mCallLogAdapter.getCount();
+
+        // TODO krelease: Calculate the position properly.
+        if (callLogAdapterCount > 0) {
+            if (position < callLogAdapterCount) {
+                return mCallLogAdapter.getItem(position);
+            }
+            position -= callLogAdapterCount;
+        }
+
         if (position < contactTileAdapterCount) {  // For "tile" and "frequent" sections
             return mContactTileAdapter.getItem(position);
-        } else if (position == contactTileAdapterCount) {  // For "all" section's account header
-            return mAccountFilterHeaderContainer;
         } else {  // For "all" section
-            if (mContactEntryListAdapter.isLoading()) {  // "All" section is being loaded.
+            if (mShowAllContacts && mContactEntryListAdapter.isLoading()) {
+                // "All" section is being loaded.
                 return mLoadingView;
             } else {
                 // "-1" for mAccountFilterHeaderContainer
@@ -127,16 +150,31 @@
 
     @Override
     public int getViewTypeCount() {
-        // "+2" for mAccountFilterHeaderContainer and mLoadingView
+        // "+1" for mLoadingView
         return (mContactTileAdapter.getViewTypeCount()
                 + mContactEntryListAdapter.getViewTypeCount()
-                + 2);
+                + 1
+                + mCallLogAdapter.getViewTypeCount());
     }
 
     @Override
     public int getItemViewType(int position) {
         final int contactTileAdapterCount = mContactTileAdapter.getCount();
-        final int contactEntryListAdapterCount = mContactEntryListAdapter.getCount();
+
+        final int contactEntryListAdapterCount = mShowAllContacts ?
+                mContactEntryListAdapter.getCount() : 0;
+
+        final int callLogAdapterCount = mCallLogAdapter.getCount();
+
+        if (callLogAdapterCount > 0) {
+            if (position == 0) {
+                return mContactTileAdapter.getViewTypeCount() +
+                        mContactEntryListAdapter.getViewTypeCount() + 2;
+            }
+            // Ignore the first position when calculating view types of all other items
+            position -= callLogAdapterCount;
+        }
+
         // There should be four kinds of types that are usually used, and one more exceptional
         // type (IGNORE_ITEM_VIEW_TYPE), which sometimes comes from mContactTileAdapter.
         //
@@ -190,19 +228,28 @@
     @Override
     public View getView(int position, View convertView, ViewGroup parent) {
         final int contactTileAdapterCount = mContactTileAdapter.getCount();
-        final int contactEntryListAdapterCount = mContactEntryListAdapter.getCount();
+
+        final int contactEntryListAdapterCount = mShowAllContacts ?
+                mContactEntryListAdapter.getCount() : 0;
+
+        final int callLogAdapterCount = mCallLogAdapter.getCount();
+
+        // TODO krelease: Handle the new callLogAdapterCount and position offsets properly
+        if (callLogAdapterCount > 0) {
+            if (position == 0) {
+                final View view = mCallLogAdapter.getView(position, convertView, parent);
+                return view;
+            }
+            position -= callLogAdapterCount;
+        }
 
         // Obtain a View relevant for that position, and adjust its horizontal padding. Each
         // View has different implementation, so we use different way to control those padding.
         if (position < contactTileAdapterCount) {  // For "tile" and "frequent" sections
             final View view = mContactTileAdapter.getView(position, convertView, parent);
             final int frequentHeaderPosition = mContactTileAdapter.getFrequentHeaderPosition();
-            if (position < frequentHeaderPosition) {  // "starred" contacts
-                // No padding adjustment.
-            } else if (position == frequentHeaderPosition) {
-                view.setPadding(mItemPaddingLeft, mFrequentHeaderPaddingTop,
-                        mItemPaddingRight, view.getPaddingBottom());
-            } else {
+            // TODO krelease: Get rid of frequent header position, we don't need it anymore
+            if (position >= frequentHeaderPosition) {
                 // Views for "frequent" contacts use FrameLayout's margins instead of padding.
                 final FrameLayout frameLayout = (FrameLayout) view;
                 final View child = frameLayout.getChildAt(0);
@@ -213,28 +260,16 @@
                 child.setLayoutParams(params);
             }
             return view;
-        } else if (position == contactTileAdapterCount) {  // For "all" section's account header
-            mAccountFilterHeaderContainer.setPadding(mItemPaddingLeft,
-                    mAccountFilterHeaderContainer.getPaddingTop(),
-                    mItemPaddingRight,
-                    mAccountFilterHeaderContainer.getPaddingBottom());
-
-            // Show a single "No Contacts" label under the "all" section account header
-            // if no contacts are displayed.
-            mAccountFilterHeaderContainer.findViewById(
-                    R.id.contact_list_all_empty).setVisibility(
-                    contactEntryListAdapterCount == 0 ? View.VISIBLE : View.GONE);
-            return mAccountFilterHeaderContainer;
         } else {  // For "all" section
-            if (mContactEntryListAdapter.isLoading()) {  // "All" section is being loaded.
+            if (mShowAllContacts && mContactEntryListAdapter.isLoading()) {
+                // "All" section is being loaded.
                 mLoadingView.setPadding(mItemPaddingLeft,
                         mLoadingView.getPaddingTop(),
                         mItemPaddingRight,
                         mLoadingView.getPaddingBottom());
                 return mLoadingView;
             } else {
-                // "-1" for mAccountFilterHeaderContainer
-                final int localPosition = position - contactTileAdapterCount - 1;
+                final int localPosition = position - contactTileAdapterCount;
                 final ContactListItemView itemView = (ContactListItemView)
                         mContactEntryListAdapter.getView(localPosition, convertView, null);
                 itemView.setPadding(mItemPaddingLeft, itemView.getPaddingTop(),
@@ -278,9 +313,10 @@
 
     @Override
     public int getPositionForSection(int sectionIndex) {
+        // frequent header view.
         final int contactTileAdapterCount = mContactTileAdapter.getCount();
         final int localPosition = mContactEntryListAdapter.getPositionForSection(sectionIndex);
-        return contactTileAdapterCount + 1 + localPosition;
+        return contactTileAdapterCount + localPosition;
     }
 
     @Override
@@ -289,8 +325,7 @@
         if (position <= contactTileAdapterCount) {
             return 0;
         } else {
-            // "-1" for mAccountFilterHeaderContainer
-            final int localPosition = position - contactTileAdapterCount - 1;
+            final int localPosition = position - contactTileAdapterCount;
             return mContactEntryListAdapter.getSectionForPosition(localPosition);
         }
     }
diff --git a/src/com/android/dialer/list/OnListFragmentScrolledListener.java b/src/com/android/dialer/list/OnListFragmentScrolledListener.java
new file mode 100644
index 0000000..cc5f3cd
--- /dev/null
+++ b/src/com/android/dialer/list/OnListFragmentScrolledListener.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2013 Google Inc.
+ * Licensed to 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.list;
+
+/*
+ * Interface to provide callback to activity when a child fragment is scrolled
+ */
+public interface OnListFragmentScrolledListener {
+    public void onListFragmentScrollStateChange(int scrollState);
+}
diff --git a/src/com/android/dialer/list/PhoneFavoriteMergedAdapter.java b/src/com/android/dialer/list/PhoneFavoriteMergedAdapter.java
index ba291a0..bb758a7 100644
--- a/src/com/android/dialer/list/PhoneFavoriteMergedAdapter.java
+++ b/src/com/android/dialer/list/PhoneFavoriteMergedAdapter.java
@@ -130,7 +130,7 @@
         // "+2" for mAccountFilterHeaderContainer and mLoadingView
         return (mContactTileAdapter.getViewTypeCount()
                 + mContactEntryListAdapter.getViewTypeCount()
-                + 2);
+                + 1);
     }
 
     @Override
diff --git a/src/com/android/dialer/list/PhoneFavoriteRegularRowView.java b/src/com/android/dialer/list/PhoneFavoriteRegularRowView.java
new file mode 100644
index 0000000..2f5921e
--- /dev/null
+++ b/src/com/android/dialer/list/PhoneFavoriteRegularRowView.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.dialer.list;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.android.contacts.common.MoreContactUtils;
+import com.android.contacts.common.list.ContactEntry;
+import com.android.contacts.common.list.ContactTileView;
+import com.android.contacts.common.util.ViewUtil;
+
+/**
+ * A light version of the {@link com.android.contacts.common.list.ContactTileView} that is used in Dialtacts
+ * for frequently called contacts. Slightly different behavior from superclass...
+ * when you tap it, you want to call the frequently-called number for the
+ * contact, even if that is not the default number for that contact.
+ */
+public class PhoneFavoriteRegularRowView extends ContactTileView {
+    private String mPhoneNumberString;
+
+    public PhoneFavoriteRegularRowView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected boolean isDarkTheme() {
+        return false;
+    }
+
+    @Override
+    protected int getApproximateImageSize() {
+        return ViewUtil.getConstantPreLayoutWidth(getQuickContact());
+    }
+
+    @Override
+    public void loadFromContact(ContactEntry entry) {
+        super.loadFromContact(entry);
+        mPhoneNumberString = null; // ... in case we're reusing the view
+        if (entry != null) {
+            // Grab the phone-number to call directly... see {@link onClick()}
+            mPhoneNumberString = entry.phoneNumber;
+        }
+    }
+
+    @Override
+    protected OnClickListener createClickListener() {
+        return new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (mListener == null) return;
+                if (TextUtils.isEmpty(mPhoneNumberString)) {
+                    // Copy "superclass" implementation
+                    mListener.onContactSelected(getLookupUri(), MoreContactUtils
+                            .getTargetRectFromView(
+                                    mContext, PhoneFavoriteRegularRowView.this));
+                } else {
+                    // When you tap a frequently-called contact, you want to
+                    // call them at the number that you usually talk to them
+                    // at (i.e. the one displayed in the UI), regardless of
+                    // whether that's their default number.
+                    mListener.onCallNumberDirectly(mPhoneNumberString);
+                }
+            }
+        };
+    }
+}
diff --git a/src/com/android/dialer/list/PhoneFavoriteTileView.java b/src/com/android/dialer/list/PhoneFavoriteTileView.java
new file mode 100644
index 0000000..d87e2a8
--- /dev/null
+++ b/src/com/android/dialer/list/PhoneFavoriteTileView.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.dialer.list;
+
+import android.content.Context;
+import android.content.Intent;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageButton;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.list.ContactTileView;
+
+/**
+ * Displays the contact's picture overlayed with their name
+ * in a perfect square. It also has an additional touch target for a secondary action.
+ */
+public class PhoneFavoriteTileView extends ContactTileView {
+    private ImageButton mSecondaryButton;
+
+    public PhoneFavoriteTileView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+
+        mSecondaryButton = (ImageButton) findViewById(R.id.contact_tile_secondary_button);
+        mSecondaryButton.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Intent intent = new Intent(Intent.ACTION_VIEW, getLookupUri());
+                // Secondary target will be visible only from phone's favorite screen, then
+                // we want to launch it as a separate People task.
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                getContext().startActivity(intent);
+            }
+        });
+    }
+
+    @Override
+    protected boolean isDarkTheme() {
+        return false;
+    }
+
+    @Override
+    protected int getApproximateImageSize() {
+        // The picture is the full size of the tile (minus some padding, but we can be generous)
+        return mListener.getApproximateTileWidth();
+    }
+}
diff --git a/src/com/android/dialer/list/PhoneFavoritesTileAdapter.java b/src/com/android/dialer/list/PhoneFavoritesTileAdapter.java
new file mode 100644
index 0000000..36fc346
--- /dev/null
+++ b/src/com/android/dialer/list/PhoneFavoritesTileAdapter.java
@@ -0,0 +1,515 @@
+/*
+ * Copyright (C) 2013 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.list;
+
+import android.content.ContentUris;
+import android.content.Context;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.Contacts;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.FrameLayout;
+
+import com.android.contacts.common.ContactPhotoManager;
+import com.android.contacts.common.ContactTileLoaderFactory;
+import com.android.contacts.common.R;
+import com.android.contacts.common.list.ContactEntry;
+import com.android.contacts.common.list.ContactTileAdapter;
+import com.android.contacts.common.list.ContactTileView;
+
+import java.util.ArrayList;
+
+/**
+ * Also allows for a configurable number of columns as well as a maximum row of tiled contacts.
+ *
+ * This adapter has been rewritten to only support a maximum of one row for favorites.
+ *
+ * TODO Krelease: Move to PhoneContactTileAdapter in Dialer package.
+ */
+public class PhoneFavoritesTileAdapter extends BaseAdapter {
+    private static final String TAG = ContactTileAdapter.class.getSimpleName();
+
+    public static final int NO_ROW_LIMIT = -1;
+
+    private ContactTileView.Listener mListener;
+    private Context mContext;
+    private Resources mResources;
+    protected Cursor mContactCursor = null;
+    private ContactPhotoManager mPhotoManager;
+    protected int mNumFrequents;
+
+    /**
+     * Index of the first NON starred contact in the {@link Cursor}
+     * Only valid when {@link DisplayType#STREQUENT} is true
+     */
+    private int mDividerPosition;
+    protected int mColumnCount;
+    private int mMaxTiledRows = NO_ROW_LIMIT;
+    private int mStarredIndex;
+
+    protected int mIdIndex;
+    protected int mLookupIndex;
+    protected int mPhotoUriIndex;
+    protected int mNameIndex;
+    protected int mPresenceIndex;
+    protected int mStatusIndex;
+
+    /**
+     * Only valid when {@link DisplayType#STREQUENT_PHONE_ONLY} is true
+     */
+    private int mPhoneNumberIndex;
+    private int mPhoneNumberTypeIndex;
+    private int mPhoneNumberLabelIndex;
+
+    private boolean mIsQuickContactEnabled = false;
+    private final int mPaddingInPixels;
+
+    public PhoneFavoritesTileAdapter(Context context, ContactTileView.Listener listener, int numCols) {
+        this(context, listener, numCols, NO_ROW_LIMIT);
+    }
+
+    public PhoneFavoritesTileAdapter(Context context, ContactTileView.Listener listener, int numCols,
+            int maxTiledRows) {
+        mListener = listener;
+        mContext = context;
+        mResources = context.getResources();
+        mColumnCount = numCols;
+        mNumFrequents = 0;
+        mMaxTiledRows = maxTiledRows;
+
+        // Converting padding in dips to padding in pixels
+        mPaddingInPixels = mContext.getResources()
+                .getDimensionPixelSize(R.dimen.contact_tile_divider_padding);
+        bindColumnIndices();
+    }
+
+    public void setPhotoLoader(ContactPhotoManager photoLoader) {
+        mPhotoManager = photoLoader;
+    }
+
+    public void setMaxRowCount(int maxRows) {
+        mMaxTiledRows = maxRows;
+    }
+
+    public void setColumnCount(int columnCount) {
+        mColumnCount = columnCount;
+    }
+
+    public void enableQuickContact(boolean enableQuickContact) {
+        mIsQuickContactEnabled = enableQuickContact;
+    }
+
+    /**
+     * Sets the column indices for expected {@link Cursor}
+     * based on {@link DisplayType}.
+     */
+    protected void bindColumnIndices() {
+        mIdIndex = ContactTileLoaderFactory.CONTACT_ID;
+        mLookupIndex = ContactTileLoaderFactory.LOOKUP_KEY;
+        mPhotoUriIndex = ContactTileLoaderFactory.PHOTO_URI;
+        mNameIndex = ContactTileLoaderFactory.DISPLAY_NAME;
+        mStarredIndex = ContactTileLoaderFactory.STARRED;
+        mPresenceIndex = ContactTileLoaderFactory.CONTACT_PRESENCE;
+        mStatusIndex = ContactTileLoaderFactory.CONTACT_STATUS;
+
+        mPhoneNumberIndex = ContactTileLoaderFactory.PHONE_NUMBER;
+        mPhoneNumberTypeIndex = ContactTileLoaderFactory.PHONE_NUMBER_TYPE;
+        mPhoneNumberLabelIndex = ContactTileLoaderFactory.PHONE_NUMBER_LABEL;
+    }
+
+    /**
+     * Gets the number of frequents from the passed in cursor.
+     *
+     * This methods is needed so the GroupMemberTileAdapter can override this.
+     *
+     * @param cursor The cursor to get number of frequents from.
+     */
+    protected void saveNumFrequentsFromCursor(Cursor cursor) {
+        mNumFrequents = cursor.getCount() - mDividerPosition;
+    }
+
+    /**
+     * Creates {@link ContactTileView}s for each item in {@link Cursor}.
+     *
+     * Else use {@link ContactTileLoaderFactory}
+     */
+    public void setContactCursor(Cursor cursor) {
+        mContactCursor = cursor;
+        mDividerPosition = getDividerPosition(cursor);
+
+        saveNumFrequentsFromCursor(cursor);
+
+        // cause a refresh of any views that rely on this data
+        notifyDataSetChanged();
+    }
+
+    /**
+     * Iterates over the {@link Cursor}
+     * Returns position of the first NON Starred Contact
+     * Returns -1 if {@link DisplayType#STARRED_ONLY}
+     * Returns 0 if {@link DisplayType#FREQUENT_ONLY}
+     */
+    protected int getDividerPosition(Cursor cursor) {
+        if (cursor == null || cursor.isClosed()) {
+            throw new IllegalStateException("Unable to access cursor");
+        }
+
+        cursor.moveToPosition(-1);
+        while (cursor.moveToNext()) {
+            if (cursor.getInt(mStarredIndex) == 0) {
+                return cursor.getPosition();
+            }
+        }
+
+        // There are not NON Starred contacts in cursor
+        // Set divider positon to end
+        return cursor.getCount();
+    }
+
+    protected ContactEntry createContactEntryFromCursor(Cursor cursor, int position) {
+        // If the loader was canceled we will be given a null cursor.
+        // In that case, show an empty list of contacts.
+        if (cursor == null || cursor.isClosed() || cursor.getCount() <= position) return null;
+
+        cursor.moveToPosition(position);
+        long id = cursor.getLong(mIdIndex);
+        String photoUri = cursor.getString(mPhotoUriIndex);
+        String lookupKey = cursor.getString(mLookupIndex);
+
+        ContactEntry contact = new ContactEntry();
+        String name = cursor.getString(mNameIndex);
+        contact.name = (name != null) ? name : mResources.getString(R.string.missing_name);
+        contact.status = cursor.getString(mStatusIndex);
+        contact.photoUri = (photoUri != null ? Uri.parse(photoUri) : null);
+        contact.lookupKey = ContentUris.withAppendedId(
+                Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey), id);
+
+        // Set phone number and label
+        int phoneNumberType = cursor.getInt(mPhoneNumberTypeIndex);
+        String phoneNumberCustomLabel = cursor.getString(mPhoneNumberLabelIndex);
+        contact.phoneLabel = (String) Phone.getTypeLabel(mResources, phoneNumberType,
+                phoneNumberCustomLabel);
+        contact.phoneNumber = cursor.getString(mPhoneNumberIndex);
+
+        return contact;
+    }
+
+    /**
+     * Returns the number of frequents that will be displayed in the list.
+     */
+    public int getNumFrequents() {
+        return mNumFrequents;
+    }
+
+    @Override
+    public int getCount() {
+        if (mContactCursor == null || mContactCursor.isClosed()) {
+            return 0;
+        }
+
+        // Takes numbers of rows the Starred Contacts Occupy
+        int starredRowCount = getRowCount(mDividerPosition) +
+                (mMaxTiledRows == NO_ROW_LIMIT ? 0 : Math.max(0, mDividerPosition -
+                        mMaxTiledRows * mColumnCount));
+
+        // Compute the frequent row count which is 1 plus the number of frequents
+        // (to account for the divider) or 0 if there are no frequents.
+        int frequentRowCount = mNumFrequents == 0 ? 0 : mNumFrequents;
+
+        // Return the number of starred plus frequent rows
+        return starredRowCount + frequentRowCount;
+    }
+
+    /**
+     * Returns the number of rows required to show the provided number of entries
+     * with the current number of columns.
+     */
+    protected int getRowCount(int entryCount) {
+        if (entryCount == 0) return 0;
+        final int nonLimitedRows = ((entryCount - 1) / mColumnCount) + 1;
+        return mMaxTiledRows == NO_ROW_LIMIT ? nonLimitedRows : Math.min(mMaxTiledRows,
+                nonLimitedRows);
+    }
+
+    public int getColumnCount() {
+        return mColumnCount;
+    }
+
+    /**
+     * Returns an ArrayList of the {@link ContactEntry}s that are to appear
+     * on the row for the given position.
+     */
+    @Override
+    public ArrayList<ContactEntry> getItem(int position) {
+        ArrayList<ContactEntry> resultList = new ArrayList<ContactEntry>(mColumnCount);
+        int contactIndex = position * mColumnCount;
+        if (position < getRowCount(mDividerPosition)) {
+            for (int columnCounter = 0; columnCounter < mColumnCount &&
+                    contactIndex != mDividerPosition; columnCounter++) {
+                resultList.add(createContactEntryFromCursor(mContactCursor, contactIndex));
+                contactIndex++;
+            }
+        } else {
+            /*
+             * Current position minus how many rows are before the divider and Minus 1 for the
+             * divider itself provides the relative index of the frequent contact being displayed.
+             * Then add the dividerPostion to give the offset into the contacts cursor to get the
+             * absolute index.
+             */
+            final int rowCount = getRowCount(mDividerPosition);
+            contactIndex = position - rowCount + Math.min(mDividerPosition,
+                    rowCount * mColumnCount);
+            resultList.add(createContactEntryFromCursor(mContactCursor, contactIndex));
+        }
+        return resultList;
+    }
+
+    @Override
+    public long getItemId(int position) {
+        // As we show several selectable items for each ListView row,
+        // we can not determine a stable id. But as we don't rely on ListView's selection,
+        // this should not be a problem.
+        return position;
+    }
+
+    @Override
+    public boolean areAllItemsEnabled() {
+        // No dividers, so all items are enabled.
+        return true;
+    }
+
+    @Override
+    public boolean isEnabled(int position) {
+        return position != getRowCount(mDividerPosition);
+    }
+
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+        int itemViewType = getItemViewType(position);
+
+        ContactTileRow contactTileRowView = (ContactTileRow) convertView;
+        ArrayList<ContactEntry> contactList = getItem(position);
+
+        if (contactTileRowView == null) {
+            // Creating new row if needed
+            contactTileRowView = new ContactTileRow(mContext, itemViewType);
+        }
+
+        contactTileRowView.configureRow(contactList, position == getCount() - 1);
+        return contactTileRowView;
+    }
+
+    private int getLayoutResourceId(int viewType) {
+        switch (viewType) {
+            case ViewTypes.FREQUENT:
+                return R.layout.phone_favorite_regular_row_view;
+            case ViewTypes.STARRED_PHONE:
+                return R.layout.phone_favorite_tile_view;
+            default:
+                throw new IllegalArgumentException("Unrecognized viewType " + viewType);
+        }
+    }
+    @Override
+    public int getViewTypeCount() {
+        return ViewTypes.COUNT;
+    }
+
+    @Override
+    public int getItemViewType(int position) {
+        if (position < getRowCount(mDividerPosition)) {
+            return ViewTypes.STARRED_PHONE;
+        } else {
+            return ViewTypes.FREQUENT;
+        }
+    }
+
+    /**
+     * Returns the "frequent header" position. Only available when STREQUENT or
+     * STREQUENT_PHONE_ONLY is used for its display type.
+     */
+    public int getFrequentHeaderPosition() {
+        return getRowCount(mDividerPosition);
+    }
+
+    /**
+     * Acts as a row item composed of {@link ContactTileView}
+     *
+     * TODO: FREQUENT doesn't really need it.  Just let {@link #getView} return
+     */
+    private class ContactTileRow extends FrameLayout {
+        private int mItemViewType;
+        private int mLayoutResId;
+
+        public ContactTileRow(Context context, int itemViewType) {
+            super(context);
+            mItemViewType = itemViewType;
+            mLayoutResId = getLayoutResourceId(mItemViewType);
+
+            // Remove row (but not children) from accessibility node tree.
+            setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
+        }
+
+        /**
+         * Configures the row to add {@link ContactEntry}s information to the views
+         */
+        public void configureRow(ArrayList<ContactEntry> list, boolean isLastRow) {
+            int columnCount = mItemViewType == ViewTypes.FREQUENT ? 1 : mColumnCount;
+
+            // Adding tiles to row and filling in contact information
+            for (int columnCounter = 0; columnCounter < columnCount; columnCounter++) {
+                ContactEntry entry =
+                        columnCounter < list.size() ? list.get(columnCounter) : null;
+                addTileFromEntry(entry, columnCounter, isLastRow);
+            }
+        }
+
+        private void addTileFromEntry(ContactEntry entry, int childIndex, boolean isLastRow) {
+            final ContactTileView contactTile;
+
+            if (getChildCount() <= childIndex) {
+
+                contactTile = (ContactTileView) inflate(mContext, mLayoutResId, null);
+                // Note: the layoutparam set here is only actually used for FREQUENT.
+                // We override onMeasure() for STARRED and we don't care the layout param there.
+                Resources resources = mContext.getResources();
+                FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
+                        ViewGroup.LayoutParams.WRAP_CONTENT,
+                        ViewGroup.LayoutParams.WRAP_CONTENT);
+
+                params.setMargins(
+                        resources.getDimensionPixelSize(R.dimen.detail_item_side_margin),
+                        0,
+                        resources.getDimensionPixelSize(R.dimen.detail_item_side_margin),
+                        0);
+                contactTile.setLayoutParams(params);
+                contactTile.setPhotoManager(mPhotoManager);
+                contactTile.setListener(mListener);
+                addView(contactTile);
+            } else {
+                contactTile = (ContactTileView) getChildAt(childIndex);
+            }
+            contactTile.loadFromContact(entry);
+            switch (mItemViewType) {
+                case ViewTypes.STARRED_PHONE:
+                    // Setting divider visibilities
+                    contactTile.setPaddingRelative(0, 0,
+                            childIndex >= mColumnCount - 1 ? 0 : mPaddingInPixels,
+                            isLastRow ? 0 : mPaddingInPixels);
+                    break;
+                case ViewTypes.FREQUENT:
+                    contactTile.setHorizontalDividerVisibility(
+                            isLastRow ? View.GONE : View.VISIBLE);
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        @Override
+        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+            switch (mItemViewType) {
+                case ViewTypes.STARRED_PHONE:
+                    onLayoutForTiles();
+                    return;
+                default:
+                    super.onLayout(changed, left, top, right, bottom);
+                    return;
+            }
+        }
+
+        private void onLayoutForTiles() {
+            final int count = getChildCount();
+
+            // Just line up children horizontally.
+            int childLeft = 0;
+            for (int i = 0; i < count; i++) {
+                final View child = getChildAt(i);
+
+                // Note MeasuredWidth includes the padding.
+                final int childWidth = child.getMeasuredWidth();
+                child.layout(childLeft, 0, childLeft + childWidth, child.getMeasuredHeight());
+                childLeft += childWidth;
+            }
+        }
+
+        @Override
+        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+            switch (mItemViewType) {
+                case ViewTypes.STARRED_PHONE:
+                case ViewTypes.STARRED:
+                    onMeasureForTiles(widthMeasureSpec);
+                    return;
+                default:
+                    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+                    return;
+            }
+        }
+
+        private void onMeasureForTiles(int widthMeasureSpec) {
+            final int width = MeasureSpec.getSize(widthMeasureSpec);
+
+            final int childCount = getChildCount();
+            if (childCount == 0) {
+                // Just in case...
+                setMeasuredDimension(width, 0);
+                return;
+            }
+
+            // 1. Calculate image size.
+            //      = ([total width] - [total padding]) / [child count]
+            //
+            // 2. Set it to width/height of each children.
+            //    If we have a remainder, some tiles will have 1 pixel larger width than its height.
+            //
+            // 3. Set the dimensions of itself.
+            //    Let width = given width.
+            //    Let height = image size + bottom paddding.
+
+            final int totalPaddingsInPixels = (mColumnCount - 1) * mPaddingInPixels;
+
+            // Preferred width / height for images (excluding the padding).
+            // The actual width may be 1 pixel larger than this if we have a remainder.
+            final int imageSize = (width - totalPaddingsInPixels) / mColumnCount;
+            final int remainder = width - (imageSize * mColumnCount) - totalPaddingsInPixels;
+
+            for (int i = 0; i < childCount; i++) {
+                final View child = getChildAt(i);
+                final int childWidth = imageSize + child.getPaddingRight()
+                        // Compensate for the remainder
+                        + (i < remainder ? 1 : 0);
+                final int childHeight = imageSize + child.getPaddingBottom();
+                child.measure(
+                        MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY),
+                        MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY)
+                        );
+            }
+            setMeasuredDimension(width, imageSize + getChildAt(0).getPaddingBottom());
+        }
+    }
+
+    protected static class ViewTypes {
+        public static final int COUNT = 3;
+        public static final int STARRED = 0;
+        public static final int FREQUENT = 1;
+        public static final int STARRED_PHONE = 2;
+    }
+}
diff --git a/src/com/android/dialer/list/SmartDialNumberListAdapter.java b/src/com/android/dialer/list/SmartDialNumberListAdapter.java
new file mode 100644
index 0000000..0413c4e
--- /dev/null
+++ b/src/com/android/dialer/list/SmartDialNumberListAdapter.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2013 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.list;
+
+import android.content.ContentUris;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Callable;
+import android.telephony.PhoneNumberUtils;
+import android.util.Log;
+
+import com.android.contacts.common.list.ContactListItemView;
+import com.android.contacts.common.list.PhoneNumberListAdapter;
+import com.android.dialer.dialpad.SmartDialCursorLoader;
+import com.android.dialer.dialpad.SmartDialCursorLoader.SmartDialPhoneQuery;
+import com.android.dialer.dialpad.SmartDialNameMatcher;
+import com.android.dialer.dialpad.SmartDialPrefix;
+import com.android.dialer.dialpad.SmartDialMatchPosition;
+
+import java.util.ArrayList;
+
+/**
+ * List adapter to display the SmartDial search results.
+ */
+public class SmartDialNumberListAdapter extends PhoneNumberListAdapter{
+
+    private static final String TAG = SmartDialNumberListAdapter.class.getSimpleName();
+    private static final boolean DEBUG = false;
+
+    private SmartDialNameMatcher mNameMatcher;
+
+    public SmartDialNumberListAdapter(Context context) {
+        super(context);
+        if (DEBUG) {
+            Log.v(TAG, "Constructing List Adapter");
+        }
+    }
+
+    /**
+     * Sets query for the SmartDialCursorLoader.
+     */
+    public void configureLoader(SmartDialCursorLoader loader) {
+        if (DEBUG) {
+            Log.v(TAG, "Congifugure Loader with query" + getQueryString());
+        }
+
+        if (getQueryString() == null) {
+            mNameMatcher = new SmartDialNameMatcher("", SmartDialPrefix.getMap());
+            loader.configureQuery("");
+        } else {
+            loader.configureQuery(getQueryString());
+            mNameMatcher = new SmartDialNameMatcher(PhoneNumberUtils.normalizeNumber(
+                    getQueryString()), SmartDialPrefix.getMap());
+        }
+    }
+
+    /**
+     * Sets highlight options for a List item in the SmartDial search results.
+     * @param view ContactListItemView where the result will be displayed.
+     * @param cursor Object containing information of the associated List item.
+     */
+    @Override
+    protected void setHighlight(ContactListItemView view, Cursor cursor) {
+        view.clearHighlightSequences();
+
+        if (mNameMatcher.matches(cursor.getString(SmartDialPhoneQuery.SMARTDIAL_DISPLAY_NAME))) {
+            final ArrayList<SmartDialMatchPosition> nameMatches = mNameMatcher.getMatchPositions();
+            for (SmartDialMatchPosition match:nameMatches) {
+                view.addNameHighlightSequence(match.start, match.end);
+                if (DEBUG) {
+                    Log.v(TAG, cursor.getString(SmartDialPhoneQuery.SMARTDIAL_DISPLAY_NAME) + " " +
+                            mNameMatcher.getQuery() + " " + String.valueOf(match.start));
+                }
+            }
+        }
+
+        final SmartDialMatchPosition numberMatch = mNameMatcher.matchesNumber(cursor.getString(
+                SmartDialPhoneQuery.SMARTDIAL_NUMBER));
+        if (numberMatch != null) {
+            view.addNumberHighlightSequence(numberMatch.start, numberMatch.end);
+        }
+    }
+
+    /**
+     * Gets Uri for the list item at the given position.
+     * @param position Location of the data of interest.
+     * @return Data Uri of the entry.
+     */
+    public Uri getDataUri(int position) {
+        Cursor cursor = ((Cursor)getItem(position));
+        if (cursor != null) {
+            long id = cursor.getLong(SmartDialPhoneQuery.SMARTDIAL_ID);
+            return ContentUris.withAppendedId(ContactsContract.Data.CONTENT_URI, id);
+        } else {
+            Log.w(TAG, "Cursor was null in getDataUri() call. Returning null instead.");
+            return null;
+        }
+    }
+}
diff --git a/src/com/android/dialer/list/SmartDialNumberPickerFragment.java b/src/com/android/dialer/list/SmartDialNumberPickerFragment.java
new file mode 100644
index 0000000..0892de6
--- /dev/null
+++ b/src/com/android/dialer/list/SmartDialNumberPickerFragment.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2013 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.list;
+
+import android.content.Loader;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.ContactsContract.Directory;
+import android.util.Log;
+
+import com.android.contacts.common.list.ContactEntryListAdapter;
+import com.android.contacts.common.list.PhoneNumberPickerFragment;
+import com.android.dialer.dialpad.SmartDialCursorLoader;
+
+/**
+ * Implements a fragment to load and display SmartDial search results.
+ */
+public class SmartDialNumberPickerFragment extends PhoneNumberPickerFragment {
+
+    private static final String TAG = SmartDialNumberPickerFragment.class.getSimpleName();
+
+    /**
+     * Creates a SmartDialListAdapter to display and operate on search results.
+     * @return
+     */
+    @Override
+    protected ContactEntryListAdapter createListAdapter() {
+        SmartDialNumberListAdapter adapter = new SmartDialNumberListAdapter(getActivity());
+        adapter.setDisplayPhotos(true);
+        adapter.setUseCallableUri(super.usesCallableUri());
+        return adapter;
+    }
+
+    /**
+     * Creates a SmartDialCursorLoader object to load query results.
+     */
+    @Override
+    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
+        /** SmartDial does not support Directory Load, falls back to normal search instead. */
+        if (id == getDirectoryLoaderId()) {
+            Log.v(TAG, "Directory load");
+            return super.onCreateLoader(id, args);
+        } else {
+            Log.v(TAG, "Creating loader");
+            final SmartDialNumberListAdapter adapter = (SmartDialNumberListAdapter) getAdapter();
+            SmartDialCursorLoader loader = new SmartDialCursorLoader(super.getContext());
+            adapter.configureLoader(loader);
+            return loader;
+        }
+    }
+
+    /**
+     * Gets the Phone Uri of an entry for calling.
+     * @param position Location of the data of interest.
+     * @return Phone Uri to establish a phone call.
+     */
+    @Override
+    protected Uri getPhoneUri(int position) {
+        final SmartDialNumberListAdapter adapter = (SmartDialNumberListAdapter) getAdapter();
+        return adapter.getDataUri(position);
+    }
+}
diff --git a/src/com/android/dialer/list/SmartDialSearchFragment.java b/src/com/android/dialer/list/SmartDialSearchFragment.java
new file mode 100644
index 0000000..3c1e513
--- /dev/null
+++ b/src/com/android/dialer/list/SmartDialSearchFragment.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2013 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.list;
+
+import android.app.Activity;
+import android.content.Loader;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.ContactsContract.Directory;
+import android.util.Log;
+import android.widget.AbsListView;
+import android.widget.AbsListView.OnScrollListener;
+
+import com.android.contacts.common.list.ContactEntryListAdapter;
+import com.android.contacts.common.list.ContactListItemView;
+import com.android.contacts.common.list.PhoneNumberPickerFragment;
+import com.android.dialer.dialpad.SmartDialCursorLoader;
+
+/**
+ * Implements a fragment to load and display SmartDial search results.
+ */
+public class SmartDialSearchFragment extends PhoneNumberPickerFragment {
+    private static final String TAG = SmartDialSearchFragment.class.getSimpleName();
+
+    private OnListFragmentScrolledListener mActivityScrollListener;
+
+    @Override
+    public void onAttach(Activity activity) {
+        super.onAttach(activity);
+
+        setQuickContactEnabled(true);
+        setDarkTheme(false);
+        setPhotoPosition(ContactListItemView.getDefaultPhotoPosition(true /* opposite */));
+        setUseCallableUri(true);
+
+        try {
+            mActivityScrollListener = (OnListFragmentScrolledListener) activity;
+        } catch (ClassCastException e) {
+            throw new ClassCastException(activity.toString()
+                    + " must implement OnListFragmentScrolledListener");
+        }
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        getListView().setOnScrollListener(new OnScrollListener() {
+            @Override
+            public void onScrollStateChanged(AbsListView view, int scrollState) {
+                mActivityScrollListener.onListFragmentScrollStateChange(scrollState);
+            }
+
+            @Override
+            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
+                    int totalItemCount) {
+            }
+        });
+    }
+
+    /**
+     * Creates a SmartDialListAdapter to display and operate on search results.
+     */
+    @Override
+    protected ContactEntryListAdapter createListAdapter() {
+        SmartDialNumberListAdapter adapter = new SmartDialNumberListAdapter(getActivity());
+        adapter.setUseCallableUri(super.usesCallableUri());
+        adapter.setQuickContactEnabled(true);
+        return adapter;
+    }
+
+    /**
+     * Creates a SmartDialCursorLoader object to load query results.
+     */
+    @Override
+    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
+        // Smart dialing does not support Directory Load, falls back to normal search instead.
+        if (id == getDirectoryLoaderId()) {
+            Log.v(TAG, "Directory load");
+            return super.onCreateLoader(id, args);
+        } else {
+            Log.v(TAG, "Creating loader");
+            final SmartDialNumberListAdapter adapter = (SmartDialNumberListAdapter) getAdapter();
+            SmartDialCursorLoader loader = new SmartDialCursorLoader(super.getContext());
+            adapter.configureLoader(loader);
+            return loader;
+        }
+    }
+
+    /**
+     * Gets the Phone Uri of an entry for calling.
+     * @param position Location of the data of interest.
+     * @return Phone Uri to establish a phone call.
+     */
+    @Override
+    protected Uri getPhoneUri(int position) {
+        final SmartDialNumberListAdapter adapter = (SmartDialNumberListAdapter) getAdapter();
+        return adapter.getDataUri(position);
+    }
+
+    @Override
+    protected void setSearchMode(boolean flag) {
+        super.setSearchMode(flag);
+        // This hides the "All contacts with phone numbers" header in the search fragment
+        getAdapter().setHasHeader(0, false);
+    }
+}
diff --git a/tests/src/com/android/dialer/database/SmartDialPrefixTest.java b/tests/src/com/android/dialer/database/SmartDialPrefixTest.java
index db0a0f3..fe42db3 100644
--- a/tests/src/com/android/dialer/database/SmartDialPrefixTest.java
+++ b/tests/src/com/android/dialer/database/SmartDialPrefixTest.java
@@ -147,7 +147,7 @@
                 lastTimeUsed, timesUsed, starred, isSuperPrimary, inVisibleGroup, isPrimary});
         nameCursor.addRow(new Object[]{displayName, contactId});
 
-        return new ContactNumber(contactId, displayName, number, lookupKey);
+        return new ContactNumber(contactId, id, displayName, number, lookupKey, 0);
     }
 
     private ArrayList<ContactNumber> getLooseMatchesFromDb(String query) {