Fix bug 3061544 and some clipping errors.

Change-Id: I124d0bcae080c27e2978be7eecfbb131f101a35f
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 6522de0..6797ea8 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -93,6 +93,7 @@
 import android.view.View;
 import android.view.ViewDebug;
 import android.view.ViewGroup.LayoutParams;
+import android.view.ViewParent;
 import android.view.ViewRoot;
 import android.view.ViewTreeObserver;
 import android.view.accessibility.AccessibilityEvent;
@@ -192,7 +193,8 @@
     
     private static int PRIORITY = 100;
 
-    private final int[] mTempCoords = new int[2];
+    final int[] mTempCoords = new int[2];
+    Rect mTempRect;
 
     private ColorStateList mTextColor;
     private int mCurTextColor;
@@ -7646,6 +7648,8 @@
         private float mOffsetY;
         private float mHotspotX;
         private float mHotspotY;
+        private int mLastParentX;
+        private int mLastParentY;
 
         public HandleView(CursorController controller, Drawable handle) {
             super(TextView.this.mContext);
@@ -7655,8 +7659,11 @@
                     com.android.internal.R.attr.textSelectHandleWindowStyle);
             mContainer.setSplitTouchEnabled(true);
             mContainer.setClippingEnabled(false);
-            mHotspotX = mDrawable.getIntrinsicWidth() * 0.5f;
-            mHotspotY = -mDrawable.getIntrinsicHeight() * 0.2f;
+
+            final int handleWidth = mDrawable.getIntrinsicWidth();
+            final int handleHeight = mDrawable.getIntrinsicHeight();
+            mHotspotX = handleWidth * 0.5f;
+            mHotspotY = -handleHeight * 0.2f;
         }
 
         @Override
@@ -7666,7 +7673,7 @@
         }
 
         public void show() {
-            if (!isPositionInBounds()) {
+            if (!isPositionVisible()) {
                 hide();
                 return;
             }
@@ -7687,7 +7694,12 @@
             return mContainer.isShowing();
         }
 
-        private boolean isPositionInBounds() {
+        private boolean isPositionVisible() {
+            // Always show a dragging handle.
+            if (mIsDragging) {
+                return true;
+            }
+
             final int extendedPaddingTop = getExtendedPaddingTop();
             final int extendedPaddingBottom = getExtendedPaddingBottom();
             final int compoundPaddingLeft = getCompoundPaddingLeft();
@@ -7699,28 +7711,55 @@
             final int top = 0;
             final int bottom = hostView.getHeight();
 
-            final int clipLeft = left + compoundPaddingLeft;
-            final int clipTop = top + extendedPaddingTop;
-            final int clipRight = right - compoundPaddingRight;
-            final int clipBottom = bottom - extendedPaddingBottom;
+            if (mTempRect == null) {
+                mTempRect = new Rect();
+            }
+            final Rect clip = mTempRect;
+            clip.left = left + compoundPaddingLeft;
+            clip.top = top + extendedPaddingTop;
+            clip.right = right - compoundPaddingRight;
+            clip.bottom = bottom - extendedPaddingBottom;
 
-            return mPositionX + mHotspotX >= clipLeft && mPositionX + mHotspotX <= clipRight &&
-                    mPositionY + mHotspotY >= clipTop && mPositionY + mHotspotY <= clipBottom;
+            final ViewParent parent = hostView.getParent();
+            if (parent == null || !parent.getChildVisibleRect(hostView, clip, null)) {
+                return false;
+            }
+
+            final int[] coords = mTempCoords;
+            hostView.getLocationInWindow(coords);
+            final int posX = coords[0] + mPositionX + (int) mHotspotX;
+            final int posY = coords[1] + mPositionY;
+
+            return posX >= clip.left && posX <= clip.right &&
+                    posY >= clip.top && posY + mHotspotY <= clip.bottom;
         }
 
         private void moveTo(int x, int y) {
             mPositionX = x - TextView.this.mScrollX;
             mPositionY = y - TextView.this.mScrollY;
-            if (isPositionInBounds()) {
+            if (isPositionVisible()) {
+                int[] coords = null;
                 if (mContainer.isShowing()){
-                    final int[] coords = mTempCoords;
+                    coords = mTempCoords;
                     TextView.this.getLocationInWindow(coords);
-                    coords[0] += mPositionX;
-                    coords[1] += mPositionY;
-                    mContainer.update(coords[0], coords[1], mRight - mLeft, mBottom - mTop);
+                    mContainer.update(coords[0] + mPositionX, coords[1] + mPositionY,
+                            mRight - mLeft, mBottom - mTop);
                 } else {
                     show();
                 }
+
+                if (mIsDragging) {
+                    if (coords == null) {
+                        coords = mTempCoords;
+                        TextView.this.getLocationInWindow(coords);
+                    }
+                    if (coords[0] != mLastParentX || coords[1] != mLastParentY) {
+                        mOffsetX += coords[0] - mLastParentX;
+                        mOffsetY += coords[1] - mLastParentY;
+                        mLastParentX = coords[0];
+                        mLastParentY = coords[1];
+                    }
+                }
             } else {
                 hide();
             }
@@ -7747,6 +7786,10 @@
                 final float rawY = ev.getRawY();
                 mOffsetX = rawX - mPositionX;
                 mOffsetY = rawY - mPositionY;
+                final int[] coords = mTempCoords;
+                TextView.this.getLocationInWindow(coords);
+                mLastParentX = coords[0];
+                mLastParentY = coords[1];
                 mIsDragging = true;
                 break;
             }