merge in klp-release history after reset to klp-dev
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index f0b4d82..7d7071e 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -32,7 +32,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"Gesprekkenoverzicht is leeg"</string>
     <string name="clearCallLogConfirmation_title" msgid="6427524640461816332">"Oproeplog wissen?"</string>
     <string name="clearCallLogConfirmation" msgid="5043563133171583152">"Al uw oproepgegevens worden verwijderd."</string>
-    <string name="clearCallLogProgress_title" msgid="8365943000154295771">"Oproeplogboek wissen..."</string>
+    <string name="clearCallLogProgress_title" msgid="8365943000154295771">"Gesprekkenlijst wissen..."</string>
   <plurals name="notification_voicemail_title">
     <item quantity="one" msgid="1746619685488504230">"Voicemail"</item>
     <item quantity="other" msgid="5513481419205061254">"<xliff:g id="COUNT">%1$d</xliff:g> voicemails"</item>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 2717049..90ed648 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -24,12 +24,12 @@
     <string name="menu_sendTextMessage" msgid="6937343460284499306">"发送短信"</string>
     <string name="recentCalls_callNumber" msgid="1756372533999226126">"呼叫<xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="recentCalls_editNumberBeforeCall" msgid="7756171675833267857">"呼叫之前编辑号码"</string>
-    <string name="recentCalls_addToContact" msgid="1429899535546487008">"添加到“联系人”"</string>
+    <string name="recentCalls_addToContact" msgid="1429899535546487008">"添加到通讯录"</string>
     <string name="recentCalls_removeFromRecentList" msgid="401662244636511330">"从通话记录中删除"</string>
     <string name="recentCalls_deleteAll" msgid="6352364392762163704">"清除通话记录"</string>
     <string name="recentCalls_trashVoicemail" msgid="7604696960787435655">"删除语音邮件"</string>
     <string name="recentCalls_shareVoicemail" msgid="1416112847592942840">"分享语音邮件"</string>
-    <string name="recentCalls_empty" msgid="247053222448663107">"通话记录为空。"</string>
+    <string name="recentCalls_empty" msgid="247053222448663107">"没有通话记录。"</string>
     <string name="clearCallLogConfirmation_title" msgid="6427524640461816332">"要清除通话记录吗?"</string>
     <string name="clearCallLogConfirmation" msgid="5043563133171583152">"系统将删除您的所有通话记录。"</string>
     <string name="clearCallLogProgress_title" msgid="8365943000154295771">"正在清除通话记录..."</string>
@@ -89,7 +89,7 @@
     <string name="menu_show_missed_only" msgid="154473166059743996">"仅显示未接来电"</string>
     <string name="menu_show_voicemails_only" msgid="1898421289561435703">"只显示语音邮件"</string>
     <string name="menu_show_all_calls" msgid="7560347482073345885">"显示所有通话"</string>
-    <string name="add_2sec_pause" msgid="9214012315201040129">"暂停时间延长 2 秒"</string>
+    <string name="add_2sec_pause" msgid="9214012315201040129">"暂停时间延长2秒"</string>
     <string name="add_wait" msgid="3360818652790319634">"延长等待时间"</string>
     <string name="call_settings" msgid="7666474782093693667">"设置"</string>
     <string name="menu_newContact" msgid="1209922412763274638">"新建联系人"</string>
diff --git a/src/com/android/dialer/list/PhoneFavoriteDragAndDropListeners.java b/src/com/android/dialer/list/PhoneFavoriteDragAndDropListeners.java
deleted file mode 100644
index f0e97ac..0000000
--- a/src/com/android/dialer/list/PhoneFavoriteDragAndDropListeners.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * 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.graphics.Rect;
-import android.util.Log;
-import android.view.DragEvent;
-import android.view.View;
-import android.view.View.OnDragListener;
-
-import com.android.dialer.list.PhoneFavoritesTileAdapter.ContactTileRow;
-
-/**
- * Implements the OnLongClickListener and OnDragListener for phone's favorite tiles and rows.
- */
-public class PhoneFavoriteDragAndDropListeners {
-
-    private static final String TAG = PhoneFavoriteDragAndDropListeners.class.getSimpleName();
-    private static final boolean DEBUG = false;
-
-    /**
-     * Implements the OnDragListener to handle drag events.
-     */
-    public static class PhoneFavoriteDragListener implements OnDragListener {
-        /** Location of the drag event. */
-        private float mX = 0;
-        private float mY = 0;
-        private final ContactTileRow mContactTileRow;
-        private final PhoneFavoritesTileAdapter mTileAdapter;
-
-        public PhoneFavoriteDragListener(ContactTileRow contactTileRow,
-                PhoneFavoritesTileAdapter tileAdapter) {
-            super();
-            mContactTileRow = contactTileRow;
-            mTileAdapter = tileAdapter;
-        }
-
-        /**
-         * @return The item index in {@link #mTileAdapter} for the given {@link DragEvent}.
-         *     Returns -1 if {@link #mTileAdapter} is not in dragging or index can not be found.
-         */
-        private int getDragItemIndex(DragEvent event) {
-            int itemIndex = -1;
-            if (mTileAdapter != null && mContactTileRow != null
-                    && !mTileAdapter.getInDragging()) {
-                mX = event.getX();
-                mY = event.getY();
-                if (DEBUG) {
-                    Log.v(TAG, String.valueOf(mX) + "; " + String.valueOf(mY));
-                }
-
-                final int[] rowLocation = new int[2];
-                mContactTileRow.getLocationOnScreen(rowLocation);
-
-                final Rect locationRect = new Rect(rowLocation[0], rowLocation[1],
-                        rowLocation[0] + mContactTileRow.getWidth(),
-                        rowLocation[1] + mContactTileRow.getHeight());
-
-                if (locationRect.contains((int) mX, (int) mY)) {
-                    // Finds out which item is being dragged.
-                    // Computes relative coordinates as we get absolute coordinates.
-                    itemIndex = mContactTileRow.getItemIndex(
-                            mX - rowLocation[0], mY - rowLocation[1]);
-                    if (DEBUG) {
-                        Log.v(TAG, "Start dragging " + String.valueOf(itemIndex));
-                    }
-                }
-            }
-            return itemIndex;
-        }
-
-        @Override
-        public boolean onDrag(View v, DragEvent event) {
-            if (DEBUG) {
-                Log.v(TAG, event.toString());
-            }
-            // Handles drag events.
-            switch (event.getAction()) {
-                case DragEvent.ACTION_DRAG_STARTED:
-                    final int itemIndex = getDragItemIndex(event);
-                    if (itemIndex != -1) {
-                        // Indicates a drag has started.
-                        mTileAdapter.setInDragging(true);
-
-                        // Temporarily pops out the Contact entry.
-                        mTileAdapter.popContactEntry(itemIndex);
-                    }
-                    break;
-                case DragEvent.ACTION_DRAG_ENTERED:
-                    break;
-                case DragEvent.ACTION_DRAG_EXITED:
-                    break;
-                case DragEvent.ACTION_DROP:
-                    // Indicates a drag has finished.
-                    if (mTileAdapter != null && mContactTileRow != null) {
-                        mTileAdapter.setInDragging(false);
-                        // The drop to position has been reported to the adapter
-                        // via {@link DragEvent#ACTION_DRAG_LOCATION} events in ListView.
-                        mTileAdapter.handleDrop();
-                    }
-                    break;
-                case DragEvent.ACTION_DRAG_ENDED:
-                    if (mTileAdapter != null && mTileAdapter.getInDragging()) {
-                        // If the drag and drop ends when the drop happens outside of any rows,
-                        // we will end the drag here and put the item back to where it was dragged
-                        // from before.
-                        mTileAdapter.setInDragging(false);
-                        mTileAdapter.handleDrop();
-                    }
-                    break;
-                case DragEvent.ACTION_DRAG_LOCATION:
-                    break;
-                default:
-                    break;
-            }
-            return true;
-        }
-    }
-}
diff --git a/src/com/android/dialer/list/PhoneFavoriteFragment.java b/src/com/android/dialer/list/PhoneFavoriteFragment.java
index 270ed63..d8179e7 100644
--- a/src/com/android/dialer/list/PhoneFavoriteFragment.java
+++ b/src/com/android/dialer/list/PhoneFavoriteFragment.java
@@ -211,6 +211,7 @@
         mListView.setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_RIGHT);
         mListView.setScrollBarStyle(ListView.SCROLLBARS_OUTSIDE_OVERLAY);
         mListView.setOnItemSwipeListener(mContactTileAdapter);
+        mListView.setOnDragDropListener(mContactTileAdapter);
 
         mEmptyView = inflater.inflate(R.layout.phone_no_favorites, mListView, false);
 
diff --git a/src/com/android/dialer/list/PhoneFavoriteListView.java b/src/com/android/dialer/list/PhoneFavoriteListView.java
index 00f645a..4ce5df1 100644
--- a/src/com/android/dialer/list/PhoneFavoriteListView.java
+++ b/src/com/android/dialer/list/PhoneFavoriteListView.java
@@ -19,6 +19,9 @@
 
 import android.content.Context;
 import android.content.res.Configuration;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
 import android.os.Handler;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -47,6 +50,7 @@
     private boolean mEnableSwipe = true;
 
     private OnItemGestureListener mOnItemGestureListener;
+    private OnDragDropListener mOnDragDropListener;
 
     private float mDensityScale;
     private float mTouchSlop;
@@ -60,7 +64,22 @@
     private final int DRAG_SCROLL_PX_UNIT = 10;
 
     private boolean mIsDragScrollerRunning = false;
+    private int mTouchDownForDragStartX;
     private int mTouchDownForDragStartY;
+    private Bitmap mDragShadowBitmap;
+
+    // X and Y offsets inside the item from where the user grabbed to the
+    // child's left coordinate. This is used to aid in the drawing of the drag shadow.
+    private int mTouchOffsetToChildLeft;
+    private int mTouchOffsetToChildTop;
+
+    private int mDragShadowLeft;
+    private int mDragShadowTop;
+    private int mDragShadowWidth;
+    private int mDragShadowHeight;
+
+    private final int DRAG_SHADOW_ALPHA = 180;
+    private final Paint mPaint = new Paint();
 
     /**
      * {@link #mTopScrollBound} and {@link mBottomScrollBound} will be
@@ -95,6 +114,7 @@
         mSwipeHelper = new SwipeHelper(context, SwipeHelper.X, this,
                 mDensityScale, mTouchSlop);
         setItemsCanFocus(true);
+        mPaint.setAlpha(DRAG_SHADOW_ALPHA);
     }
 
     @Override
@@ -121,9 +141,14 @@
         mOnItemGestureListener = listener;
     }
 
+    public void setOnDragDropListener(OnDragDropListener listener) {
+        mOnDragDropListener = listener;
+    }
+
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+            mTouchDownForDragStartX = (int) ev.getX();
             mTouchDownForDragStartY = (int) ev.getY();
         }
         if (isSwipeEnabled()) {
@@ -147,24 +172,13 @@
 
     @Override
     public View getChildAtPosition(MotionEvent ev) {
-        // find the view under the pointer, accounting for GONE views
-        final int count = getChildCount();
-        final int touchY = (int) ev.getY();
-        View slidingChild;
-        for (int childIdx = 0; childIdx < count; childIdx++) {
-            slidingChild = getChildAt(childIdx);
-            if (slidingChild.getVisibility() == GONE) {
-                continue;
-            }
-            if (touchY >= slidingChild.getTop() && touchY <= slidingChild.getBottom()) {
-                if (SwipeHelper.isSwipeable(slidingChild)) {
-                    // If this view is swipable in this listview, then return it. Otherwise
-                    // return a null view, which will simply be ignored by the swipe helper.
-                    return slidingChild;
-                } else {
-                    return null;
-                }
-            }
+        final View view = getViewAtPosition((int) ev.getX(), (int) ev.getY());
+        if (view != null &&
+                SwipeHelper.isSwipeable(view) &&
+                view.getVisibility() != GONE) {
+            // If this view is swipable in this listview, then return it. Otherwise
+            // return a null view, which will simply be ignored by the swipe helper.
+            return view;
         }
         return null;
     }
@@ -205,10 +219,18 @@
 
     @Override
     public boolean dispatchDragEvent(DragEvent event) {
-        switch (event.getAction()) {
+        final int action = event.getAction();
+        final int eX = (int) event.getX();
+        final int eY = (int) event.getY();
+        switch (action) {
+            case DragEvent.ACTION_DRAG_STARTED:
+                if (!handleDragStarted(mTouchDownForDragStartX, mTouchDownForDragStartY)) {
+                    return false;
+                };
+                break;
             case DragEvent.ACTION_DRAG_LOCATION:
-                mLastDragY = (int) event.getY();
-                handleDrag((int) event.getX(), mLastDragY);
+                mLastDragY = eY;
+                handleDragHovered(eX, eY);
                 // Kick off {@link #mScrollHandler} if it's not started yet.
                 if (!mIsDragScrollerRunning &&
                         // And if the distance traveled while dragging exceeds the touch slop
@@ -229,13 +251,39 @@
                 ensureScrollHandler();
                 mScrollHandler.removeCallbacks(mDragScroller);
                 mIsDragScrollerRunning = false;
+                if (action != DragEvent.ACTION_DRAG_EXITED) {
+                    handleDragFinished(eX, eY);
+                }
                 break;
-            case DragEvent.ACTION_DRAG_STARTED:
-                // Not a receiver
             default:
                 break;
         }
-        return super.dispatchDragEvent(event);
+        // This ListView will consumer the drag events on behalf of its children.
+        return true;
+    }
+
+    @Override
+    public void dispatchDraw(Canvas canvas) {
+        super.dispatchDraw(canvas);
+        // Draw the drag shadow at its last known location if the drag shadow exists.
+        if (mDragShadowBitmap != null) {
+            canvas.drawBitmap(mDragShadowBitmap, mDragShadowLeft, mDragShadowTop, mPaint);
+        }
+    }
+
+    /**
+     * Find the view under the pointer.
+     */
+    private View getViewAtPosition(int x, int y) {
+        final int count = getChildCount();
+        View child;
+        for (int childIdx = 0; childIdx < count; childIdx++) {
+            child = getChildAt(childIdx);
+            if (y >= child.getTop() && y <= child.getBottom()) {
+                return child;
+            }
+        }
+        return null;
     }
 
     private void ensureScrollHandler() {
@@ -244,29 +292,112 @@
         }
     }
 
-    private void handleDrag(int x, int y) {
-        // find the view under the pointer, accounting for GONE views
-        final int count = getChildCount();
-        View slidingChild;
-        for (int childIdx = 0; childIdx < count; childIdx++) {
-            slidingChild = getChildAt(childIdx);
-            if (slidingChild.getVisibility() == GONE) {
-                continue;
+    /**
+     * @return True if the drag is started.
+     */
+    private boolean handleDragStarted(int x, int y) {
+        final View child = getViewAtPosition(x, y);
+        if (!(child instanceof ContactTileRow)) {
+            // Bail early.
+            return false;
+        }
+
+        final ContactTileRow tile = (ContactTileRow) child;
+        final int itemIndex = tile.getItemIndex(x, y);
+        if (itemIndex != -1 && mOnDragDropListener != null) {
+            final PhoneFavoriteTileView tileView =
+                    (PhoneFavoriteTileView) tile.getViewAtPosition(x, y);
+            mDragShadowBitmap = createDraggedChildBitmap(tileView);
+            if (mDragShadowBitmap == null) {
+                return false;
             }
-            if (y >= slidingChild.getTop() &&
-                    y <= slidingChild.getBottom() &&
-                    slidingChild instanceof ContactTileRow) {
-                final ContactTileRow tile = (ContactTileRow) slidingChild;
-                reportDragEnteredItemIndex(tile.getItemIndex(x, y));
+
+            if (tileView instanceof PhoneFavoriteRegularRowView) {
+                mDragShadowLeft = tile.getLeft();
+                mDragShadowTop = tile.getTop();
+            } else {
+                // Square tile is relative to the contact tile,
+                // and contact tile is relative to this list view.
+                mDragShadowLeft = tileView.getLeft() + tileView.getParentRow().getLeft();
+                mDragShadowTop = tileView.getTop() + tileView.getParentRow().getTop();
             }
+            mDragShadowWidth = tileView.getWidth();
+            mDragShadowHeight = tileView.getHeight();
+
+            // x and y passed in are the coordinates of where the user has touched down, calculate
+            // the offset to the top left coordinate of the dragged child.  This will be used for
+            // drawing the drag shadow.
+            mTouchOffsetToChildLeft = x - mDragShadowLeft;
+            mTouchOffsetToChildTop = y - mDragShadowTop;
+
+            // invalidate to trigger a redraw of the drag shadow.
+            invalidate();
+
+            mOnDragDropListener.onDragStarted(itemIndex);
+        }
+
+        return true;
+    }
+
+    private void handleDragHovered(int x, int y) {
+        final View child = getViewAtPosition(x, y);
+        if (!(child instanceof ContactTileRow)) {
+            // Bail early.
+            return;
+        }
+
+        // Update the drag shadow location.
+        mDragShadowLeft = x - mTouchOffsetToChildLeft;
+        mDragShadowTop = y - mTouchOffsetToChildTop;
+
+        // invalidate to trigger a redraw of the drag shadow.
+        invalidate();
+
+        final ContactTileRow tile = (ContactTileRow) child;
+        final int itemIndex = tile.getItemIndex(x, y);
+        if (itemIndex != -1 && mOnDragDropListener != null) {
+            mOnDragDropListener.onDragHovered(itemIndex);
         }
     }
 
-    private void reportDragEnteredItemIndex(int itemIndex) {
-        final PhoneFavoriteMergedAdapter adapter =
-                (PhoneFavoriteMergedAdapter) getAdapter();
-        if (adapter != null) {
-            adapter.reportDragEnteredItemIndex(itemIndex);
+    private void handleDragFinished(int x, int y) {
+        // Update the drag shadow location.
+        mDragShadowLeft = x - mTouchOffsetToChildLeft;
+        mDragShadowTop = y - mTouchOffsetToChildTop;
+
+        if (mDragShadowBitmap != null) {
+            mDragShadowBitmap.recycle();
+            mDragShadowBitmap = null;
         }
+
+        if (mOnDragDropListener != null) {
+            mOnDragDropListener.onDragFinished();
+        }
+    }
+
+    private Bitmap createDraggedChildBitmap(View view) {
+        view.setDrawingCacheEnabled(true);
+        final Bitmap cache = view.getDrawingCache();
+
+        Bitmap bitmap = null;
+        if (cache != null) {
+            try {
+                bitmap = cache.copy(Bitmap.Config.ARGB_8888, false);
+            } catch (final OutOfMemoryError e) {
+                Log.w(LOG_TAG, "Failed to copy bitmap from Drawing cache", e);
+                bitmap = null;
+            }
+        }
+
+        view.destroyDrawingCache();
+        view.setDrawingCacheEnabled(false);
+
+        return bitmap;
+    }
+
+    public interface OnDragDropListener {
+        public void onDragStarted(int itemIndex);
+        public void onDragHovered(int itemIndex);
+        public void onDragFinished();
     }
 }
diff --git a/src/com/android/dialer/list/PhoneFavoriteMergedAdapter.java b/src/com/android/dialer/list/PhoneFavoriteMergedAdapter.java
index 084a34e..c7554e2 100644
--- a/src/com/android/dialer/list/PhoneFavoriteMergedAdapter.java
+++ b/src/com/android/dialer/list/PhoneFavoriteMergedAdapter.java
@@ -346,10 +346,4 @@
             mOnItemSwipeListener = listener;
         }
     }
-
-    public void reportDragEnteredItemIndex(int itemIndex) {
-        if (mContactTileAdapter != null) {
-            mContactTileAdapter.reportDragEnteredItemIndex(itemIndex);
-        }
-    }
 }
diff --git a/src/com/android/dialer/list/PhoneFavoriteRegularRowView.java b/src/com/android/dialer/list/PhoneFavoriteRegularRowView.java
index 374f733..efe7bdd 100644
--- a/src/com/android/dialer/list/PhoneFavoriteRegularRowView.java
+++ b/src/com/android/dialer/list/PhoneFavoriteRegularRowView.java
@@ -23,7 +23,6 @@
 
 import com.android.contacts.common.util.ViewUtil;
 import com.android.dialer.R;
-import com.android.dialer.list.PhoneFavoriteDragAndDropListeners.PhoneFavoriteDragListener;
 
 import com.android.dialer.list.PhoneFavoritesTileAdapter.ContactTileRow;
 
diff --git a/src/com/android/dialer/list/PhoneFavoriteTileView.java b/src/com/android/dialer/list/PhoneFavoriteTileView.java
index 76a0e35..5a3f4e5 100644
--- a/src/com/android/dialer/list/PhoneFavoriteTileView.java
+++ b/src/com/android/dialer/list/PhoneFavoriteTileView.java
@@ -20,7 +20,6 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
-import android.content.ClipData;
 import android.content.Context;
 import android.text.TextUtils;
 import android.util.AttributeSet;
@@ -32,7 +31,6 @@
 import com.android.contacts.common.MoreContactUtils;
 import com.android.contacts.common.list.ContactEntry;
 import com.android.contacts.common.list.ContactTileView;
-import com.android.dialer.list.PhoneFavoriteDragAndDropListeners.PhoneFavoriteDragListener;
 import com.android.dialer.list.PhoneFavoritesTileAdapter.ContactTileRow;
 import com.android.dialer.list.PhoneFavoritesTileAdapter.ViewTypes;
 
@@ -94,20 +92,17 @@
             public boolean onLongClick(View v) {
                 setPressed(false);
                 final PhoneFavoriteTileView view = (PhoneFavoriteTileView) v;
-                final ClipData data = ClipData.newPlainText("", "");
+                // NOTE The drag shadow is handled in the ListView.
                 if (view instanceof PhoneFavoriteRegularRowView) {
-                    // If the view is regular row, start drag the row view.
-                    final View.DragShadowBuilder shadowBuilder =
-                            new View.DragShadowBuilder(view.getParentRow());
                     final ContactTileRow parent = (ContactTileRow) view.getParentRow();
+                    // If the view is regular row, start drag the row view.
                     // Drag is not available for the item exceeds the PIN_LIMIT.
                     if (parent.getRegularRowItemIndex() < PhoneFavoritesTileAdapter.PIN_LIMIT) {
-                        view.getParentRow().startDrag(data, shadowBuilder, null, 0);
+                        parent.startDrag(null, new View.DragShadowBuilder(), null, 0);
                     }
                 } else {
                     // If the view is a tile view, start drag the tile.
-                    final View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);
-                    view.startDrag(data, shadowBuilder, null, 0);
+                    view.startDrag(null, new View.DragShadowBuilder(), null, 0);
                 }
                 return true;
             }
@@ -205,8 +200,6 @@
     @Override
     protected void onAttachedToWindow() {
         mParentRow = (ContactTileRow) getParent();
-        mParentRow.setOnDragListener(new PhoneFavoriteDragListener(mParentRow,
-                mParentRow.getTileAdapter()));
     }
 
     @Override
diff --git a/src/com/android/dialer/list/PhoneFavoritesTileAdapter.java b/src/com/android/dialer/list/PhoneFavoritesTileAdapter.java
index 4eaeaf5..779b15d 100644
--- a/src/com/android/dialer/list/PhoneFavoritesTileAdapter.java
+++ b/src/com/android/dialer/list/PhoneFavoritesTileAdapter.java
@@ -62,7 +62,7 @@
  *
  */
 public class PhoneFavoritesTileAdapter extends BaseAdapter implements
-        SwipeHelper.OnItemGestureListener {
+        SwipeHelper.OnItemGestureListener, PhoneFavoriteListView.OnDragDropListener {
     private static final String TAG = PhoneFavoritesTileAdapter.class.getSimpleName();
     private static final boolean DEBUG = false;
 
@@ -634,6 +634,7 @@
                         PinnedPositions.STAR_WHEN_PINNING, "true").build();
                 // update the database here with the new pinned positions
                 mContext.getContentResolver().update(pinUri, cv, null, null);
+                notifyDataSetChanged();
             }
             mDraggedEntry = null;
         }
@@ -970,27 +971,32 @@
             return mPosition;
         }
 
-        @Override
-        public View getChildAtPosition(MotionEvent ev) {
+        /**
+         * Find the view under the pointer.
+         */
+        public View getViewAtPosition(int x, int y) {
             // find the view under the pointer, accounting for GONE views
             final int count = getChildCount();
-            final int touchX = (int) ev.getX();
-            View slidingChild;
+            View view;
             for (int childIdx = 0; childIdx < count; childIdx++) {
-                slidingChild = getChildAt(childIdx);
-                if (slidingChild.getVisibility() == GONE) {
-                    continue;
+                view = getChildAt(childIdx);
+                if (x >= view.getLeft() && x <= view.getRight()) {
+                    return view;
                 }
-                if (touchX >= slidingChild.getLeft() && touchX <= slidingChild.getRight()) {
-                    if (SwipeHelper.isSwipeable(slidingChild)) {
-                        // If this view is swipable, then return it. If not, because the removal
-                        // dialog is currently showing, then return a null view, which will simply
-                        // be ignored by the swipe helper.
-                        return slidingChild;
-                    } else {
-                        return null;
-                    }
-                }
+            }
+            return null;
+        }
+
+        @Override
+        public View getChildAtPosition(MotionEvent ev) {
+            final View view = getViewAtPosition((int) ev.getX(), (int) ev.getY());
+            if (view != null &&
+                    SwipeHelper.isSwipeable(view) &&
+                    view.getVisibility() != GONE) {
+                // If this view is swipable, then return it. If not, because the removal
+                // dialog is currently showing, then return a null view, which will simply
+                // be ignored by the swipe helper.
+                return view;
             }
             return null;
         }
@@ -1192,11 +1198,14 @@
         return !mAwaitingRemove;
     }
 
-    public void setEmptyView(View emptyView) {
-        mEmptyView = emptyView;
+    @Override
+    public void onDragStarted(int itemIndex) {
+        setInDragging(true);
+        popContactEntry(itemIndex);
     }
 
-    public void reportDragEnteredItemIndex(int itemIndex) {
+    @Override
+    public void onDragHovered(int itemIndex) {
         if (mInDragging &&
                 mDragEnteredEntryIndex != itemIndex &&
                 isIndexInBound(itemIndex) &&
@@ -1204,4 +1213,14 @@
             markDropArea(itemIndex);
         }
     }
+
+    @Override
+    public void onDragFinished() {
+        setInDragging(false);
+        handleDrop();
+    }
+
+    public void setEmptyView(View emptyView) {
+        mEmptyView = emptyView;
+    }
 }