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

Commit 7e587a0e authored by Shu Chen's avatar Shu Chen Committed by Android (Google) Code Review
Browse files

Merge "Implement the floating cursor via the fisheye magnifier."

parents 5f3debfc 4021c3df
Loading
Loading
Loading
Loading
+60 −22
Original line number Diff line number Diff line
@@ -154,6 +154,10 @@ public class Editor {
    // Specifies whether to use the magnifier when pressing the insertion or selection handles.
    private static final boolean FLAG_USE_MAGNIFIER = true;

    // Specifies how far to make the cursor start float when drag the cursor away from the
    // beginning or end of the line.
    private static final int CURSOR_START_FLOAT_DISTANCE_PX = 20;

    private static final int DELAY_BEFORE_HANDLE_FADES_OUT = 4000;
    private static final int RECENT_CUT_COPY_DURATION_MS = 15 * 1000; // 15 seconds in millis

@@ -289,6 +293,9 @@ public class Editor {
    private boolean mRenderCursorRegardlessTiming;
    private Blink mBlink;

    // Whether to let magnifier draw cursor on its surface. This is for floating cursor effect.
    // And it can only be true when |mNewMagnifierEnabled| is true.
    private boolean mDrawCursorOnMagnifier;
    boolean mCursorVisible = true;
    boolean mSelectAllOnFocus;
    boolean mTextIsSelectable;
@@ -890,7 +897,7 @@ public class Editor {
        }

        boolean enabled = windowSupportsHandles && mTextView.getLayout() != null;
        mInsertionControllerEnabled = enabled && isCursorVisible();
        mInsertionControllerEnabled = enabled && (mDrawCursorOnMagnifier || isCursorVisible());
        mSelectionControllerEnabled = enabled && mTextView.textCanBeSelected();

        if (!mInsertionControllerEnabled) {
@@ -5101,14 +5108,25 @@ public class Editor {
            final int[] textViewLocationOnScreen = new int[2];
            mTextView.getLocationOnScreen(textViewLocationOnScreen);
            final float touchXInView = event.getRawX() - textViewLocationOnScreen[0];
            float leftBound = mTextView.getTotalPaddingLeft() - mTextView.getScrollX();
            float rightBound = mTextView.getTotalPaddingLeft() - mTextView.getScrollX();
            if (sameLineSelection && ((trigger == MagnifierHandleTrigger.SELECTION_END) ^ rtl)) {
            float leftBound, rightBound;
            if (mNewMagnifierEnabled) {
                leftBound = 0;
                rightBound = mTextView.getWidth();
                if (touchXInView < leftBound || touchXInView > rightBound) {
                    // The touch is too far from the current line / selection, so hide the magnifier.
                    return false;
                }
            } else {
                leftBound = mTextView.getTotalPaddingLeft() - mTextView.getScrollX();
                rightBound = mTextView.getTotalPaddingLeft() - mTextView.getScrollX();
                if (sameLineSelection && ((trigger == MagnifierHandleTrigger.SELECTION_END)
                        ^ rtl)) {
                    leftBound += getHorizontal(mTextView.getLayout(), otherHandleOffset);
                } else {
                    leftBound += mTextView.getLayout().getLineLeft(lineNumber);
                }
            if (sameLineSelection && ((trigger == MagnifierHandleTrigger.SELECTION_START) ^ rtl)) {
                if (sameLineSelection && ((trigger == MagnifierHandleTrigger.SELECTION_START)
                        ^ rtl)) {
                    rightBound += getHorizontal(mTextView.getLayout(), otherHandleOffset);
                } else {
                    rightBound += mTextView.getLayout().getLineRight(lineNumber);
@@ -5122,6 +5140,7 @@ public class Editor {
                    // The touch is too far from the current line / selection, so hide the magnifier.
                    return false;
                }
            }

            final float scaledTouchXInView;
            if (mTextViewScaleX == 1f) {
@@ -5178,7 +5197,8 @@ public class Editor {
            final Rect magnifierRect = new Rect(magnifierTopLeft.x, magnifierTopLeft.y,
                    magnifierTopLeft.x + mMagnifierAnimator.mMagnifier.getWidth(),
                    magnifierTopLeft.y + mMagnifierAnimator.mMagnifier.getHeight());
            setVisible(!handleOverlapsMagnifier(HandleView.this, magnifierRect));
            setVisible(!handleOverlapsMagnifier(HandleView.this, magnifierRect)
                    && !mDrawCursorOnMagnifier);
            final HandleView otherHandle = getOtherSelectionHandle();
            if (otherHandle != null) {
                otherHandle.setVisible(!handleOverlapsMagnifier(otherHandle, magnifierRect));
@@ -5208,7 +5228,20 @@ public class Editor {
                    lineLeft += mTextView.getTotalPaddingLeft() - mTextView.getScrollX();
                    int lineRight = (int) layout.getLineRight(line);
                    lineRight += mTextView.getTotalPaddingLeft() - mTextView.getScrollX();
                    mMagnifierAnimator.mMagnifier.setSourceHorizontalBounds(lineLeft, lineRight);
                    mDrawCursorOnMagnifier =
                            showPosInView.x < lineLeft - CURSOR_START_FLOAT_DISTANCE_PX
                            || showPosInView.x > lineRight + CURSOR_START_FLOAT_DISTANCE_PX;
                    mMagnifierAnimator.mMagnifier.setDrawCursor(
                            mDrawCursorOnMagnifier, mDrawableForCursor);
                    boolean cursorVisible = mCursorVisible;
                    // Updates cursor visibility, so that the real cursor and the float cursor on
                    // magnifier surface won't appear at the same time.
                    mCursorVisible = !mDrawCursorOnMagnifier;
                    if (mCursorVisible && !cursorVisible) {
                        // When the real cursor is a drawable, hiding/showing it would change its
                        // bounds. So, call updateCursorPosition() to correct its position.
                        updateCursorPosition();
                    }
                    final int lineHeight =
                            layout.getLineBottomWithoutSpacing(line) - layout.getLineTop(line);
                    float zoom = mInitialZoom;
@@ -5230,6 +5263,11 @@ public class Editor {
            if (mMagnifierAnimator != null) {
                mMagnifierAnimator.dismiss();
                mRenderCursorRegardlessTiming = false;
                mDrawCursorOnMagnifier = false;
                if (!mCursorVisible) {
                    mCursorVisible = true;
                    mTextView.invalidate();
                }
                resumeBlink();
                setVisible(true);
                final HandleView otherHandle = getOtherSelectionHandle();
+32 −21
Original line number Diff line number Diff line
@@ -149,9 +149,6 @@ public final class Magnifier {
    private int mLeftCutWidth = 0;
    // The width of the cut region on the right edge of the pixel copy source rect.
    private int mRightCutWidth = 0;
    // The horizontal bounds of the content source in pixels, relative to the view.
    private int mLeftBound = Integer.MIN_VALUE;
    private int mRightBound = Integer.MAX_VALUE;
    // The width of the ramp region in pixels on the left & right sides of the fish-eye effect.
    private final int mRamp;

@@ -243,18 +240,6 @@ public final class Magnifier {
        sPixelCopyHandlerThread.start();
    }

    /**
     * Sets the horizontal bounds of the source when showing the magnifier.
     * This is used for new style magnifier. e.g. limit the source bounds by the text line bounds.
     *
     * @param left the left of the bounds, relative to the view.
     * @param right the right of the bounds, relative to the view.
     */
    void setSourceHorizontalBounds(int left, int right) {
        mLeftBound = left;
        mRightBound = right;
    }

    /**
     * Shows the magnifier on the screen. The method takes the coordinates of the center
     * of the content source going to be magnified and copied to the magnifier. The coordinates
@@ -280,6 +265,14 @@ public final class Magnifier {
                sourceCenterY + mDefaultVerticalSourceToMagnifierOffset);
    }

    private Drawable mCursorDrawable;
    private boolean mDrawCursorEnabled;

    void setDrawCursor(boolean enabled, Drawable cursorDrawable) {
        mDrawCursorEnabled = enabled;
        mCursorDrawable = cursorDrawable;
    }

    /**
     * Shows the magnifier on the screen at a position that is independent from its content
     * position. The first two arguments represent the coordinates of the center of the
@@ -309,8 +302,7 @@ public final class Magnifier {
            magnifierCenterX = mClampedCenterZoomCoords.x - mViewCoordinatesInSurface[0];
            magnifierCenterY = mClampedCenterZoomCoords.y - mViewCoordinatesInSurface[1];

            // mLeftBound & mRightBound (typically the text line left/right) is for magnified
            // content. However the PixelCopy requires the pre-magnified bounds.
            // PixelCopy requires the pre-magnified bounds.
            // The below logic calculates the leftBound & rightBound for the pre-magnified bounds.
            final float rampPre =
                    (mSourceWidth - (mSourceWidth - 2 * mRamp) / mZoom) / 2;
@@ -318,7 +310,7 @@ public final class Magnifier {
            // Calculates the pre-zoomed left edge.
            // The leftEdge moves from the left of view towards to sourceCenterX, considering the
            // fisheye-like zooming.
            final float x0 = sourceCenterX - mSourceWidth / 2;
            final float x0 = sourceCenterX - mSourceWidth / 2f;
            final float rampX0 = x0 + mRamp;
            float leftEdge = 0;
            if (leftEdge > rampX0) {
@@ -330,12 +322,12 @@ public final class Magnifier {
                // increase per ramp zoom (ramp / rampPre).
                leftEdge = x0 + rampPre - (rampX0 - leftEdge) * rampPre / mRamp;
            }
            int leftBound = Math.min(Math.max((int) leftEdge, mLeftBound), mRightBound);
            int leftBound = Math.min((int) leftEdge, mView.getWidth());

            // Calculates the pre-zoomed right edge.
            // The rightEdge moves from the right of view towards to sourceCenterX, considering the
            // fisheye-like zooming.
            final float x1 = sourceCenterX + mSourceWidth / 2;
            final float x1 = sourceCenterX + mSourceWidth / 2f;
            final float rampX1 = x1 - mRamp;
            float rightEdge = mView.getWidth();
            if (rightEdge < rampX1) {
@@ -347,7 +339,7 @@ public final class Magnifier {
                // increase per ramp zoom (ramp / rampPre).
                rightEdge = x1 - rampPre + (rightEdge - rampX1) * rampPre / mRamp;
            }
            int rightBound = Math.max(leftBound, Math.min((int) rightEdge, mRightBound));
            int rightBound = Math.max(leftBound, (int) rightEdge);

            // Gets the startX for new style, which should be bounded by the horizontal bounds.
            // Also calculates the left/right cut width for pixel copy.
@@ -772,6 +764,23 @@ public final class Magnifier {
        }
    }

    private void maybeDrawCursor(Canvas canvas) {
        if (mDrawCursorEnabled) {
            if (mCursorDrawable != null) {
                mCursorDrawable.setBounds(
                        mSourceWidth / 2, 0,
                        mSourceWidth / 2 + mCursorDrawable.getIntrinsicWidth(), mSourceHeight);
                mCursorDrawable.draw(canvas);
            } else {
                Paint paint = new Paint();
                paint.setColor(Color.BLACK);  // The cursor on magnifier is by default in black.
                canvas.drawRect(
                        new Rect(mSourceWidth / 2 - 1, 0, mSourceWidth / 2 + 1, mSourceHeight),
                        paint);
            }
        }
    }

    private void performPixelCopy(final int startXInSurface, final int startYInSurface,
            final boolean updateWindowPosition) {
        if (mContentCopySurface.mSurface == null || !mContentCopySurface.mSurface.isValid()) {
@@ -827,8 +836,10 @@ public final class Magnifier {
                            final Rect dstRect = new Rect(mLeftCutWidth, 0,
                                    mSourceWidth - mRightCutWidth, bitmap.getHeight());
                            can.drawBitmap(bitmap, null, dstRect, null);
                            maybeDrawCursor(can);
                            mWindow.updateContent(newBitmap);
                        } else {
                            maybeDrawCursor(new Canvas(bitmap));
                            mWindow.updateContent(bitmap);
                        }
                    }