Merge "Import translations. DO NOT MERGE"
diff --git a/res/drawable-hdpi/ic_overflow_menu.png b/res/drawable-hdpi/ic_overflow_menu.png
new file mode 100644
index 0000000..0170057
--- /dev/null
+++ b/res/drawable-hdpi/ic_overflow_menu.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_overflow_menu.png b/res/drawable-mdpi/ic_overflow_menu.png
new file mode 100644
index 0000000..0170057
--- /dev/null
+++ b/res/drawable-mdpi/ic_overflow_menu.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_overflow_menu.png b/res/drawable-xhdpi/ic_overflow_menu.png
new file mode 100644
index 0000000..7773841
--- /dev/null
+++ b/res/drawable-xhdpi/ic_overflow_menu.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_overflow_menu.png b/res/drawable-xxhdpi/ic_overflow_menu.png
new file mode 100644
index 0000000..7773841
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_overflow_menu.png
Binary files differ
diff --git a/res/layout/dialpad.xml b/res/layout/dialpad.xml
index c13f525..df6f527 100644
--- a/res/layout/dialpad.xml
+++ b/res/layout/dialpad.xml
@@ -42,20 +42,36 @@
                     android:baselineAlignBottom="true" />
             </LinearLayout>
         </com.android.dialer.dialpad.DialpadKeyButton>
-        <include layout="@layout/dialpad_key" android:id="@+id/two"/>
-        <include layout="@layout/dialpad_key" android:id="@+id/three"/>
+        <include layout="@layout/dialpad_key"
+            android:id="@+id/two"
+            style="@style/DialpadKeyButtonStyle" />
+        <include layout="@layout/dialpad_key"
+            android:id="@+id/three"
+            style="@style/DialpadKeyButtonStyle" />
     </TableRow>
 
     <TableRow>
-        <include layout="@layout/dialpad_key" android:id="@+id/four"/>
-        <include layout="@layout/dialpad_key" android:id="@+id/five"/>
-        <include layout="@layout/dialpad_key" android:id="@+id/six"/>
+        <include layout="@layout/dialpad_key"
+            android:id="@+id/four"
+            style="@style/DialpadKeyButtonStyle" />
+        <include layout="@layout/dialpad_key"
+            android:id="@+id/five"
+            style="@style/DialpadKeyButtonStyle" />
+        <include layout="@layout/dialpad_key"
+            android:id="@+id/six"
+            style="@style/DialpadKeyButtonStyle" />
     </TableRow>
 
     <TableRow>
-        <include layout="@layout/dialpad_key" android:id="@+id/seven"/>
-        <include layout="@layout/dialpad_key" android:id="@+id/eight"/>
-        <include layout="@layout/dialpad_key" android:id="@+id/nine"/>
+        <include layout="@layout/dialpad_key"
+            android:id="@+id/seven"
+            style="@style/DialpadKeyButtonStyle" />
+        <include layout="@layout/dialpad_key"
+            android:id="@+id/eight"
+            style="@style/DialpadKeyButtonStyle" />
+        <include layout="@layout/dialpad_key"
+            android:id="@+id/nine"
+            style="@style/DialpadKeyButtonStyle" />
     </TableRow>
 
     <TableRow>
@@ -72,7 +88,9 @@
                     android:layout_width="@dimen/dialpad_key_letters_width" />
             </LinearLayout>
         </com.android.dialer.dialpad.DialpadKeyButton>
-        <include layout="@layout/dialpad_key" android:id="@+id/zero"/>
+        <include layout="@layout/dialpad_key"
+            android:id="@+id/zero"
+            style="@style/DialpadKeyButtonStyle" />
         <com.android.dialer.dialpad.DialpadKeyButton
             android:id="@+id/pound"
             style="@style/DialpadKeyButtonStyle">
@@ -87,4 +105,35 @@
             </LinearLayout>
         </com.android.dialer.dialpad.DialpadKeyButton>
     </TableRow>
+
+    <TableRow>
+        <FrameLayout
+            android:id="@+id/dialpad_add_contact"
+            android:contentDescription="@string/description_add_contact"
+            style="@style/DialpadBottomKeyButtonStyle"
+            android:visibility="invisible"
+            >
+            <ImageView
+                android:src="@drawable/ic_add_person_dk"
+                android:importantForAccessibility="no"
+                android:paddingRight="@dimen/dialpad_key_letters_width"
+                style="@style/DialpadKeyInternalLayoutStyle"
+                />
+        </FrameLayout>
+        <Space
+            style="@style/DialpadBottomKeyButtonStyle"
+            />
+        <FrameLayout
+            android:id="@+id/dialpad_overflow"
+            android:contentDescription="@string/description_dialpad_overflow"
+            style="@style/DialpadBottomKeyButtonStyle"
+            >
+            <ImageView
+                android:src="@drawable/ic_overflow_menu"
+                android:importantForAccessibility="no"
+                android:paddingRight="@dimen/dialpad_key_letters_width"
+                style="@style/DialpadKeyInternalLayoutStyle"
+                />
+        </FrameLayout>
+    </TableRow>
 </TableLayout>
diff --git a/res/layout/dialpad_digits.xml b/res/layout/dialpad_digits.xml
index 21638f0..55fd27e 100644
--- a/res/layout/dialpad_digits.xml
+++ b/res/layout/dialpad_digits.xml
@@ -38,7 +38,6 @@
         android:textSize="@dimen/dialpad_digits_text_size"
         android:freezesText="true"
         android:focusableInTouchMode="true"
-        android:editable="true"
         android:cursorVisible="false"
         android:textColor="@color/dialpad_digits_text_color"
         android:textCursorDrawable="@null"
diff --git a/res/layout/dialpad_fragment.xml b/res/layout/dialpad_fragment.xml
index d285cc3..9d3c620 100644
--- a/res/layout/dialpad_fragment.xml
+++ b/res/layout/dialpad_fragment.xml
@@ -32,13 +32,13 @@
         android:background="@drawable/shadow_fade_up" />
     <view class="com.android.dialer.dialpad.DialpadFragment$HoverIgnoringLinearLayout"
         android:id="@+id/top"
-        android:animateLayoutChanges="true"
         android:layout_height="wrap_content"
         android:layout_width="match_parent"
         android:layout_gravity="bottom"
         android:orientation="vertical"
         android:layoutDirection="ltr"
-        android:background="@color/background_dialpad">
+        android:background="@color/background_dialpad"
+        android:clickable="true">
 
         <Space
             android:layout_width="match_parent"
@@ -47,13 +47,13 @@
 
         <Space
             android:layout_width="match_parent"
-            android:layout_height="10dp" />
+            android:layout_height="5dp" />
 
         <include layout="@layout/dialpad_digits" />
 
         <Space
             android:layout_width="match_parent"
-            android:layout_height="8dp" />
+            android:layout_height="4dp" />
 
         <include layout="@layout/dialpad" />
 
diff --git a/res/layout/dialpad_key.xml b/res/layout/dialpad_key.xml
index 5bf858c..abbe4f9 100644
--- a/res/layout/dialpad_key.xml
+++ b/res/layout/dialpad_key.xml
@@ -17,7 +17,7 @@
 <!-- A layout representing a single key in the dialpad -->
 <com.android.dialer.dialpad.DialpadKeyButton
     xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/DialpadKeyButtonStyle">
+    style="@style/DialpadKeyButtonStyle" >
 
     <LinearLayout style="@style/DialpadKeyInternalLayoutStyle">
 
diff --git a/res/layout/dialtacts_activity.xml b/res/layout/dialtacts_activity.xml
index 2513216..50049af 100644
--- a/res/layout/dialtacts_activity.xml
+++ b/res/layout/dialtacts_activity.xml
@@ -13,7 +13,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<LinearLayout
+<RelativeLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/dialtacts_mainlayout"
     android:layout_width="match_parent"
@@ -27,8 +27,7 @@
     <RelativeLayout
         android:id="@+id/dialtacts_container"
         android:layout_width="match_parent"
-        android:layout_height="0dp"
-        android:layout_weight="1"
+        android:layout_height="match_parent"
         android:clipChildren="false">
         <!-- The main contacts grid -->
         <FrameLayout
@@ -117,45 +116,28 @@
             </com.android.dialer.list.RemoveView>
         </FrameLayout>
     </RelativeLayout>
-    <!-- TODO: To be removed entirely and replaced with a floating action button -->
     <FrameLayout
-        android:layout_height="@dimen/fake_action_bar_height"
-        android:layout_width="match_parent"
-        android:id="@+id/fake_action_bar"
-        android:background="@color/actionbar_background_color">
-        <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/action_menu_call_history_description"
-            android:src="@drawable/ic_menu_history_lt"/>
+        android:layout_height="@dimen/floating_action_button_height"
+        android:layout_width="@dimen/floating_action_button_width"
+        android:layout_marginBottom="@dimen/floating_action_button_margin_bottom"
+        android:id="@+id/floating_action_button"
+        android:background="@color/actionbar_background_color"
+        android:layout_centerHorizontal="true"
+        android:layout_alignParentBottom="true" >
         <ImageButton
             android:id="@+id/dialpad_button"
-            android:layout_width="@dimen/fake_menu_button_min_width"
+            android:layout_width="match_parent"
             android:layout_height="match_parent"
-            android:layout_gravity="bottom|center"
             android:background="?android:attr/selectableItemBackground"
             android:contentDescription="@string/action_menu_dialpad_button"
             android:src="@drawable/ic_menu_dialpad_lt"/>
         <ImageButton
             android:id="@+id/dial_button"
-            android:layout_width="@dimen/fake_action_bar_height"
-            android:layout_height="@dimen/fake_action_bar_height"
-            android:layout_gravity="bottom|center"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
             android:background="@drawable/btn_call"
             android:contentDescription="@string/description_dial_button"
             android:src="@drawable/ic_dial_action_call"
             android:visibility="gone" />
-        <ImageButton
-            android:id="@+id/overflow_menu_button"
-            android:layout_width="@dimen/fake_menu_button_min_width"
-            android:layout_height="match_parent"
-            android:layout_gravity="bottom|end"
-            android:visibility="gone"
-            android:src="@drawable/ic_menu_overflow_lt"
-            android:contentDescription="@string/action_menu_overflow_description"
-            android:background="?android:attr/selectableItemBackground"/>
     </FrameLayout>
-</LinearLayout>
+</RelativeLayout>
diff --git a/res/menu/dialpad_options.xml b/res/menu/dialpad_options.xml
index 0727dd5..27a9b8a 100644
--- a/res/menu/dialpad_options.xml
+++ b/res/menu/dialpad_options.xml
@@ -15,11 +15,6 @@
 -->
 <menu xmlns:android="http://schemas.android.com/apk/res/android">
     <item
-        android:id="@+id/menu_add_contacts"
-        android:title="@string/recentCalls_addToContact"
-        android:showAsAction="withText"
-        android:orderInCategory="1" />
-    <item
         android:id="@+id/menu_2s_pause"
         android:title="@string/add_2sec_pause"
         android:showAsAction="withText"
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 496eb43..4696778 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -51,11 +51,13 @@
     <dimen name="dialpad_key_numbers_width">30dp</dimen>
     <dimen name="dialpad_key_letters_width">50dp</dimen>
     <dimen name="dialpad_key_height">56dp</dimen>
+    <!-- The bottom row of the dialpad is slightly taller to account for the dial button -->
+    <dimen name="dialpad_bottom_key_height">70dp</dimen>
     <dimen name="dialpad_key_plus_size">18sp</dimen>
     <dimen name="dialpad_number_to_letters_padding">11dp</dimen>
     <dimen name="dialpad_horizontal_padding">5dp</dimen>
-    <dimen name="dialpad_digits_text_size">36sp</dimen>
-    <dimen name="dialpad_digits_height">47dp</dimen>
+    <dimen name="dialpad_digits_text_size">33sp</dimen>
+    <dimen name="dialpad_digits_height">55dp</dimen>
     <dimen name="dialpad_digits_padding">16dp</dimen>
     <dimen name="dialpad_digits_margin_bottom">0px</dimen>
     <dimen name="dialpad_center_margin">3dp</dimen>
@@ -63,11 +65,16 @@
     <!-- Match call_button_height to Phone's dimens/in_call_end_button_height -->
     <dimen name="call_button_height">74dp</dimen>
 
-    <dimen name="fake_action_bar_height">60dp</dimen>
-    <!-- Min width of fake menu buttons, which should be same as ActionBar's one -->
-    <dimen name="fake_menu_button_min_width">56dp</dimen>
+    <!-- Height of the floating action button -->
+    <dimen name="floating_action_button_height">60dp</dimen>
+    <!-- Width of the floating action button -->
+    <dimen name="floating_action_button_width">60dp</dimen>
+    <!-- Bottom margin of the floating action button -->
+    <dimen name="floating_action_button_margin_bottom">10dp</dimen>
+    <!-- Z translation of the floating action button -->
+    <dimen name="floating_action_button_translation_z">5dp</dimen>
 
-    <!--  Favorites tile and recent call log padding -->
+    <!-- Dimensions for speed dial tiles -->
     <dimen name="contact_tile_divider_width">1dp</dimen>
     <dimen name="contact_tile_info_button_height_and_width">36dp</dimen>
     <item name="contact_tile_height_to_width_ratio" type="dimen">67%</item>
@@ -76,10 +83,15 @@
     <dimen name="favorites_row_top_padding">1dp</dimen>
     <dimen name="favorites_row_bottom_padding">0dp</dimen>
     <dimen name="favorites_row_start_padding">1dp</dimen>
+
     <!-- Padding from the last contact tile will provide the end padding. -->
     <dimen name="favorites_row_end_padding">0dp</dimen>
     <dimen name="favorites_row_undo_text_side_padding">32dp</dimen>
+
+    <!-- Dimensions for most recent call shortcut cards -->
+    <dimen name="recent_call_log_item_translation_z">5dp</dimen>
     <dimen name="recent_call_log_item_padding">8dp</dimen>
+
     <!-- Size of the star icon on the favorites tile. -->
     <dimen name="favorites_star_icon_size">20dp</dimen>
 
diff --git a/res/values/strings.xml b/res/values/strings.xml
index bd9aefb..2575a0b 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -427,6 +427,9 @@
     -->
     <string name="description_add_contact">Add contact</string>
 
+    <!-- String describing the overflow menu button in the dialpad -->
+    <string name="description_dialpad_overflow">More options</string>
+
     <!-- String describing the button to view the contact for the current number.
 
         Note: AccessibilityServices use this attribute to announce what the view represents.
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 381ee35..a0e8aeb 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -144,6 +144,10 @@
         <item name="android:focusable">true</item>
     </style>
 
+    <style name="DialpadBottomKeyButtonStyle" parent="DialpadKeyButtonStyle">
+        <item name="android:layout_height">@dimen/dialpad_bottom_key_height</item>
+    </style>
+
     <style name="DialpadKeyInternalLayoutStyle">
         <item name="android:layout_width">wrap_content</item>
         <item name="android:layout_height">wrap_content</item>
diff --git a/src/com/android/dialer/DialtactsActivity.java b/src/com/android/dialer/DialtactsActivity.java
index c449e09..5dabb93 100644
--- a/src/com/android/dialer/DialtactsActivity.java
+++ b/src/com/android/dialer/DialtactsActivity.java
@@ -45,6 +45,7 @@
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
+import android.view.View.OnClickListener;
 import android.view.View.OnLayoutChangeListener;
 import android.view.ViewGroup.LayoutParams;
 import android.view.ViewTreeObserver.OnGlobalLayoutListener;
@@ -74,7 +75,7 @@
 import com.android.dialer.list.ListsFragment;
 import com.android.dialer.list.OnDragDropListener;
 import com.android.dialer.list.OnListFragmentScrolledListener;
-import com.android.dialer.list.PhoneFavoriteFragment;
+import com.android.dialer.list.SpeedDialFragment;
 import com.android.dialer.list.PhoneFavoriteTileView;
 import com.android.dialer.list.PhoneFavoriteSquareTileView;
 import com.android.dialer.list.RegularSearchFragment;
@@ -95,7 +96,7 @@
         OnListFragmentScrolledListener,
         DialpadFragment.HostInterface,
         ListsFragment.HostInterface,
-        PhoneFavoriteFragment.HostInterface,
+        SpeedDialFragment.HostInterface,
         OnDragDropListener, View.OnLongClickListener,
         OnPhoneNumberPickerActionListener {
     private static final String TAG = "DialtactsActivity";
@@ -151,12 +152,10 @@
      */
     private ListsFragment mListsFragment;
 
-    private View mFakeActionBar;
+    private View mFloatingActionButton;
     private View mMenuButton;
-    private View mCallHistoryButton;
     private View mDialpadButton;
     private View mDialButton;
-    private PopupMenu mDialpadOverflowMenu;
 
     private View mFragmentsFrame;
 
@@ -207,7 +206,7 @@
         public void show() {
             final Menu menu = getMenu();
             final MenuItem clearFrequents = menu.findItem(R.id.menu_clear_frequents);
-            // TODO: Check mPhoneFavoriteFragment.hasFrequents()
+            // TODO: Check mSpeedDialFragment.hasFrequents()
             clearFrequents.setVisible(true);
             super.show();
         }
@@ -329,16 +328,13 @@
 
         mFragmentsFrame = findViewById(R.id.dialtacts_frame);
 
-        mFakeActionBar = findViewById(R.id.fake_action_bar);
+        mFloatingActionButton = findViewById(R.id.floating_action_button);
+        setupFloatingActionButton(mFloatingActionButton);
 
-        mCallHistoryButton = findViewById(R.id.call_history_button);
-        mCallHistoryButton.setOnClickListener(this);
         mDialButton = findViewById(R.id.dial_button);
         mDialButton.setOnClickListener(this);
         mDialpadButton = findViewById(R.id.dialpad_button);
         mDialpadButton.setOnClickListener(this);
-        mMenuButton = findViewById(R.id.overflow_menu_button);
-        mMenuButton.setOnClickListener(this);
 
         mRemoveViewContainer = (RemoveView) findViewById(R.id.remove_view_container);
         mSearchAndRemoveViewContainer = findViewById(R.id.search_and_remove_view_container);
@@ -416,9 +412,6 @@
     @Override
     public void onClick(View view) {
         switch (view.getId()) {
-            case R.id.overflow_menu_button:
-                mDialpadOverflowMenu.show();
-                break;
             case R.id.dialpad_button:
                 // Reset the boolean flag that tracks whether the dialpad was up because
                 // we were in call. Regardless of whether it was true before, we want to
@@ -427,9 +420,6 @@
                 mInCallDialpadUp = false;
                 showDialpadFragment(true);
                 break;
-            case R.id.call_history_button:
-                showCallHistory();
-                break;
             case R.id.dial_button:
                 // Dial button was pressed; tell the Dialpad fragment
                 mDialpadFragment.dialButtonPressed();
@@ -483,7 +473,7 @@
                 return true;
             case R.id.menu_clear_frequents:
                 // TODO: This should be enabled/disabled based on
-                // PhoneFavoritesFragments.hasFrequents
+                // SpeedDialFragment.hasFrequents
                 ClearFrequentsDialog.show(getFragmentManager());
                 return true;
             case R.id.menu_call_settings:
@@ -582,11 +572,6 @@
     public void onDialpadShown() {
         mDialButton.setVisibility(View.VISIBLE);
         mDialpadButton.setVisibility(View.GONE);
-        mMenuButton.setVisibility(View.VISIBLE);
-        if (mDialpadOverflowMenu == null) {
-            mDialpadOverflowMenu = mDialpadFragment.buildOptionsMenu(mMenuButton);
-            mMenuButton.setOnTouchListener(mDialpadOverflowMenu.getDragToOpenListener());
-        }
 
         SearchFragment fragment = null;
         if (mInDialpadSearch) {
@@ -612,7 +597,6 @@
     public void onDialpadHidden() {
         mDialButton.setVisibility(View.GONE);
         mDialpadButton.setVisibility(View.VISIBLE);
-        mMenuButton.setVisibility(View.GONE);
 
         SearchFragment fragment = null;
         if (mInDialpadSearch) {
@@ -853,9 +837,6 @@
                 // fragment manager correctly figure out whatever fragment was last displayed.
                 return;
             }
-            if (mDialpadFragment != null) {
-                mDialpadOverflowMenu = mDialpadFragment.buildOptionsMenu(mMenuButton);
-            }
             mSearchView.setQuery(normalizedQuery, false);
         }
     }
@@ -884,7 +865,7 @@
 
     @Override
     public void setDialButtonContainerVisible(boolean visible) {
-        mFakeActionBar.setVisibility(visible ? View.VISIBLE : View.GONE);
+        mFloatingActionButton.setVisibility(visible ? View.VISIBLE : View.GONE);
     }
 
     private boolean phoneIsInUse() {
@@ -907,6 +888,34 @@
         return resolveInfo != null && resolveInfo.size() > 0;
     }
 
+    private void setupFloatingActionButton(View view) {
+        // Once layout is complete and the floating action button has been assigned a width
+        // and height, assign the outline.
+        view.addOnLayoutChangeListener(new OnLayoutChangeListener() {
+            @Override
+            public void onLayoutChange(View v,
+                    int left,
+                    int top,
+                    int right,
+                    int bottom,
+                    int oldLeft,
+                    int oldTop,
+                    int oldRight,
+                    int oldBottom) {
+                final Outline outline = new Outline();
+                final int minDimension = Math.min(right - left, bottom - top);
+                if (minDimension <= 0) {
+                    return;
+                }
+                outline.setRoundRect(0, 0, right - left, bottom - top, minDimension / 2);
+                v.setOutline(outline);
+                v.setClipToOutline(true);
+            }
+        });
+        view.setTranslationZ(getResources().getDimensionPixelSize(
+                R.dimen.floating_action_button_translation_z));
+    }
+
     @Override
     public void showCallHistory() {
         // Use explicit CallLogActivity intent instead of ACTION_VIEW +
@@ -940,7 +949,7 @@
     public void onDroppedOnRemove() {}
 
     /**
-     * Allows the PhoneFavoriteFragment to attach the drag controller to mRemoveViewContainer
+     * Allows the SpeedDialFragment to attach the drag controller to mRemoveViewContainer
      * once it has been attached to the activity.
      */
     @Override
diff --git a/src/com/android/dialer/dialpad/DialpadFragment.java b/src/com/android/dialer/dialpad/DialpadFragment.java
index 703c277..72abaa0 100644
--- a/src/com/android/dialer/dialpad/DialpadFragment.java
+++ b/src/com/android/dialer/dialpad/DialpadFragment.java
@@ -76,9 +76,11 @@
 import com.android.dialer.DialtactsActivity;
 import com.android.dialer.R;
 import com.android.dialer.SpecialCharSequenceMgr;
+import com.android.dialer.util.DialerUtils;
 import com.android.internal.telephony.ITelephony;
 import com.android.phone.common.CallLogAsync;
 import com.android.phone.common.HapticFeedback;
+
 import com.google.common.annotations.VisibleForTesting;
 
 import java.util.HashSet;
@@ -199,6 +201,8 @@
     /** Remembers if we need to clear digits field when the screen is completely gone. */
     private boolean mClearDigitsOnStop;
 
+    private View mAddContactButton;
+    private View mOverflowMenuButton;
     private View mDelete;
     private ToneGenerator mToneGenerator;
     private final Object mToneGeneratorLock = new Object();
@@ -333,6 +337,9 @@
         if (isDigitsEmpty()) {
             mDigitsFilledByIntent = false;
             mDigits.setCursorVisible(false);
+            mAddContactButton.setVisibility(View.INVISIBLE);
+        } else {
+            mAddContactButton.setVisibility(View.VISIBLE);
         }
 
         if (mDialpadQueryListener != null) {
@@ -612,8 +619,6 @@
 
         for (int i = 0; i < buttonIds.length; i++) {
             dialpadKey = (DialpadKeyButton) fragmentView.findViewById(buttonIds[i]);
-            dialpadKey.setLayoutParams(new TableRow.LayoutParams(
-                    TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.MATCH_PARENT));
             dialpadKey.setOnPressedListener(this);
             numberView = (TextView) dialpadKey.findViewById(R.id.dialpad_key_number);
             lettersView = (TextView) dialpadKey.findViewById(R.id.dialpad_key_letters);
@@ -637,6 +642,13 @@
         zero.setLongHoverContentDescription(
                 resources.getText(R.string.description_image_button_plus));
 
+        mAddContactButton = fragmentView.findViewById(R.id.dialpad_add_contact);
+        mAddContactButton.setOnClickListener(this);
+
+        mOverflowMenuButton = fragmentView.findViewById(R.id.dialpad_overflow);
+        mOverflowMenuButton.setOnClickListener(this);
+        final PopupMenu overflowMenu = buildOptionsMenu(mOverflowMenuButton);
+        mOverflowMenuButton.setOnTouchListener(overflowMenu.getDragToOpenListener());
     }
 
     @Override
@@ -768,22 +780,6 @@
         outState.putBoolean(PREF_DIGITS_FILLED_BY_INTENT, mDigitsFilledByIntent);
     }
 
-    private void setupMenuItems(Menu menu) {
-        final MenuItem addToContactMenuItem = menu.findItem(R.id.menu_add_contacts);
-
-        // We show "add to contacts" menu only when the user is
-        // seeing usual dialpad and has typed at least one digit.
-        // We never show a menu if the "choose dialpad" UI is up.
-        if (dialpadChooserVisible() || isDigitsEmpty()) {
-            addToContactMenuItem.setVisible(false);
-        } else {
-            final CharSequence digits = mDigits.getText();
-            // Put the current digits string into an intent
-            addToContactMenuItem.setIntent(DialtactsActivity.getAddNumberToContactIntent(digits));
-            addToContactMenuItem.setVisible(true);
-        }
-    }
-
     private void keyPressed(int keyCode) {
         if (getView().getTranslationY() != 0) {
             return;
@@ -937,7 +933,6 @@
         final PopupMenu popupMenu = new PopupMenu(getActivity(), invoker);
         popupMenu.inflate(R.menu.dialpad_options);
         popupMenu.setOnMenuItemClickListener(this);
-        setupMenuItems(popupMenu.getMenu());
         return popupMenu;
     }
 
@@ -963,6 +958,16 @@
                 }
                 return;
             }
+            case R.id.dialpad_add_contact: {
+                final CharSequence digits = mDigits.getText();
+                DialerUtils.startActivityWithErrorToast(getActivity(),
+                        DialtactsActivity.getAddNumberToContactIntent(digits));
+                return;
+            }
+            case R.id.dialpad_overflow: {
+                buildOptionsMenu(view).show();
+                break;
+            }
             default: {
                 Log.wtf(TAG, "Unexpected onClick() event from: " + view);
                 return;
diff --git a/src/com/android/dialer/list/AllContactsFragment.java b/src/com/android/dialer/list/AllContactsFragment.java
index ba48203..50f23aa 100644
--- a/src/com/android/dialer/list/AllContactsFragment.java
+++ b/src/com/android/dialer/list/AllContactsFragment.java
@@ -16,6 +16,9 @@
 
 package com.android.dialer.list;
 
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.ContactsContract.QuickContact;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -35,7 +38,7 @@
 public class AllContactsFragment extends ContactEntryListFragment<ContactEntryListAdapter> {
 
     public AllContactsFragment() {
-        setQuickContactEnabled(true);
+        setQuickContactEnabled(false);
         setPhotoLoaderEnabled(true);
         setSectionHeaderDisplayEnabled(true);
         setDarkTheme(false);
@@ -44,7 +47,13 @@
 
     @Override
     protected ContactEntryListAdapter createListAdapter() {
-        DefaultContactListAdapter adapter = new DefaultContactListAdapter(getActivity());
+        final DefaultContactListAdapter adapter = new DefaultContactListAdapter(getActivity()) {
+            @Override
+            protected void bindView(View itemView, int partition, Cursor cursor, int position) {
+                super.bindView(itemView, partition, cursor, position);
+                itemView.setTag(this.getContactUri(partition, cursor));
+            }
+        };
         adapter.setDisplayPhotos(true);
         adapter.setFilter(ContactListFilter.createFilterWithType(
                 ContactListFilter.FILTER_TYPE_WITH_PHONE_NUMBERS_ONLY));
@@ -60,9 +69,10 @@
 
     @Override
     public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-        ContactListItemView contactListItemView = (ContactListItemView) view;
-        QuickContactBadge quickContact = contactListItemView.getQuickContact();
-        quickContact.onClick(quickContact);
+        final Uri uri = (Uri) view.getTag();
+        if (uri != null) {
+            QuickContact.showQuickContact(getActivity(), view, uri, QuickContact.MODE_LARGE, null);
+        }
     }
 
     @Override
diff --git a/src/com/android/dialer/list/ListsFragment.java b/src/com/android/dialer/list/ListsFragment.java
index b91f09a..676b3b0 100644
--- a/src/com/android/dialer/list/ListsFragment.java
+++ b/src/com/android/dialer/list/ListsFragment.java
@@ -65,13 +65,13 @@
 
     private ViewPager mViewPager;
     private ViewPagerAdapter mViewPagerAdapter;
-    private PhoneFavoriteFragment mSpeedDialFragment;
+    private SpeedDialFragment mSpeedDialFragment;
     private CallLogFragment mRecentsFragment;
     private AllContactsFragment mAllContactsFragment;
 
     private String[] mTabTitles;
 
-    private PhoneFavoriteMergedAdapter mMergedAdapter;
+    private ShortcutCardsAdapter mMergedAdapter;
     private CallLogAdapter mCallLogAdapter;
     private CallLogQueryHandler mCallLogQueryHandler;
 
@@ -116,7 +116,7 @@
         public Fragment getItem(int position) {
             switch (position) {
                 case TAB_INDEX_SPEED_DIAL:
-                    mSpeedDialFragment = new PhoneFavoriteFragment();
+                    mSpeedDialFragment = new SpeedDialFragment();
                     return mSpeedDialFragment;
                 case TAB_INDEX_RECENTS:
                     mRecentsFragment = new CallLogFragment(CallLogQueryHandler.CALL_TYPE_ALL,
@@ -168,8 +168,7 @@
         mCallLogAdapter = ObjectFactory.newCallLogAdapter(getActivity(), this,
                 new ContactInfoHelper(getActivity(), currentCountryIso), false, false);
 
-        mMergedAdapter = new PhoneFavoriteMergedAdapter(getActivity(), this, null,
-                mCallLogAdapter, null, null);
+        mMergedAdapter = new ShortcutCardsAdapter(getActivity(), this, mCallLogAdapter);
     }
 
     @Override
diff --git a/src/com/android/dialer/list/PhoneFavoriteMergedAdapter.java b/src/com/android/dialer/list/PhoneFavoriteMergedAdapter.java
deleted file mode 100644
index 03ff67e..0000000
--- a/src/com/android/dialer/list/PhoneFavoriteMergedAdapter.java
+++ /dev/null
@@ -1,396 +0,0 @@
-/*
- * Copyright (C) 2011 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;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.database.DataSetObserver;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.FrameLayout;
-
-import com.android.dialer.R;
-import com.android.dialer.calllog.CallLogAdapter;
-import com.android.dialer.calllog.CallLogNotificationsHelper;
-import com.android.dialer.calllog.CallLogQueryHandler;
-import com.android.dialer.list.SwipeHelper.OnItemGestureListener;
-import com.android.dialer.list.SwipeHelper.SwipeHelperCallback;
-
-/**
- * An adapter that combines items from {@link com.android.contacts.common.list.ContactTileAdapter}
- * and {@link com.android.dialer.calllog.CallLogAdapter} into a single list.
- */
-public class PhoneFavoriteMergedAdapter extends BaseAdapter {
-
-    private class CustomDataSetObserver extends DataSetObserver {
-        @Override
-        public void onChanged() {
-            notifyDataSetChanged();
-        }
-    }
-
-    private static final String TAG = PhoneFavoriteMergedAdapter.class.getSimpleName();
-
-    private static final int TILE_INTERACTION_TEASER_VIEW_POSITION = 3;
-    private static final int TILE_INTERACTION_TEASER_VIEW_ID = -2;
-    private static final int FAVORITES_MENU_ITEM_ID = -3;
-    private final PhoneFavoritesTileAdapter mContactTileAdapter;
-    private final CallLogAdapter mCallLogAdapter;
-    private final View mPhoneFavoritesMenu;
-    private final ListsFragment mFragment;
-    private final TileInteractionTeaserView mTileInteractionTeaserView;
-
-    private final int mCallLogPadding;
-
-    private final Context mContext;
-
-    private final DataSetObserver mObserver;
-
-    private final CallLogQueryHandler mCallLogQueryHandler;
-
-    private final OnItemGestureListener mCallLogOnItemSwipeListener =
-            new OnItemGestureListener() {
-        @Override
-        public void onSwipe(View view) {
-            mCallLogQueryHandler.markNewCallsAsOld();
-            mCallLogQueryHandler.markNewVoicemailsAsOld();
-            CallLogNotificationsHelper.removeMissedCallNotifications();
-            CallLogNotificationsHelper.updateVoicemailNotifications(mContext);
-            mFragment.dismissShortcut(view);
-        }
-
-        @Override
-        public void onTouch() {}
-
-        @Override
-        public boolean isSwipeEnabled() {
-            return true;
-        }
-    };
-
-    private final CallLogQueryHandler.Listener mCallLogQueryHandlerListener =
-            new CallLogQueryHandler.Listener() {
-        @Override
-        public void onVoicemailStatusFetched(Cursor statusCursor) {}
-
-        @Override
-        public void onCallsFetched(Cursor combinedCursor) {
-            mCallLogAdapter.invalidateCache();
-            mCallLogAdapter.changeCursor(combinedCursor);
-            mCallLogAdapter.notifyDataSetChanged();
-        }
-    };
-
-    public PhoneFavoriteMergedAdapter(Context context,
-            ListsFragment fragment,
-            PhoneFavoritesTileAdapter contactTileAdapter,
-            CallLogAdapter callLogAdapter,
-            View phoneFavoritesMenu,
-            TileInteractionTeaserView tileInteractionTeaserView) {
-        final Resources resources = context.getResources();
-        mContext = context;
-        mFragment = fragment;
-        mCallLogPadding = resources.getDimensionPixelSize(R.dimen.recent_call_log_item_padding);
-        mContactTileAdapter = contactTileAdapter;
-        mCallLogAdapter = callLogAdapter;
-        mObserver = new CustomDataSetObserver();
-        mCallLogAdapter.registerDataSetObserver(mObserver);
-        mPhoneFavoritesMenu = phoneFavoritesMenu;
-        mTileInteractionTeaserView = tileInteractionTeaserView;
-        mCallLogQueryHandler = new CallLogQueryHandler(mContext.getContentResolver(),
-                mCallLogQueryHandlerListener);
-    }
-
-    /**
-     * Determines the number of items in the adapter.
-     * mCallLogAdapter contains the item for the most recent caller.
-     * mContactTileAdapter contains the starred contacts.
-     * The +1 is to account for the presence of the favorites menu.
-     *
-     * @return Number of items in the adapter.
-     */
-    @Override
-    public int getCount() {
-        return mCallLogAdapter.getCount();
-    }
-
-    @Override
-    public Object getItem(int position) {
-        final int callLogAdapterCount = mCallLogAdapter.getCount();
-
-        if (callLogAdapterCount > 0) {
-            if (position < callLogAdapterCount) {
-                return mCallLogAdapter.getItem(position);
-            }
-        }
-        // Set position to the position of the actual favorite contact in the favorites adapter
-        position = getAdjustedPositionInContactTileAdapter(position);
-
-        return mContactTileAdapter.getItem(position);
-    }
-
-    /**
-     * In order to ensure that items have stable ids (for animation purposes), we need to
-     * guarantee that every single item has a unique ID, even across data set changes.
-     *
-     * These are the ranges of IDs reserved for each item type.
-     *
-     * -4 and lower: CallLogAdapterItems representing most recent call.
-     * -3: Favorites menu
-     * -2: Teaser
-     * 0 to (N -1): Rows of tiled contacts, where N is equal to the max rows of tiled contacts
-     * N to infinity: Rows of regular contacts. Their item id is calculated by N + contact_id,
-     * where contact_id is guaranteed to never be negative.
-     */
-    @Override
-    public long getItemId(int position) {
-        final int callLogAdapterCount = mCallLogAdapter.getCount();
-        if (position < callLogAdapterCount) {
-            // Call log items are not animated, so reusing their position for IDs is fine.
-            return FAVORITES_MENU_ITEM_ID - 1 - position;
-        } else if (position == TILE_INTERACTION_TEASER_VIEW_POSITION + callLogAdapterCount &&
-                mTileInteractionTeaserView.getShouldDisplayInList()) {
-            return TILE_INTERACTION_TEASER_VIEW_ID;
-        } else if (position == callLogAdapterCount) {
-            return FAVORITES_MENU_ITEM_ID;
-        } else if (position < (callLogAdapterCount + mContactTileAdapter.getCount() +
-                getTeaserViewCount() + 1)) {
-            return mContactTileAdapter.getItemId(
-                    getAdjustedPositionInContactTileAdapter(position));
-        } else {
-            // Default fallback.  We don't normally get here.
-            return FAVORITES_MENU_ITEM_ID;
-        }
-    }
-
-    @Override
-    public boolean hasStableIds() {
-        return true;
-    }
-
-    /**
-     * Determine the number of view types present.
-     */
-    @Override
-    public int getViewTypeCount() {
-        return mCallLogAdapter.getViewTypeCount();
-    }
-
-    @Override
-    public int getItemViewType(int position) {
-        final int callLogAdapterCount = mCallLogAdapter.getCount();
-
-        if (position < callLogAdapterCount) {
-            return 0;
-        } else if (position == TILE_INTERACTION_TEASER_VIEW_POSITION + callLogAdapterCount &&
-                mTileInteractionTeaserView.getShouldDisplayInList()) {
-            // View type of the teaser row is the last view type of the contact tile adapter +2
-            return mContactTileAdapter.getViewTypeCount() + 2;
-        } else if (position == callLogAdapterCount) {
-            // View type of the favorites menu is last view type of contact tile adapter +3
-            return mContactTileAdapter.getViewTypeCount() + 3;
-        } else if (position < getCount()) {
-            return mContactTileAdapter.getItemViewType(
-                    getAdjustedPositionInContactTileAdapter(position));
-        } else {
-            // Catch-all - we shouldn't get here but if we do use the same as the favorites menu.
-            return mContactTileAdapter.getViewTypeCount() + 3;
-        }
-    }
-
-    /**
-     * Determines the view for a specified position.
-     *
-     * @param position Position for which to retrieve view.
-     * @return view corresponding to position.
-     */
-    @Override
-    public View getView(int position, View convertView, ViewGroup parent) {
-        final int callLogAdapterCount = mCallLogAdapter.getCount();
-
-        if (callLogAdapterCount > 0 && position < callLogAdapterCount) {
-            // Handle case where we are requesting the view for the "most recent caller".
-
-            final SwipeableCallLogRow wrapper;
-            if (convertView == null) {
-                wrapper = new SwipeableCallLogRow(mContext);
-                wrapper.setOnItemSwipeListener(mCallLogOnItemSwipeListener);
-            } else {
-                wrapper = (SwipeableCallLogRow) convertView;
-            }
-
-            // Special case wrapper view for the most recent call log item. This allows
-            // us to create a card-like effect for the more recent call log item in
-            // the PhoneFavoriteMergedAdapter, but keep the original look of the item in
-            // the CallLogAdapter.
-            final View view = mCallLogAdapter.getView(position, convertView == null ?
-                    null : wrapper.getChildAt(0), parent);
-            wrapper.removeAllViews();
-            final View callLogItem = view.findViewById(R.id.call_log_list_item);
-            // Reset the internal call log item view if it is being recycled
-            callLogItem.setTranslationX(0);
-            callLogItem.setAlpha(1);
-            wrapper.addView(view);
-            return wrapper;
-        } else if (position == callLogAdapterCount) {
-            // If position is just after the entries in the mCallLogAdapter (most recent call),
-            // return the favorites menu.
-            return mPhoneFavoritesMenu;
-        }
-
-        // Set position to the position of the actual favorite contact in the favorites adapter.
-        // Adjusts based on the presence of other views, such as the favorites menu.
-        position = getAdjustedPositionInContactTileAdapter(position);
-
-        // Favorites section
-        final View view = mContactTileAdapter.getView(position, convertView, parent);
-        return view;
-    }
-
-    @Override
-    public boolean areAllItemsEnabled() {
-        return mCallLogAdapter.areAllItemsEnabled();
-    }
-
-    @Override
-    public boolean isEnabled(int position) {
-        final int callLogAdapterCount = mCallLogAdapter.getCount();
-        if (position < callLogAdapterCount) {
-            return mCallLogAdapter.isEnabled(position);
-        } else { // For favorites section
-            return mContactTileAdapter.isEnabled(
-                    getAdjustedPositionInContactTileAdapter(position));
-        }
-    }
-
-    /**
-     * Given the current position in the merged adapter, return the index in the
-     * mContactTileAdapter this position corresponds to.
-     *
-     * @param position current position in the overall (merged) adapter.
-     * @return position in the mContactTileAdapter.
-     */
-    public int getAdjustedPositionInContactTileAdapter(int position) {
-        final int callLogAdapterCount = mCallLogAdapter.getCount();
-        if (position - callLogAdapterCount > TILE_INTERACTION_TEASER_VIEW_POSITION &&
-                mTileInteractionTeaserView.getShouldDisplayInList()) {
-            return position - callLogAdapterCount - 2;
-        } else {
-            return position - callLogAdapterCount - 1;
-        }
-    }
-
-    /**
-     * Determines the number of teaser views visible.
-     * @return 1 or 0 depending on if the teaser view is showing.
-     */
-    private int getTeaserViewCount() {
-        return (mContactTileAdapter.getCount() > TILE_INTERACTION_TEASER_VIEW_POSITION &&
-                mTileInteractionTeaserView.getShouldDisplayInList() ? 1 : 0);
-    }
-
-    /**
-     * The swipeable call log row.
-     */
-    private class SwipeableCallLogRow extends FrameLayout implements SwipeHelperCallback {
-        private SwipeHelper mSwipeHelper;
-        private OnItemGestureListener mOnItemSwipeListener;
-
-        public SwipeableCallLogRow(Context context) {
-            super(context);
-            final float densityScale = getResources().getDisplayMetrics().density;
-            final float pagingTouchSlop = ViewConfiguration.get(context)
-                    .getScaledPagingTouchSlop();
-            mSwipeHelper = new SwipeHelper(context, SwipeHelper.X, this,
-                    densityScale, pagingTouchSlop);
-        }
-
-        @Override
-        public void addView(View view) {
-            view.setBackgroundResource(R.drawable.ic_tile_for_recents_and_contact_tile);
-
-            final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
-                    FrameLayout.LayoutParams.MATCH_PARENT,
-                    FrameLayout.LayoutParams.WRAP_CONTENT);
-            params.setMargins(mCallLogPadding, mCallLogPadding, mCallLogPadding, mCallLogPadding);
-            view.setLayoutParams(params);
-
-            super.addView(view);
-        }
-
-        @Override
-        public View getChildAtPosition(MotionEvent ev) {
-            return getChildCount() > 0 ? getChildAt(0) : null;
-        }
-
-        @Override
-        public View getChildContentView(View v) {
-            return v.findViewById(R.id.call_log_list_item);
-        }
-
-        @Override
-        public void onScroll() {}
-
-        @Override
-        public boolean canChildBeDismissed(View v) {
-            return true;
-        }
-
-        @Override
-        public void onBeginDrag(View v) {
-            // We do this so the underlying ScrollView knows that it won't get
-            // the chance to intercept events anymore
-            requestDisallowInterceptTouchEvent(true);
-        }
-
-        @Override
-        public void onChildDismissed(View v) {
-            if (v != null && mOnItemSwipeListener != null) {
-                mOnItemSwipeListener.onSwipe(v);
-            }
-        }
-
-        @Override
-        public void onDragCancelled(View v) {}
-
-        @Override
-        public boolean onInterceptTouchEvent(MotionEvent ev) {
-            if (mSwipeHelper != null) {
-                return mSwipeHelper.onInterceptTouchEvent(ev) || super.onInterceptTouchEvent(ev);
-            } else {
-                return super.onInterceptTouchEvent(ev);
-            }
-        }
-
-        @Override
-        public boolean onTouchEvent(MotionEvent ev) {
-            if (mSwipeHelper != null) {
-                return mSwipeHelper.onTouchEvent(ev) || super.onTouchEvent(ev);
-            } else {
-                return super.onTouchEvent(ev);
-            }
-        }
-
-        public void setOnItemSwipeListener(OnItemGestureListener listener) {
-            mOnItemSwipeListener = listener;
-        }
-    }
-}
diff --git a/src/com/android/dialer/list/ShortcutCardsAdapter.java b/src/com/android/dialer/list/ShortcutCardsAdapter.java
new file mode 100644
index 0000000..0009ee5
--- /dev/null
+++ b/src/com/android/dialer/list/ShortcutCardsAdapter.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2011 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;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.database.DataSetObserver;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.FrameLayout;
+
+import com.android.dialer.R;
+import com.android.dialer.calllog.CallLogAdapter;
+import com.android.dialer.calllog.CallLogNotificationsHelper;
+import com.android.dialer.calllog.CallLogQueryHandler;
+import com.android.dialer.list.SwipeHelper.OnItemGestureListener;
+import com.android.dialer.list.SwipeHelper.SwipeHelperCallback;
+
+/**
+ * An adapter that displays call shortcuts from {@link com.android.dialer.calllog.CallLogAdapter}
+ * in the form of cards.
+ */
+public class ShortcutCardsAdapter extends BaseAdapter {
+
+    private class CustomDataSetObserver extends DataSetObserver {
+        @Override
+        public void onChanged() {
+            notifyDataSetChanged();
+        }
+    }
+
+    private static final String TAG = ShortcutCardsAdapter.class.getSimpleName();
+
+    private final CallLogAdapter mCallLogAdapter;
+    private final ListsFragment mFragment;
+
+    private final int mCallLogPadding;
+
+    private final Context mContext;
+
+    private final DataSetObserver mObserver;
+
+    private final CallLogQueryHandler mCallLogQueryHandler;
+
+    private final OnItemGestureListener mCallLogOnItemSwipeListener =
+            new OnItemGestureListener() {
+        @Override
+        public void onSwipe(View view) {
+            mCallLogQueryHandler.markNewCallsAsOld();
+            mCallLogQueryHandler.markNewVoicemailsAsOld();
+            CallLogNotificationsHelper.removeMissedCallNotifications();
+            CallLogNotificationsHelper.updateVoicemailNotifications(mContext);
+            mFragment.dismissShortcut(view);
+        }
+
+        @Override
+        public void onTouch() {}
+
+        @Override
+        public boolean isSwipeEnabled() {
+            return true;
+        }
+    };
+
+    private final CallLogQueryHandler.Listener mCallLogQueryHandlerListener =
+            new CallLogQueryHandler.Listener() {
+        @Override
+        public void onVoicemailStatusFetched(Cursor statusCursor) {}
+
+        @Override
+        public void onCallsFetched(Cursor combinedCursor) {
+            mCallLogAdapter.invalidateCache();
+            mCallLogAdapter.changeCursor(combinedCursor);
+            mCallLogAdapter.notifyDataSetChanged();
+        }
+    };
+
+    public ShortcutCardsAdapter(Context context,
+            ListsFragment fragment,
+            CallLogAdapter callLogAdapter) {
+        final Resources resources = context.getResources();
+        mContext = context;
+        mFragment = fragment;
+        mCallLogPadding = resources.getDimensionPixelSize(R.dimen.recent_call_log_item_padding);
+        mCallLogAdapter = callLogAdapter;
+        mObserver = new CustomDataSetObserver();
+        mCallLogAdapter.registerDataSetObserver(mObserver);
+        mCallLogQueryHandler = new CallLogQueryHandler(mContext.getContentResolver(),
+                mCallLogQueryHandlerListener);
+    }
+
+    /**
+     * Determines the number of items in the adapter.
+     * mCallLogAdapter contains the item for the most recent caller.
+     * mContactTileAdapter contains the starred contacts.
+     * The +1 is to account for the presence of the favorites menu.
+     *
+     * @return Number of items in the adapter.
+     */
+    @Override
+    public int getCount() {
+        return mCallLogAdapter.getCount();
+    }
+
+    @Override
+    public Object getItem(int position) {
+        return mCallLogAdapter.getItem(position);
+    }
+
+    @Override
+    public long getItemId(int position) {
+        return position;
+    }
+
+    @Override
+    public boolean hasStableIds() {
+        return true;
+    }
+
+    /**
+     * Determine the number of view types present.
+     */
+    @Override
+    public int getViewTypeCount() {
+        return mCallLogAdapter.getViewTypeCount();
+    }
+
+    @Override
+    public int getItemViewType(int position) {
+        return mCallLogAdapter.getItemViewType(position);
+    }
+
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+        final SwipeableCallLogRow wrapper;
+        if (convertView == null) {
+            wrapper = new SwipeableCallLogRow(mContext);
+            wrapper.setOnItemSwipeListener(mCallLogOnItemSwipeListener);
+        } else {
+            wrapper = (SwipeableCallLogRow) convertView;
+        }
+
+        // Special case wrapper view for the most recent call log item. This allows
+        // us to create a card-like effect for the more recent call log item in
+        // the PhoneFavoriteMergedAdapter, but keep the original look of the item in
+        // the CallLogAdapter.
+        final View view = mCallLogAdapter.getView(position, convertView == null ?
+                null : wrapper.getChildAt(0), parent);
+        wrapper.removeAllViews();
+        final View callLogItem = view.findViewById(R.id.call_log_list_item);
+        // Reset the internal call log item view if it is being recycled
+        callLogItem.setTranslationX(0);
+        callLogItem.setAlpha(1);
+        wrapper.addView(view);
+        return wrapper;
+    }
+
+    @Override
+    public boolean areAllItemsEnabled() {
+        return mCallLogAdapter.areAllItemsEnabled();
+    }
+
+    @Override
+    public boolean isEnabled(int position) {
+        return mCallLogAdapter.isEnabled(position);
+    }
+
+    /**
+     * The swipeable call log row.
+     */
+    private class SwipeableCallLogRow extends FrameLayout implements SwipeHelperCallback {
+        private SwipeHelper mSwipeHelper;
+        private OnItemGestureListener mOnItemSwipeListener;
+
+        public SwipeableCallLogRow(Context context) {
+            super(context);
+            final float densityScale = getResources().getDisplayMetrics().density;
+            final float pagingTouchSlop = ViewConfiguration.get(context)
+                    .getScaledPagingTouchSlop();
+            mSwipeHelper = new SwipeHelper(context, SwipeHelper.X, this,
+                    densityScale, pagingTouchSlop);
+        }
+
+        @Override
+        public void addView(View view) {
+            view.setBackgroundResource(R.drawable.ic_tile_for_recents_and_contact_tile);
+
+            final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
+                    FrameLayout.LayoutParams.MATCH_PARENT,
+                    FrameLayout.LayoutParams.WRAP_CONTENT);
+            params.setMargins(mCallLogPadding, mCallLogPadding, mCallLogPadding, mCallLogPadding);
+            view.setLayoutParams(params);
+            view.setTranslationZ(getResources().getDimensionPixelSize(
+                    R.dimen.recent_call_log_item_translation_z));
+
+            super.addView(view);
+        }
+
+        @Override
+        public View getChildAtPosition(MotionEvent ev) {
+            return getChildCount() > 0 ? getChildAt(0) : null;
+        }
+
+        @Override
+        public View getChildContentView(View v) {
+            return v.findViewById(R.id.call_log_list_item);
+        }
+
+        @Override
+        public void onScroll() {}
+
+        @Override
+        public boolean canChildBeDismissed(View v) {
+            return true;
+        }
+
+        @Override
+        public void onBeginDrag(View v) {
+            // We do this so the underlying ScrollView knows that it won't get
+            // the chance to intercept events anymore
+            requestDisallowInterceptTouchEvent(true);
+        }
+
+        @Override
+        public void onChildDismissed(View v) {
+            if (v != null && mOnItemSwipeListener != null) {
+                mOnItemSwipeListener.onSwipe(v);
+            }
+        }
+
+        @Override
+        public void onDragCancelled(View v) {}
+
+        @Override
+        public boolean onInterceptTouchEvent(MotionEvent ev) {
+            if (mSwipeHelper != null) {
+                return mSwipeHelper.onInterceptTouchEvent(ev) || super.onInterceptTouchEvent(ev);
+            } else {
+                return super.onInterceptTouchEvent(ev);
+            }
+        }
+
+        @Override
+        public boolean onTouchEvent(MotionEvent ev) {
+            if (mSwipeHelper != null) {
+                return mSwipeHelper.onTouchEvent(ev) || super.onTouchEvent(ev);
+            } else {
+                return super.onTouchEvent(ev);
+            }
+        }
+
+        public void setOnItemSwipeListener(OnItemGestureListener listener) {
+            mOnItemSwipeListener = listener;
+        }
+    }
+}
diff --git a/src/com/android/dialer/list/PhoneFavoriteFragment.java b/src/com/android/dialer/list/SpeedDialFragment.java
similarity index 95%
rename from src/com/android/dialer/list/PhoneFavoriteFragment.java
rename to src/com/android/dialer/list/SpeedDialFragment.java
index 05e2d44..9de75bb 100644
--- a/src/com/android/dialer/list/PhoneFavoriteFragment.java
+++ b/src/com/android/dialer/list/SpeedDialFragment.java
@@ -50,14 +50,9 @@
 import java.util.HashMap;
 
 /**
- * Fragment for Phone UI's favorite screen.
- *
- * This fragment contains three kinds of contacts in one screen: "starred", "frequent", and "all"
- * contacts. To show them at once, this merges results from {@link com.android.contacts.common.list.ContactTileAdapter} and
- * {@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.
+ * This fragment displays the user's favorite/frequent contacts in a grid.
  */
-public class PhoneFavoriteFragment extends Fragment implements OnItemClickListener,
+public class SpeedDialFragment extends Fragment implements OnItemClickListener,
         PhoneFavoritesTileAdapter.OnDataSetChangedForAnimationListener {
 
     /**
@@ -69,7 +64,7 @@
      */
     private static final long KEY_REMOVED_ITEM_HEIGHT = Long.MAX_VALUE;
 
-    private static final String TAG = PhoneFavoriteFragment.class.getSimpleName();
+    private static final String TAG = SpeedDialFragment.class.getSimpleName();
     private static final boolean DEBUG = false;
 
     private int mAnimationDuration;
diff --git a/src/com/android/dialer/list/TileInteractionTeaserView.java b/src/com/android/dialer/list/TileInteractionTeaserView.java
index 6e70fd1..fd5ed34 100644
--- a/src/com/android/dialer/list/TileInteractionTeaserView.java
+++ b/src/com/android/dialer/list/TileInteractionTeaserView.java
@@ -31,7 +31,7 @@
     private int mTextTop;
     private int mAnimatedHeight = -1;
 
-    private PhoneFavoriteMergedAdapter mAdapter;
+    private ShortcutCardsAdapter mAdapter;
 
     public TileInteractionTeaserView(final Context context) {
         this(context, null);
@@ -91,7 +91,7 @@
         return prefs.getBoolean(KEY_TILE_INTERACTION_TEASER_SHOWN, true);
     }
 
-    public void setAdapter(PhoneFavoriteMergedAdapter adapter) {
+    public void setAdapter(ShortcutCardsAdapter adapter) {
         mAdapter = adapter;
     }