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

Commit 4021c3df authored by Shu Chen's avatar Shu Chen
Browse files

Implement the floating cursor via the fisheye magnifier.

 - Remove the lineLeft/lineRight source bounds.
 - Make the magnifier center X can be away from the cursor X.
 - Let Magnifier know how to render floating cursor.

Test: locally verified.
Bug: 149883037

Change-Id: Iae3c68fa9cda0a83704fa30fa7b9f4db0a8d3314
parent d551401a
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;
@@ -877,7 +884,7 @@ public class Editor {
        }

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

        if (!mInsertionControllerEnabled) {
@@ -5088,14 +5095,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);
@@ -5109,6 +5127,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) {
@@ -5165,7 +5184,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));
@@ -5195,7 +5215,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;
@@ -5217,6 +5250,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);
                        }
                    }