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
This commit is contained in:
@@ -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,26 +5095,38 @@ 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)) {
|
||||
leftBound += getHorizontal(mTextView.getLayout(), otherHandleOffset);
|
||||
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.getLayout().getLineLeft(lineNumber);
|
||||
}
|
||||
if (sameLineSelection && ((trigger == MagnifierHandleTrigger.SELECTION_START) ^ rtl)) {
|
||||
rightBound += getHorizontal(mTextView.getLayout(), otherHandleOffset);
|
||||
} else {
|
||||
rightBound += mTextView.getLayout().getLineRight(lineNumber);
|
||||
}
|
||||
leftBound *= mTextViewScaleX;
|
||||
rightBound *= mTextViewScaleX;
|
||||
final float contentWidth = Math.round(mMagnifierAnimator.mMagnifier.getWidth()
|
||||
/ mMagnifierAnimator.mMagnifier.getZoom());
|
||||
if (touchXInView < leftBound - contentWidth / 2
|
||||
|| touchXInView > rightBound + contentWidth / 2) {
|
||||
// The touch is too far from the current line / selection, so hide the magnifier.
|
||||
return false;
|
||||
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)) {
|
||||
rightBound += getHorizontal(mTextView.getLayout(), otherHandleOffset);
|
||||
} else {
|
||||
rightBound += mTextView.getLayout().getLineRight(lineNumber);
|
||||
}
|
||||
leftBound *= mTextViewScaleX;
|
||||
rightBound *= mTextViewScaleX;
|
||||
final float contentWidth = Math.round(mMagnifierAnimator.mMagnifier.getWidth()
|
||||
/ mMagnifierAnimator.mMagnifier.getZoom());
|
||||
if (touchXInView < leftBound - contentWidth / 2
|
||||
|| touchXInView > rightBound + contentWidth / 2) {
|
||||
// The touch is too far from the current line / selection, so hide the magnifier.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
final float scaledTouchXInView;
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user