Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 949d0c8c authored by Gilles Debunne's avatar Gilles Debunne Committed by Android (Google) Code Review
Browse files

Merge "Text handles positions' are correctly updated." into honeycomb-mr1

parents 055a8585 cfc22c53
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1039,7 +1039,7 @@ public class PopupWindow {
     *
     * @return true if the popup is translated upwards to fit on screen
     */
    boolean findDropDownPosition(View anchor, WindowManager.LayoutParams p,
    private boolean findDropDownPosition(View anchor, WindowManager.LayoutParams p,
            int xoff, int yoff) {

        anchor.getLocationInWindow(mDrawingLocation);
+98 −128
Original line number Diff line number Diff line
@@ -4498,8 +4498,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        */

        canvas.restore();

        updateCursorControllerPositions();
    }

    private void updateCursorsPositions() {
@@ -4557,15 +4555,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
     * @hide
     */
    protected void updateCursorControllerPositions() {
        // No need to create the controllers if they were not already
        if (mInsertionPointCursorController != null &&
                mInsertionPointCursorController.isShowing()) {
            mInsertionPointCursorController.updatePosition();
        }
        if (mSelectionModifierCursorController != null &&
                mSelectionModifierCursorController.isShowing()) {
            mSelectionModifierCursorController.updatePosition();
        }
        // TODO remove
    }

    @Override
@@ -7356,14 +7346,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
            }

            if (isTextEditable() || mTextIsSelectable) {
                if (mScrollX != oldScrollX || mScrollY != oldScrollY) {
                if (mScrollX != oldScrollX || mScrollY != oldScrollY) { // TODO remove
                    // Hide insertion anchor while scrolling. Leave selection.
                    hideInsertionPointCursorController();
                    // No need to create the controller, since there is nothing to update.
                    if (mSelectionModifierCursorController != null &&
                            mSelectionModifierCursorController.isShowing()) {
                        mSelectionModifierCursorController.updatePosition();
                    }
                    hideInsertionPointCursorController(); // TODO any motion should hide it
                }

                if (touchIsFinished) {
@@ -7373,7 +7358,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                        handled |= imm != null && imm.showSoftInput(this, 0);
                    }


                    boolean selectAllGotFocus = mSelectAllOnFocus && didTouchFocusSelect();
                    if (!selectAllGotFocus && hasSelection()) {
                        startSelectionActionMode();
@@ -8653,26 +8637,31 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        }
    }

    private class HandleView extends View implements ViewTreeObserver.OnScrollChangedListener {
    private class HandleView extends View implements ViewTreeObserver.OnPreDrawListener {
        private Drawable mDrawable;
        private final ScrollingPopupWindow mContainer;
        private int mPositionX;
        private int mPositionY;
        private final PopupWindow mContainer;
        // Position with respect to the parent TextView
        private int mPositionX, mPositionY;
        private final CursorController mController;
        private boolean mIsDragging;
        private float mTouchToWindowOffsetX;
        private float mTouchToWindowOffsetY;
        // Offset from touch position to mPosition
        private float mTouchToWindowOffsetX, mTouchToWindowOffsetY;
        private float mHotspotX;
        // Offsets the hotspot point up, so that cursor is not hidden by the finger when moving up
        private float mTouchOffsetY;
        // Where the touch position should be on the handle to ensure a maximum cursor visibility
        private float mIdealVerticalOffset;
        private int mLastParentX;
        private int mLastParentY;
        // Parent's (TextView) position in window
        private int mLastParentX, mLastParentY;
        private float mDownPositionX, mDownPositionY;
        // PopupWindow container absolute position with respect to the enclosing window
        private int mContainerPositionX, mContainerPositionY;
        private long mTouchTimer;
        // Visible or not (scrolled off screen), whether or not this handle should be visible
        private boolean mIsActive = false;
        // The insertion handle can have an associated PastePopupMenu
        private boolean mIsInsertionHandle = false;
        // Used to detect taps on the insertion handle, which will affect the PastePopupMenu
        private long mTouchTimer;
        private PastePopupMenu mPastePopupWindow;

        // Touch-up filter: number of previous positions remembered
@@ -8684,12 +8673,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        private int mPreviousOffsetIndex = 0;
        private int mNumberPreviousOffsets = 0;

        public void startTouchUpFilter(int offset) {
        private void startTouchUpFilter(int offset) {
            mNumberPreviousOffsets = 0;
            addPositionToTouchUpFilter(offset);
        }

        public void addPositionToTouchUpFilter(int offset) {
        private void addPositionToTouchUpFilter(int offset) {
            if (mNumberPreviousOffsets > 0 &&
                    mPreviousOffsets[mPreviousOffsetIndex] == offset) {
                // Make sure only actual changes of position are recorded.
@@ -8702,7 +8691,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
            mNumberPreviousOffsets++;
        }

        public void filterOnTouchUp() {
        private void filterOnTouchUp() {
            final long now = SystemClock.uptimeMillis();
            int i = 0;
            int index = mPreviousOffsetIndex;
@@ -8725,16 +8714,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        public HandleView(CursorController controller, int pos) {
            super(TextView.this.mContext);
            mController = controller;
            mContainer = new ScrollingPopupWindow(TextView.this.mContext, null,
            mContainer = new PopupWindow(TextView.this.mContext, null,
                    com.android.internal.R.attr.textSelectHandleWindowStyle);
            mContainer.setSplitTouchEnabled(true);
            mContainer.setClippingEnabled(false);
            mContainer.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL);
            mContainer.setContentView(this);

            setOrientation(pos);
            setPosition(pos);
        }

        public void setOrientation(int pos) {
        private void setPosition(int pos) {
            int handleWidth;
            switch (pos) {
                case LEFT: {
@@ -8774,38 +8764,48 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
            }

            final int handleHeight = mDrawable.getIntrinsicHeight();

            mTouchOffsetY = -0.3f * handleHeight;
            mIdealVerticalOffset = 0.7f * handleHeight;

            invalidate();
        }

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            setMeasuredDimension(mDrawable.getIntrinsicWidth(),
                    mDrawable.getIntrinsicHeight());
            setMeasuredDimension(mDrawable.getIntrinsicWidth(), mDrawable.getIntrinsicHeight());
        }

        public void show() {
            if (!isPositionVisible()) {
                hide();
                return;
            }
            mContainer.setContentView(this);
            mContainerPositionX = mPositionX;
            mContainerPositionY = mPositionY - TextView.this.getHeight();
            mContainer.showAsDropDown(TextView.this, mContainerPositionX, mContainerPositionY);
            updateContainerPosition();
            if (isShowing()) {
                mContainer.update(mContainerPositionX, mContainerPositionY,
                        mRight - mLeft, mBottom - mTop);

            // Hide paste view when handle is moved on screen.
                hidePastePopupWindow();
            } else {
                mContainer.showAtLocation(TextView.this, 0,
                        mContainerPositionX, mContainerPositionY);

                mIsActive = true;

                ViewTreeObserver vto = TextView.this.getViewTreeObserver();
                vto.addOnPreDrawListener(this);
            }
        }

        public void hide() {
        private void dismiss() {
            mIsDragging = false;
            mContainer.dismiss();
            hidePastePopupWindow();
        }

        public void hide() {
            dismiss();

            mIsActive = false;

            ViewTreeObserver vto = TextView.this.getViewTreeObserver();
            vto.removeOnScrollChangedListener(this);
            vto.removeOnPreDrawListener(this);
        }

        public boolean isShowing() {
@@ -8856,44 +8856,59 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        private void moveTo(int x, int y) {
            mPositionX = x - TextView.this.mScrollX;
            mPositionY = y - TextView.this.mScrollY;
            if (isPositionVisible()) {
                int[] coords = null;
                if (mContainer.isShowing()) {
                    final int containerPositionX = mPositionX;
                    final int containerPositionY = mPositionY - TextView.this.getHeight();

            if (mIsDragging) {
                TextView.this.getLocationInWindow(mTempCoords);
                if (mTempCoords[0] != mLastParentX || mTempCoords[1] != mLastParentY) {
                    mTouchToWindowOffsetX += mTempCoords[0] - mLastParentX;
                    mTouchToWindowOffsetY += mTempCoords[1] - mLastParentY;
                    mLastParentX = mTempCoords[0];
                    mLastParentY = mTempCoords[1];
                }
                // Hide paste popup window as soon as the handle is dragged.
                hidePastePopupWindow();
            }
        }

        /**
         * Updates the global container's position.
         * @return whether or not the position has actually changed
         */
        private boolean updateContainerPosition() {
            // TODO Prevent this using different HandleView subclasses
            mController.updateOffset(this, mController.getCurrentOffset(this));
            TextView.this.getLocationInWindow(mTempCoords);
            final int containerPositionX = mTempCoords[0] + mPositionX;
            final int containerPositionY = mTempCoords[1] + mPositionY;

            if (containerPositionX != mContainerPositionX ||
                containerPositionY != mContainerPositionY) {
                mContainerPositionX = containerPositionX;
                mContainerPositionY = containerPositionY;
                return true;
            }
            return false;
        }

                        mContainer.update(TextView.this, mContainerPositionX, mContainerPositionY,
        public boolean onPreDraw() {
            if (updateContainerPosition()) {
                if (isPositionVisible()) {
                    mContainer.update(mContainerPositionX, mContainerPositionY,
                            mRight - mLeft, mBottom - mTop);

                        // Hide paste popup window as soon as a scroll occurs.
                        hidePastePopupWindow();
                    }
                } else {
                    if (mIsActive && !isShowing()) {
                        show();
                    }

                if (mIsDragging) {
                    if (coords == null) {
                        coords = mTempCoords;
                        TextView.this.getLocationInWindow(coords);
                } else {
                    if (isShowing()) {
                        dismiss();
                    }
                    if (coords[0] != mLastParentX || coords[1] != mLastParentY) {
                        mTouchToWindowOffsetX += coords[0] - mLastParentX;
                        mTouchToWindowOffsetY += coords[1] - mLastParentY;
                        mLastParentX = coords[0];
                        mLastParentY = coords[1];
                }
                    // Hide paste popup window as soon as the handle is dragged.

                // Hide paste popup as soon as the view is scrolled or moved
                hidePastePopupWindow();
            }
            } else {
                hide();
            }
            return true;
        }

        @Override
@@ -8979,7 +8994,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
            return mIsDragging;
        }

        void positionAtCursor(final int offset) {
        void positionAtCursor(int offset) {
            addPositionToTouchUpFilter(offset);
            final int width = mDrawable.getIntrinsicWidth();
            final int height = mDrawable.getIntrinsicHeight();
@@ -9013,50 +9028,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                mPastePopupWindow.hide();
            }
        }

        /**
         * A popup window, attached to a view, and that listens to scroll events in its anchors'
         * view hierarchy, so that it is automatically moved on such events.
         */
        private class ScrollingPopupWindow extends PopupWindow {

            private int[] mDrawingLocations = new int[2];

            public ScrollingPopupWindow(Context context, AttributeSet attrs, int defStyle) {
                super(context, attrs, defStyle);
            }

            @Override
            public boolean findDropDownPosition(View anchor, WindowManager.LayoutParams p,
                    int xoff, int yoff) {
                anchor.getLocationInWindow(mDrawingLocations);
                p.x = mDrawingLocations[0] + xoff;
                p.y = mDrawingLocations[1] + anchor.getHeight() + yoff;

                // Hide paste popup as soon as the view is scrolled.
                hidePastePopupWindow();

                if (!isPositionVisible()) {
                    dismiss();
                    onHandleBecomeInvisible();
                }

                return false;
            }
        }

        public void onScrollChanged() {
            if (isPositionVisible()) {
                show();
                ViewTreeObserver vto = TextView.this.getViewTreeObserver();
                vto.removeOnScrollChangedListener(this);
            }
        }

        public void onHandleBecomeInvisible() {
            ViewTreeObserver vto = TextView.this.getViewTreeObserver();
            vto.addOnScrollChangedListener(this);
        }
    }

    private class InsertionPointCursorController implements CursorController {
@@ -9074,7 +9045,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        }

        public void show(int delayBeforePaste) {
            updatePosition();
            getHandle().show();
            hideDelayed();
            removePastePopupCallback();
            final long durationSinceCutOrCopy = SystemClock.uptimeMillis() - sLastCutOrCopyTime;
@@ -9213,7 +9184,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
            if (mEndHandle == null) mEndHandle = new HandleView(this, HandleView.RIGHT);

            mIsShowing = true;
            updatePosition();

            mStartHandle.show();
            mEndHandle.show();